<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Univers Libre - ansible</title>
    <subtitle>Yet another sysadmin&#39;s personal blog</subtitle>
    <link rel="self" type="application/atom+xml" href="https://univers-libre.net/tags/ansible/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://univers-libre.net"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2019-04-21T00:00:00+00:00</updated>
    <id>https://univers-libre.net/tags/ansible/atom.xml</id>
    <entry xml:lang="en">
        <title>Using molecule with GitLab CI</title>
        <published>2019-04-21T00:00:00+00:00</published>
        <updated>2019-04-21T00:00:00+00:00</updated>
        
        <author>
          <name>Romain</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://univers-libre.net/posts/ansible-molecule-gitlab-ci/"/>
        <id>https://univers-libre.net/posts/ansible-molecule-gitlab-ci/</id>
        
        <content type="html" xml:base="https://univers-libre.net/posts/ansible-molecule-gitlab-ci/">&lt;p&gt;This article follows &lt;a href=&quot;/posts/ansible-molecule.html&quot;&gt;this one&lt;/a&gt; where I talk
about verifying and testing your Ansible roles with molecule.&lt;/p&gt;
&lt;p&gt;As I wrote in this first article, I also configured GitLab CI to automatically
run molecule tests after each push to the repository. A good documentation to start with is the official &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://docs.gitlab.com/ee/ci/&quot;&gt;GitLab CI/CD documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is our &lt;em&gt;.gitlab-ci.yml&lt;/em&gt; (&lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/blob/master/.gitlab-ci.yml&quot;&gt;latest version&lt;/a&gt;) used on our &lt;em&gt;ansible&lt;/em&gt; repository hosting all our roles:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;image: quay.io/ansible/molecule:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - docker:dind&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stages:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - tests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;before_script:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - docker -v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - python -V&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - ansible --version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - molecule --version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;molecule-role-common:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  stage: tests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  tags:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  variables:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DOCKER_HOST: &amp;quot;tcp://docker:2375&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PY_COLORS: 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - cd roles/common/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - molecule test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  only:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    changes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - roles/common/**/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;molecule-role-monitoring-tools:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  stage: tests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  tags:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  variables:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DOCKER_HOST: &amp;quot;tcp://docker:2375&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PY_COLORS: 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  script:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - cd roles/monitoring-tools/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - molecule test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  only:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    changes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - roles/monitoring-tools/**/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[…]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our repository is hosted on gitlab.com and even if we can connect our own
GitLab Runners to gitlab.com instance, we decided to use the provided
gitlab.com’s shared runners to get started quickly.&lt;/p&gt;
&lt;p&gt;Those use Docker to run the jobs. So we instantiate the official molecule image
(from Red Hat’s registry):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;image: quay.io/ansible/molecule:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And since molecule also needs to spawn Docker containers, we need to start
another container: &lt;em&gt;docker:dind&lt;/em&gt; (Docker in Docker). This is done with:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - docker:dind&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And by exporting the &lt;code&gt;DOCKER_HOST&lt;/code&gt; variable to the jobs, so that molecule will
be able to connect to the Docker daemon to manage its containers:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;variables:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  DOCKER_HOST: &amp;quot;tcp://docker:2375&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we define one stage, called &lt;em&gt;tests&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stages:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - tests&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each jobs related to this stage will have the &lt;code&gt;stage: tests&lt;/code&gt; key in their
definition.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;before_script&lt;/code&gt; block is here for debugging purpose (if the molecule tests
succeed locally bt fail on the runners, it may be because the tests are run
with a different version of molecule).&lt;/p&gt;
&lt;p&gt;Last, we define as many jobs as we have roles to test with molecule. Here,
&lt;code&gt;tags&lt;/code&gt; is important since it is used by GitLab CI to select the runner the job
will be executed on. We need a runner with Docker, thus:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tags:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - docker&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;script&lt;/code&gt; keyword we specify each command the runner should run. Pretty
self-explanatory:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;script:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - cd roles/monitoring-tools/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - molecule test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And &lt;code&gt;only&lt;/code&gt; adds kind of a condition to the job. We don’t want to run all jobs
if, for instance, someone updates the README file. The job should run only if a
commit introduces a change to a file in the role itself. So we restrict the
execution to a change under the role’s hierarchy only with:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;only:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  changes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - roles/monitoring-tools/**/*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For instance, &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/pipelines/54380774/builds&quot;&gt;this
pipeline&lt;/a&gt;,
triggered by the commit afe5929c, has spawned only &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/-/jobs/187303076&quot;&gt;one
job&lt;/a&gt;, the
&lt;em&gt;molecule-role-firewall&lt;/em&gt; test, since only the firewall role was modified.
Whereas &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/commit/39abe0e9785e72aa8964a193e3af066106552f6a&quot;&gt;this
commit&lt;/a&gt;
(which impacted multiple roles) triggered &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/pipelines/54499990/builds&quot;&gt;7
jobs&lt;/a&gt; (and yes, one
has failed).&lt;/p&gt;
&lt;p&gt;If a job fails, the commiter will receive a notification by e-mail with the
commit and job ID. We can check the &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/-/jobs/187667011&quot;&gt;job’s
output&lt;/a&gt; on GitLab, to see
why it has failed.&lt;/p&gt;
&lt;p&gt;As an ending note, to test your &lt;em&gt;.gitlab-ci.yml&lt;/em&gt; without pushing, you can
install the &lt;em&gt;gitlab-runner&lt;/em&gt; package and run it on your repository (you still
need to commit your changes since `gitlab-runner will checkout the repository):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ gitlab-runner exec docker &amp;lt;your job name&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Automatically generate a diagram of your infrastructure from Ansible inventory</title>
        <published>2019-04-05T00:00:00+00:00</published>
        <updated>2019-04-05T00:00:00+00:00</updated>
        
        <author>
          <name>Romain</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://univers-libre.net/posts/ansible-infrastructure-diagram/"/>
        <id>https://univers-libre.net/posts/ansible-infrastructure-diagram/</id>
        
        <content type="html" xml:base="https://univers-libre.net/posts/ansible-infrastructure-diagram/">&lt;p&gt;Another post about Ansible. This time I will talk about generating a
representation of your infrastructure, for documentation purpose, using your
Ansible inventory and gathered facts.&lt;/p&gt;
&lt;p&gt;I had to update the infrastructure diagram of the Services FACiLes project, it
was deprecated and, inevitably, will still be in a few months because we keep
adding new containers and services. That’s a common issue in tech documentation.&lt;/p&gt;
&lt;p&gt;Moreover, manually editing a graph isn’t a thing I usually like to do,
especially when elements, relations and additional text can more easily be declared
in a text file using a definition language. I found for instance &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://github.com/otahi/network_drawer&quot;&gt;this
tool&lt;/a&gt; (not tested) which allows you to
describe what you want to graph using a YAML file and then use graphviz to draw
the resulting diagram. But, wait, I already have this kind of structured data,
it’s in my Ansible inventory file.&lt;/p&gt;
&lt;p&gt;I then thought about writing an equivalent tool to draw a diagram representing
Ansible hosts and groups declared in the inventory and their facts and
variables. Of course, someone else already had this idea, and this is called
&lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://github.com/willthames/ansible-inventory-grapher&quot;&gt;ansible-inventory-grapher&lt;/a&gt;.
This python tool produces graphviz code that you can directly pipe to graphviz
to generate a png or svg file.&lt;/p&gt;
&lt;p&gt;As an example, here is how the graph of our infrastructure looks like:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/posts/ansible-infrastructure-diagram/ansible-inventory-graph.png&quot;&gt;&lt;img src=&quot;/posts/ansible-infrastructure-diagram/ansible-inventory-graph.png&quot; alt=&quot;infrastructure graph generated from Ansible inventory&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ansible-inventory-grapher doesn’t show value of variables but you can use [this
fork]((https://github.com/eking-go/ansible-inventory-grapher/tree/variables_with_value)
&lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://github.com/willthames/ansible-inventory-grapher/pull/39&quot;&gt;merge request
pending&lt;/a&gt;) to
have them on your graph.
You should also enable fact caching in your &lt;code&gt;ansible.cfg&lt;/code&gt; and gather your server’s facts before running ansible-inventory-grapher. Else you will only have variables declared in &lt;em&gt;host_vars/&lt;/em&gt; and &lt;em&gt;group_vars/&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The default jinja2 template used to generate the code suitable for graphviz prints all variables and facts, but I was only interested by some of them (those passed to the &lt;code&gt;--visible-vars&lt;/code&gt; actually) so I slighty modified the template as follow:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- doc/ansible-inventory-graph.default.j2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ doc/ansible-inventory-graph.j2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -8,7 +8,7 @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;font face=&amp;quot;Times New Roman, Bold&amp;quot; point-size=&amp;quot;16&amp;quot;&amp;gt;{{ node.name}}&amp;lt;/font&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-{% if node.vars and showvars %}&amp;lt;hr/&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;font face=&amp;quot;Times New Roman, Bold&amp;quot; point-size=&amp;quot;14&amp;quot;&amp;gt;{% for var in node.vars|sort %}{{var}}{% if var in visible_vars %} = {{node.vars[var]}}{% endif %}&amp;lt;br/&amp;gt;{%endfor %}&amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;{% endif %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+{% if node.vars and showvars %}&amp;lt;hr/&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;font face=&amp;quot;Times New Roman, Bold&amp;quot; point-size=&amp;quot;14&amp;quot;&amp;gt;{% for var in node.vars|sort %}{% if var in visible_vars %}{{var}} = {% if node.vars[var] is iterable and node.vars[var] is not string %}{{ node.vars[var]|map(attribute=&amp;#39;name&amp;#39;)|join(&amp;#39;, &amp;#39;) }}{% else %}{{node.vars[var]}}{% endif %}&amp;lt;br/&amp;gt;{% endif %}{% else %}&amp;lt;br /&amp;gt;{%endfor %}&amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;{% endif %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &amp;lt;/table&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &amp;gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; {% else %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -17,7 +17,7 @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;b&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;font face=&amp;quot;Times New Roman, Bold&amp;quot; point-size=&amp;quot;16&amp;quot;&amp;gt;{{ node.name}}&amp;lt;/font&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-{% if node.vars and showvars %}&amp;lt;hr/&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;font face=&amp;quot;Times New Roman, Bold&amp;quot; point-size=&amp;quot;14&amp;quot;&amp;gt;{% for var in node.vars|sort %}{{var}}{% if var in visible_vars %} = {{node.vars[var]}}{% endif %}&amp;lt;br/&amp;gt;{%endfor %}&amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;{% endif %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+{% if node.vars and showvars %}&amp;lt;hr/&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;font face=&amp;quot;Times New Roman, Bold&amp;quot; point-size=&amp;quot;14&amp;quot;&amp;gt;{% for var in node.vars|sort %}{% if var in visible_vars %}{{var}} = {% if node.vars[var] is iterable %}{{ node.vars[var]|map(attribute=&amp;#39;name&amp;#39;)|join(&amp;#39;, &amp;#39;) }}{% else %}{{node.vars[var]}}{% endif %}&amp;lt;br/&amp;gt;{% endif %}{% else %}&amp;lt;br /&amp;gt;{% endfor %}&amp;lt;/font&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;{% endif %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &amp;lt;/table&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &amp;gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; {% endif %}{% endfor %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -26,3 +26,5 @@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   {{ edge.source|labelescape }} -&amp;gt; {{ edge.target|labelescape }};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; {% endfor %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I wrote a simple Makefile to easily update the graph when inventory is
updated:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Clear out default implicit rules and variables.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MAKEFLAGS += --no-builtin-rules --no-builtin-variables&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.PHONY: inventory-graph&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;inventory-graph: doc/ansible-inventory-graph.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;doc/ansible-inventory-graph.png: inventory/hosts $(wildcard inventory/group_vars/*.yml) $(wildcard inventory/host_vars/*.yml)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ansible -i inventory/ -m setup all &amp;gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	~/src/ansible-inventory-grapher/bin/ansible-inventory-grapher -i inventory/ -t doc/ansible-inventory-graph.j2 -a &amp;quot;rankdir=LR;&amp;quot; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars knot_zones \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars backup_server \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars munin_master \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars icinga2_master \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars icinga2_parent \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars backup_hosts \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars icinga2_monitored_sites \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars db_type \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars hosted_by \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars libvirt_domains \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars lxc_containers \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_architecture \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_default_ipv4.address \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_default_ipv6.address \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_distribution \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_distribution_version \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_memtotal_mb \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_processor_vcpus \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_virtualization_role \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	--visible-vars ansible_virtualization_type \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	all | dot -T png &amp;gt;$@&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That way, when we add a new machine or make any change in our infra, all we
need to do is &lt;code&gt;make inventory-graph&lt;/code&gt; and commit the resulting graph. The image
file is linked in our documentation in our private wiki, thus we are ensured
that it is always up to date!&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ansible QA and testing with molecule</title>
        <published>2019-03-31T00:00:00+00:00</published>
        <updated>2019-03-31T00:00:00+00:00</updated>
        
        <author>
          <name>Romain</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://univers-libre.net/posts/ansible-molecule/"/>
        <id>https://univers-libre.net/posts/ansible-molecule/</id>
        
        <content type="html" xml:base="https://univers-libre.net/posts/ansible-molecule/">&lt;p&gt;Winter is already over in the Laurentians, and for a few weeks now ski
conditions are so horribles that it’s not fun anymore and I’m sick of applying
and cleaning klister on my skis. We will soon have rain and mud and flooding
everywhere. April is definitely the worst month in Quebec despite sunny and
longer days. But the good thing is that I suddenly have a huge amount of time
left for other things. Like system administration and coding.&lt;/p&gt;
&lt;p&gt;Thus I picked up a task from my todo list that I always wanted to do: trying
molecule over our Ansible roles and playbook at FACiL. The infrastructure
running behind the &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://facil.services/&quot;&gt;Services FACiLes&lt;/a&gt; project is setup
and maintained 100% with Ansible. All our roles and playbooks are &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://gitlab.com/facil/ansible/&quot;&gt;public and
hosted on Gitlab&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://github.com/ansible/molecule&quot;&gt;molecule&lt;/a&gt; is a Python tool
developed by the same team as Ansible and aims running different kind of tests
over your ansible roles: linting, role execution on multiple targets and
scenarios, ensure idempotence over multiple executions and running unit
tests on the target.&lt;/p&gt;
&lt;p&gt;I am not going to write a full tutorial on molecule, a lot of them already
exist on Internet, though not always up to date since molecule is still a
young project and in heavy development. The &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://molecule.readthedocs.io/en/latest/&quot;&gt;official
documentation&lt;/a&gt; is a bit rough to
get started and to understand the scope of molecule. A &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://www.jeffgeerling.com/blog/2018/testing-your-ansible-roles-molecule&quot;&gt;good
tutorial&lt;/a&gt;
I found for being the most up to date and accurate.&lt;/p&gt;
&lt;p&gt;Instead, in this post I’m going to explain how I use it to test our roles, with
some tips I didn’t find in the official documentation. I also played with
Gitlab CI so molecule tests are run on each git push, but it will be for
another post.&lt;/p&gt;
&lt;h2 id=&quot;molecule-s-files&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#molecule-s-files&quot; aria-label=&quot;Anchor link for: molecule-s-files&quot;&gt;molecule’s files&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We start by creating a molecule directory in our role:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule init scenario --verifier-name goss --driver-name docker --role-name &amp;lt;role&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will create a directory named &lt;em&gt;molecule/&lt;/em&gt; in your role’s directory. You can
have multiple scenarios for your role, stored under &lt;em&gt;molecule/&lt;/em&gt; directory. By
default, &lt;code&gt;molecule init&lt;/code&gt; will create the scenario &lt;em&gt;default&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ tree molecule/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;molecule/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── Dockerfile.j2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── INSTALL.rst&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── molecule.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── playbook.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── tests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └── test_default.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── verify.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each file above are just here to help you to get started and can be edited as you
want. Options we passed to the &lt;code&gt;molecule init&lt;/code&gt; command are just here to alter
these files. I usually prefer copying the &lt;em&gt;molecule/&lt;/em&gt; directory from an
existing role (which is totally acceptable) since I have done some extra
customization on it.&lt;/p&gt;
&lt;h3 id=&quot;molecule-yml&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#molecule-yml&quot; aria-label=&quot;Anchor link for: molecule-yml&quot;&gt;&lt;em&gt;molecule.yml&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;molecule.yml&lt;/em&gt; is the only molecule configuration file. Here is the
&lt;em&gt;molecule.yml&lt;/em&gt; we use in our roles :&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dependency:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name: galaxy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;driver:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name: docker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lint:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name: yamllint&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;platforms:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - name: molecule-monitoring-tools&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    image: geerlingguy/docker-debian9-ansible:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    command: ${MOLECULE_DOCKER_COMMAND:-&amp;quot;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    volumes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - /sys/fs/cgroup:/sys/fs/cgroup:ro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    privileged: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pre_build_image: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;provisioner:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name: ansible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  lint:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name: ansible-lint&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  options:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    skip-tags: molecule-converge-notest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  log: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;scenario:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name: default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;molecule is designed to be very extensible. For instance, it uses the
galaxy dependency resolver (dependencies are defined in the &lt;em&gt;meta/main.yml&lt;/em&gt;
file of your role) and ansible as a provisioner (this is the only one
supported for now but we can imagine molecule will be able to use other
configuration management tools).&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;yamllint&lt;/code&gt; as the linter for all YAML file of the role (including
molecule’s own files!) and &lt;code&gt;ansible-lint&lt;/code&gt; for ansible files.&lt;/p&gt;
&lt;p&gt;For some reasons, we don’t want to run some Ansible tasks when testing the
role. molecule let us pass any &lt;code&gt;ansible-playbook&lt;/code&gt; option with the dict
&lt;code&gt;provisioner:options&lt;/code&gt;. Here we excluded tasks which have the
&lt;em&gt;molecule-converge-notest&lt;/em&gt; tag on them.&lt;/p&gt;
&lt;p&gt;And finally we tell molecule to run the role in a Docker container. molecule
supports a large range of drivers, including LXC containers, Vagrant VMs and
common public cloud providers. Even if we use LXC containers on production, I
choose to use the Docker driver with molecule because, first it’s more easy to
setup on a personal machine, and second because this is the only supported
option if we want to run molecule tests on Gitlab’s shared runners (using
Docker in Docker), I will talk about it later in a second post.&lt;/p&gt;
&lt;p&gt;Most of our roles don’t work inside a minimal Docker container, so we use
geerlingguy/docker-debian9-ansible Docker image. The image provides a more
complete Debian system (with systemd and common tools). It is maintained by
Jeff Geerling, who wrote a lot of Ansible roles and uses it to test his own roles.&lt;/p&gt;
&lt;p&gt;By default, molecule spawns a container named &lt;em&gt;instance&lt;/em&gt;. It’s a bad idea since
I ended up with conflicts when I tried to launch tests on multiple roles at the
same time, each of them was executed in the same container. Thus I edited
&lt;em&gt;platforms:name&lt;/em&gt; key so that it bears the role’s name.&lt;/p&gt;
&lt;h3 id=&quot;dockerfile-j2&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#dockerfile-j2&quot; aria-label=&quot;Anchor link for: dockerfile-j2&quot;&gt;&lt;em&gt;Dockerfile.j2&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This file is only here if you want to build your Docker container on each test.
You can use any Docker image (defined in &lt;em&gt;platforms:image&lt;/em&gt;) and this Dockerfile
will install requirements such as python, sudo, bash and ca-certificates
package to run Ansible.&lt;/p&gt;
&lt;p&gt;Since the image we use already contains those dependencies, we instruct
molecule not to build another Docker image (&lt;em&gt;platforms:pre_build_image&lt;/em&gt;).
this way, we also speed up tests.&lt;/p&gt;
&lt;h3 id=&quot;install-rst&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#install-rst&quot; aria-label=&quot;Anchor link for: install-rst&quot;&gt;&lt;em&gt;INSTALL.rst&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;INSTALL.rst&lt;/em&gt; is an informal file containing instructions to others
contributors and requirements to run molecule tests. For instance, we need to
have the Docker engine and docker-py installed on our machine.&lt;/p&gt;
&lt;h3 id=&quot;playbook-yml&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#playbook-yml&quot; aria-label=&quot;Anchor link for: playbook-yml&quot;&gt;&lt;em&gt;playbook.yml&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After &lt;em&gt;molecule.yml&lt;/em&gt;, this is the second most important file. Once molecule has spawned the container, it will run this playbook.&lt;/p&gt;
&lt;p&gt;Here is its content:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- name: Converge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hosts: all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  roles:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - role: &amp;lt;role&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty simple, it applies &lt;code&gt;&amp;lt;role&amp;gt;&lt;/code&gt; onto the spun up container. But if your role requires some variables to be set, or dependencies that aren’t declared in your role’s &lt;em&gt;meta/main.yml&lt;/em&gt; file, you can add them here. For instance:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- name: Converge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  hosts: all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  roles:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - role: &amp;lt;other role&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    - role: &amp;lt;role&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  vars:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    foo: &amp;quot;bar&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;verify-yml-and-tests-test-default-yml&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#verify-yml-and-tests-test-default-yml&quot; aria-label=&quot;Anchor link for: verify-yml-and-tests-test-default-yml&quot;&gt;&lt;em&gt;verify.yml&lt;/em&gt; and &lt;em&gt;tests/test_default.yml&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Finally, those two files are for unit tests. &lt;em&gt;verify.yml&lt;/em&gt; installs Goss (the verifier tool) in the container and run tests it finds in the &lt;em&gt;tests/&lt;/em&gt; directory. Although it’s a very interesting subject, I didn’t dig too much into unit tests for now.&lt;/p&gt;
&lt;h2 id=&quot;running-molecule&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#running-molecule&quot; aria-label=&quot;Anchor link for: running-molecule&quot;&gt;Running molecule&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, to enable bash completion:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ eval &amp;quot;$(_MOLECULE_COMPLETE=source molecule)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running &lt;code&gt;molecule&lt;/code&gt; without argument will show you the list of available sub-commands. I’m not going to explain all of them, and I don’t even sure what all these sub-commands do, I still learning about molecule.&lt;/p&gt;
&lt;p&gt;Run linting tools on your role:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule lint&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Test your role into a freshly created container (by executing &lt;em&gt;playbook.yml&lt;/em&gt; on it):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule converge&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;molecule converge&lt;/code&gt; will automatically lint your code prior to run it.&lt;/p&gt;
&lt;p&gt;At this time you can either login to the container to manually check what has been done:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule login&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or replay &lt;code&gt;molecule converge&lt;/code&gt; if you obtained errors and have fixed them in your role.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;molecule converge&lt;/code&gt; allows us to pass almost any &lt;code&gt;ansible-playbook&lt;/code&gt; option. For instance, you may want to debug tasks with a specific tag:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule converge -- -vvv --tags &amp;lt;tag&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To destroy the running container so you can start with a new one:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule destroy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you just want to start a container but don’t execute anything in it (for instance if you want to known the state of a file in a brand new install):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule prepare&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run idempotence check (molecule will simply run the &lt;em&gt;playbook.yml&lt;/em&gt; a second time and check that no tasks report a &lt;em&gt;changed&lt;/em&gt; state):&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule idempotence&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All these previous commands are useful while you are developing a role. Once you have done or did only minors edits (you are pretty confident that you didn’t break anything), it’s handy to run all the test suite at once:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ molecule test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will lint your code, start a new container, apply &lt;em&gt;playbook.yml&lt;/em&gt;, verify idempotence, run unit tests and finally destroy the container.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>[Ansible] sudo password from your password manager or agent</title>
        <published>2019-03-29T00:00:00+00:00</published>
        <updated>2019-03-29T00:00:00+00:00</updated>
        
        <author>
          <name>Romain</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://univers-libre.net/posts/ansible-sudo-password-agent/"/>
        <id>https://univers-libre.net/posts/ansible-sudo-password-agent/</id>
        
        <content type="html" xml:base="https://univers-libre.net/posts/ansible-sudo-password-agent/">&lt;p&gt;Make Ansible retrieve the sudo password from my password manager. For a long
time, I was wondering how to solve this issue. Ansible is my main tool to
manage my own servers. All the infrastructure of the &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://facil.services/&quot;&gt;Services
FACiLes&lt;/a&gt; project I contribute to (a future
&lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://chatons.org/&quot;&gt;CHATONS&lt;/a&gt; is built with Ansible automation in mind,
and even at my previous work, Ansible is used on a daily basis.&lt;/p&gt;
&lt;p&gt;A thing that really annoyed me was that each time I run a playbook, I have to
give Ansible my sudo password. Besides that, Ansible prompts for the password at an early
stage of execution, even before trying to include all files or running a syntax
check on them. Thus it isn’t uncommon that Ansible fails immediately after
because of a mistake I made in a playbook, and I have fix it, rerun the
command, reenter my password… and so on. Which is very frustrated.&lt;/p&gt;
&lt;p&gt;I know some workarounds exist to avoid dealing with the interactive sudo
password prompt: allowing Ansible to be executed without password on the servers (almost
equivalent to allowing any command to be executed without password…, which is
not an acceptable answer), storing your password into &lt;code&gt;ansible_sudo_pass&lt;/code&gt;
variable in a cleartext file somewhere (yes you can encrypt it with
&lt;code&gt;ansible-vault&lt;/code&gt; but then you have to give the vault password each time you run
your playbook), trying to mess with &lt;code&gt;except&lt;/code&gt;…&lt;/p&gt;
&lt;p&gt;The simple and elegant way of doing it for me would be that Ansible gets the password from an agent,
like &lt;code&gt;gpg-agent&lt;/code&gt;, or execute an arbitrary command to get it.
After a lot of research and experimentation, I found a pretty nice and clever
solution on &lt;a class=&quot;external-link&quot; rel=&quot;external&quot; href=&quot;https://stackoverflow.com/a/53889884&quot;&gt;Stackoverflow&lt;/a&gt; (far at the
bottom, it should be upvoted more than that IMHO). The idea is to combine &lt;code&gt;--extra-var&lt;/code&gt;
ansible option (to which a file descriptor can be passed, while prefixing it with
&lt;code&gt;@&lt;/code&gt;) and &lt;code&gt;&amp;lt;()&lt;/code&gt; bash operator to convert a command’s stdout to a file virtual
file descriptor. We end up with the following command:&lt;/p&gt;
&lt;pre class=&quot;giallo z-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ ansible-playbook -e@&amp;lt;(echo &amp;quot;ansible_sudo_pass: $(pass Sysadmin/xxxx)&amp;quot;) playbook.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way my sudo password is retrieved from my &lt;code&gt;pass&lt;/code&gt;’s password manager (which uses
gpg-agent) and I’m not bothered anymore with Ansible’s interactive prompt \o/.&lt;/p&gt;
&lt;p&gt;The only drawback is that I didn’t find a way to set this into the
&lt;em&gt;ansible.cfg&lt;/em&gt; or somewhere else, except writing a bash alias or a small
wrapper.&lt;/p&gt;
</content>
        
    </entry>
</feed>
