martin f. krafft | 3cd2a33 | 2014-10-28 15:58:23 +0100 | [diff] [blame] | 1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
| 2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| 3 | |
| 4 | |
| 5 | <html xmlns="http://www.w3.org/1999/xhtml"> |
| 6 | <head> |
| 7 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
| 8 | |
| 9 | <title>Using reclass with Ansible — reclass 1.4.1 documentation</title> |
| 10 | |
| 11 | <link rel="stylesheet" href="_static/default.css" type="text/css" /> |
| 12 | <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> |
| 13 | |
| 14 | <script type="text/javascript"> |
| 15 | var DOCUMENTATION_OPTIONS = { |
| 16 | URL_ROOT: './', |
| 17 | VERSION: '1.4.1', |
| 18 | COLLAPSE_INDEX: false, |
| 19 | FILE_SUFFIX: '.html', |
| 20 | HAS_SOURCE: true |
| 21 | }; |
| 22 | </script> |
| 23 | <script type="text/javascript" src="_static/jquery.js"></script> |
| 24 | <script type="text/javascript" src="_static/underscore.js"></script> |
| 25 | <script type="text/javascript" src="_static/doctools.js"></script> |
| 26 | <link rel="top" title="reclass 1.4.1 documentation" href="index.html" /> |
| 27 | <link rel="next" title="Using reclass with Puppet" href="puppet.html" /> |
| 28 | <link rel="prev" title="Using reclass with Salt" href="salt.html" /> |
| 29 | </head> |
| 30 | <body> |
| 31 | <div class="related"> |
| 32 | <h3>Navigation</h3> |
| 33 | <ul> |
| 34 | <li class="right" style="margin-right: 10px"> |
| 35 | <a href="genindex.html" title="General Index" |
| 36 | accesskey="I">index</a></li> |
| 37 | <li class="right" > |
| 38 | <a href="puppet.html" title="Using reclass with Puppet" |
| 39 | accesskey="N">next</a> |</li> |
| 40 | <li class="right" > |
| 41 | <a href="salt.html" title="Using reclass with Salt" |
| 42 | accesskey="P">previous</a> |</li> |
| 43 | <li><a href="index.html">reclass</a> »</li> |
| 44 | </ul> |
| 45 | </div> |
| 46 | |
| 47 | <div class="document"> |
| 48 | <div class="documentwrapper"> |
| 49 | <div class="bodywrapper"> |
| 50 | <div class="body"> |
| 51 | |
| 52 | <div class="section" id="using-reclass-with-ansible"> |
| 53 | <h1>Using reclass with Ansible<a class="headerlink" href="#using-reclass-with-ansible" title="Permalink to this headline">¶</a></h1> |
| 54 | <div class="admonition warning"> |
| 55 | <p class="first admonition-title">Warning</p> |
| 56 | <p class="last">I was kicked out of the Ansible community, presumably for <a class="reference external" href="https://github.com/madduck/reclass/issues/6">asking the wrong |
| 57 | questions</a>, and therefore I have no interest in developing this adapter |
| 58 | anymore. If you use it and have changes, I will take your patch.</p> |
| 59 | </div> |
| 60 | <div class="section" id="quick-start-with-ansible"> |
| 61 | <h2>Quick start with Ansible<a class="headerlink" href="#quick-start-with-ansible" title="Permalink to this headline">¶</a></h2> |
| 62 | <p>The following steps should get you up and running quickly with <strong>reclass</strong> and |
| 63 | <a class="reference external" href="http://www.ansibleworks.com">Ansible</a>. Generally, we will be working in <tt class="docutils literal"><span class="pre">/etc/ansible</span></tt>. However, if you |
| 64 | are using a source-code checkout of Ansible, you might also want to work |
| 65 | inside the <tt class="docutils literal"><span class="pre">./hacking</span></tt> directory instead.</p> |
| 66 | <p>Or you can also just look into <tt class="docutils literal"><span class="pre">./examples/ansible</span></tt> of your <strong>reclass</strong> |
| 67 | checkout, where the following steps have already been prepared.</p> |
| 68 | <p>/…/reclass refers to the location of your <strong>reclass</strong> checkout.</p> |
| 69 | <ol class="arabic"> |
| 70 | <li><p class="first">Complete the installation steps described in the <a class="reference internal" href="install.html"><em>installation section</em></a>.</p> |
| 71 | </li> |
| 72 | <li><p class="first">Symlink <tt class="docutils literal"><span class="pre">/usr/share/reclass/reclass-ansible</span></tt> (or wherever your distro put |
| 73 | that file), or <tt class="docutils literal"><span class="pre">/…/reclass/reclass/adapters/ansible.py</span></tt> (if running from |
| 74 | source) to <tt class="docutils literal"><span class="pre">/etc/ansible/hosts</span></tt> (or <tt class="docutils literal"><span class="pre">./hacking/hosts</span></tt>).</p> |
| 75 | </li> |
| 76 | <li><p class="first">Copy the two directories <tt class="docutils literal"><span class="pre">nodes</span></tt> and <tt class="docutils literal"><span class="pre">classes</span></tt> from the example |
| 77 | subdirectory in the <strong>reclass</strong> checkout to <tt class="docutils literal"><span class="pre">/etc/ansible</span></tt></p> |
| 78 | <p>If you prefer to put those directories elsewhere, you can create |
| 79 | <tt class="docutils literal"><span class="pre">/etc/ansible/reclass-config.yml</span></tt> with contents such as:</p> |
| 80 | <div class="highlight-python"><div class="highlight"><pre>storage_type: yaml_fs |
| 81 | inventory_base_uri: /srv/reclass |
| 82 | </pre></div> |
| 83 | </div> |
| 84 | <p>Note that <tt class="docutils literal"><span class="pre">yaml_fs</span></tt> is currently the only supported <tt class="docutils literal"><span class="pre">storage_type</span></tt>, and |
| 85 | it’s the default if you don’t set it.</p> |
| 86 | </li> |
| 87 | <li><p class="first">Check out your inventory by invoking</p> |
| 88 | <div class="highlight-python"><div class="highlight"><pre>$ ./hosts --list |
| 89 | </pre></div> |
| 90 | </div> |
| 91 | <p>which should return 5 groups in JSON format, and each group has exactly |
| 92 | one member <tt class="docutils literal"><span class="pre">localhost</span></tt>.</p> |
| 93 | </li> |
| 94 | </ol> |
| 95 | <ol class="arabic" start="4"> |
| 96 | <li><p class="first">See the node information for <tt class="docutils literal"><span class="pre">localhost</span></tt>:</p> |
| 97 | <div class="highlight-python"><div class="highlight"><pre>$ ./hosts --host localhost |
| 98 | </pre></div> |
| 99 | </div> |
| 100 | <p>This should print a set of keys and values, including a greeting, |
| 101 | a colour, and a sub-class called <tt class="docutils literal"><span class="pre">__reclas__</span></tt>.</p> |
| 102 | </li> |
| 103 | <li><p class="first">Execute some ansible commands, e.g.:</p> |
| 104 | <div class="highlight-python"><div class="highlight"><pre>$ ansible -i hosts \* --list-hosts |
| 105 | $ ansible -i hosts \* -m ping |
| 106 | $ ansible -i hosts \* -m debug -a 'msg="${greeting}"' |
| 107 | $ ansible -i hosts \* -m setup |
| 108 | $ ansible-playbook -i hosts test.yml |
| 109 | </pre></div> |
| 110 | </div> |
| 111 | </li> |
| 112 | <li><p class="first">You can also invoke <strong>reclass</strong> directly, which gives a slightly different |
| 113 | view onto the same data, i.e. before it has been adapted for Ansible:</p> |
| 114 | <div class="highlight-python"><div class="highlight"><pre>$ /…/reclass/reclass.py --pretty-print --inventory |
| 115 | $ /…/reclass/reclass.py --pretty-print --nodeinfo localhost |
| 116 | </pre></div> |
| 117 | </div> |
| 118 | <p>Or, if <strong>reclass</strong> is properly installed, just use the <strong>reclass</strong> command.</p> |
| 119 | </li> |
| 120 | </ol> |
| 121 | </div> |
| 122 | <div class="section" id="integration-with-ansible"> |
| 123 | <h2>Integration with Ansible<a class="headerlink" href="#integration-with-ansible" title="Permalink to this headline">¶</a></h2> |
| 124 | <p>The integration between <strong>reclass</strong> and Ansible is performed through an adapter, |
| 125 | and needs not be of our concern too much.</p> |
| 126 | <p>However, Ansible has no concept of “nodes”, “applications”, “parameters”, and |
| 127 | “classes”. Therefore it is necessary to explain how those correspond to |
| 128 | Ansible. Crudely, the following mapping exists:</p> |
| 129 | <table border="1" class="docutils"> |
| 130 | <colgroup> |
| 131 | <col width="53%" /> |
| 132 | <col width="47%" /> |
| 133 | </colgroup> |
| 134 | <thead valign="bottom"> |
| 135 | <tr class="row-odd"><th class="head"><strong>reclass</strong> concept</th> |
| 136 | <th class="head">Ansible concept</th> |
| 137 | </tr> |
| 138 | </thead> |
| 139 | <tbody valign="top"> |
| 140 | <tr class="row-even"><td>nodes</td> |
| 141 | <td>hosts</td> |
| 142 | </tr> |
| 143 | <tr class="row-odd"><td>classes</td> |
| 144 | <td>groups</td> |
| 145 | </tr> |
| 146 | <tr class="row-even"><td>applications</td> |
| 147 | <td>playbooks</td> |
| 148 | </tr> |
| 149 | <tr class="row-odd"><td>parameters</td> |
| 150 | <td>host_vars</td> |
| 151 | </tr> |
| 152 | </tbody> |
| 153 | </table> |
| 154 | <p><strong>reclass</strong> does not provide any <tt class="docutils literal"><span class="pre">group_vars</span></tt> because of its node-centric |
| 155 | perspective. While class definitions include parameters, those are inherited |
| 156 | by the node definitions and hence become node_vars.</p> |
| 157 | <p><strong>reclass</strong> also does not provide playbooks, nor does it deal with any of the |
| 158 | related Ansible concepts, i.e. <tt class="docutils literal"><span class="pre">vars_files</span></tt>, vars, tasks, handlers, roles, etc..</p> |
| 159 | <blockquote> |
| 160 | <div>Let it be said at this point that you’ll probably want to stop using |
| 161 | <tt class="docutils literal"><span class="pre">host_vars</span></tt>, <tt class="docutils literal"><span class="pre">group_vars</span></tt> and <tt class="docutils literal"><span class="pre">vars_files</span></tt> altogether, and if only |
| 162 | because you should no longer need them, but also because the variable |
| 163 | precedence rules of Ansible are full of surprises, at least to me.</div></blockquote> |
| 164 | <p><strong>reclass</strong>‘ Ansible adapter massage the <strong>reclass</strong> output into Ansible-usable data, |
| 165 | namely:</p> |
| 166 | <ul> |
| 167 | <li><p class="first">Every class in the ancestry of a node becomes a group to Ansible. This is |
| 168 | mainly useful to be able to target nodes during interactive use of |
| 169 | Ansible, e.g.:</p> |
| 170 | <div class="highlight-python"><div class="highlight"><pre>$ ansible debiannode@wheezy -m command -a 'apt-get upgrade' |
| 171 | → upgrade all Debian nodes running wheezy |
| 172 | |
| 173 | $ ansible ssh.server -m command -a 'invoke-rc.d ssh restart' |
| 174 | → restart all SSH server processes |
| 175 | |
| 176 | $ ansible mailserver -m command -a 'tail -n1000 /var/log/mail.err' |
| 177 | → obtain the last 1,000 lines of all mailserver error log files |
| 178 | </pre></div> |
| 179 | </div> |
| 180 | <p>The attentive reader might stumble over the use of singular words, whereas |
| 181 | it might make more sense to address all <tt class="docutils literal"><span class="pre">mailserver*s*</span></tt> with this tool. |
| 182 | This is convention and up to you. I prefer to think of my node as |
| 183 | a (singular) mailserver when I add <tt class="docutils literal"><span class="pre">mailserver</span></tt> to its parent classes.</p> |
| 184 | </li> |
| 185 | <li><p class="first">Every entry in the list of a host’s applications might well correspond to |
| 186 | an Ansible playbook. Therefore, <strong>reclass</strong> creates a (Ansible-)group for |
| 187 | every application, and adds <tt class="docutils literal"><span class="pre">_hosts</span></tt> to the name. This postfix can be |
| 188 | configured with a CLI option (<tt class="docutils literal"><span class="pre">--applications-postfix</span></tt>) or in the |
| 189 | configuration file (<tt class="docutils literal"><span class="pre">applications_postfix</span></tt>).</p> |
| 190 | <p>For instance, the ssh.server class adds the ssh.server application to |
| 191 | a node’s application list. Now the admin might create an Ansible playbook |
| 192 | like so:</p> |
| 193 | <div class="highlight-python"><div class="highlight"><pre>- name: SSH server management |
| 194 | hosts: ssh.server_hosts ← SEE HERE |
| 195 | tasks: |
| 196 | - name: install SSH package |
| 197 | action: … |
| 198 | … |
| 199 | </pre></div> |
| 200 | </div> |
| 201 | <p>There’s a bit of redundancy in this, but unfortunately Ansible playbooks |
| 202 | hardcode the nodes to which a playbook applies.</p> |
| 203 | <p>It’s now trivial to apply this playbook across your infrastructure:</p> |
| 204 | <div class="highlight-python"><div class="highlight"><pre>$ ansible-playbook ssh.server.yml |
| 205 | </pre></div> |
| 206 | </div> |
| 207 | <p>My suggested way to use Ansible site-wide is then to create a <tt class="docutils literal"><span class="pre">site.yml</span></tt> |
| 208 | playbook that includes all the other playbooks (which shall hopefully be |
| 209 | based on Ansible roles), and then to invoke Ansible like this:</p> |
| 210 | <blockquote> |
| 211 | <div><p>ansible-playbook site.yml</p> |
| 212 | </div></blockquote> |
| 213 | <p>or, if you prefer only to reconfigure a subset of nodes, e.g. all |
| 214 | webservers:</p> |
| 215 | <div class="highlight-python"><div class="highlight"><pre>$ ansible-playbook site.yml --limit webserver |
| 216 | </pre></div> |
| 217 | </div> |
| 218 | <p>Again, if the singular word <tt class="docutils literal"><span class="pre">webserver</span></tt> puts you off, change the |
| 219 | convention as you wish.</p> |
| 220 | <p>And if anyone comes up with a way to directly connect groups in the |
| 221 | inventory with roles, thereby making it unnecessary to write playbook |
| 222 | files (containing redundant information), please tell me!</p> |
| 223 | </li> |
| 224 | <li><p class="first">Parameters corresponding to a node become <tt class="docutils literal"><span class="pre">host_vars</span></tt> for that host.</p> |
| 225 | </li> |
| 226 | </ul> |
| 227 | </div> |
| 228 | <div class="section" id="variable-interpolation"> |
| 229 | <h2>Variable interpolation<a class="headerlink" href="#variable-interpolation" title="Permalink to this headline">¶</a></h2> |
| 230 | <p>Ansible allows you to include <a class="reference external" href="http://jinja.pocoo.org">Jinja2</a>-style variables in parameter values:</p> |
| 231 | <div class="highlight-python"><div class="highlight"><pre>parameters: |
| 232 | motd: |
| 233 | greeting: Welcome to {{ ansible_fqdn }}! |
| 234 | closing: This system is part of {{ realm }} |
| 235 | dict_reference: {{ motd }} |
| 236 | </pre></div> |
| 237 | </div> |
| 238 | <p>However, in resolving this, Ansible casts everything to a string, so in this |
| 239 | example, <tt class="docutils literal"><span class="pre">dict_reference</span></tt> would be the string-representation of the |
| 240 | dictionary under the <tt class="docutils literal"><span class="pre">motd</span></tt> key <a class="footnote-reference" href="#string-casts" id="id1">[1]</a>. To get at facts (such as |
| 241 | <tt class="docutils literal"><span class="pre">ansible_fqdn</span></tt>), you still have to use this approach, but for pure parameter |
| 242 | references, I strongly suggest to use <strong>reclass</strong> interpolation instead, as it |
| 243 | supports deep references, does not clobber type information, and is more |
| 244 | efficient anyway:</p> |
| 245 | <div class="highlight-python"><div class="highlight"><pre>parameters: |
| 246 | motd: |
| 247 | greeting: Welcome to {{ ansible_fqdn }}! |
| 248 | closing: This system is part of ${realm} |
| 249 | dict_reference: ${motd} |
| 250 | </pre></div> |
| 251 | </div> |
| 252 | <p>Now you just need to specify realm somewhere. The reference can reside in |
| 253 | a parent class, while the variable is defined e.g. in the node definition.</p> |
| 254 | <p>And as expected, <tt class="docutils literal"><span class="pre">dict_reference</span></tt> now points to a dictionary, not |
| 255 | a string-representation thereof.</p> |
| 256 | <table class="docutils footnote" frame="void" id="string-casts" rules="none"> |
| 257 | <colgroup><col class="label" /><col /></colgroup> |
| 258 | <tbody valign="top"> |
| 259 | <tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>I pointed this out to Michael Dehaan, Ansible’s chief |
| 260 | developer, but he denied this behaviour. When I tried to provide further |
| 261 | insights, I found myself banned from the mailing list, apparently because |
| 262 | I dared to point out flaws. If you care, you may look at |
| 263 | <a class="reference external" href="https://github.com/madduck/reclass/issues/6">https://github.com/madduck/reclass/issues/6</a> for more information.</td></tr> |
| 264 | </tbody> |
| 265 | </table> |
| 266 | </div> |
| 267 | </div> |
| 268 | |
| 269 | |
| 270 | </div> |
| 271 | </div> |
| 272 | </div> |
| 273 | <div class="sphinxsidebar"> |
| 274 | <div class="sphinxsidebarwrapper"> |
| 275 | <h3><a href="index.html">Table Of Contents</a></h3> |
| 276 | <ul> |
| 277 | <li><a class="reference internal" href="#">Using reclass with Ansible</a><ul> |
| 278 | <li><a class="reference internal" href="#quick-start-with-ansible">Quick start with Ansible</a></li> |
| 279 | <li><a class="reference internal" href="#integration-with-ansible">Integration with Ansible</a></li> |
| 280 | <li><a class="reference internal" href="#variable-interpolation">Variable interpolation</a></li> |
| 281 | </ul> |
| 282 | </li> |
| 283 | </ul> |
| 284 | |
| 285 | <h4>Previous topic</h4> |
| 286 | <p class="topless"><a href="salt.html" |
| 287 | title="previous chapter">Using reclass with Salt</a></p> |
| 288 | <h4>Next topic</h4> |
| 289 | <p class="topless"><a href="puppet.html" |
| 290 | title="next chapter">Using reclass with Puppet</a></p> |
| 291 | <div id="searchbox" style="display: none"> |
| 292 | <h3>Quick search</h3> |
| 293 | <form class="search" action="search.html" method="get"> |
| 294 | <input type="text" name="q" /> |
| 295 | <input type="submit" value="Go" /> |
| 296 | <input type="hidden" name="check_keywords" value="yes" /> |
| 297 | <input type="hidden" name="area" value="default" /> |
| 298 | </form> |
| 299 | <p class="searchtip" style="font-size: 90%"> |
| 300 | Enter search terms or a module, class or function name. |
| 301 | </p> |
| 302 | </div> |
| 303 | <script type="text/javascript">$('#searchbox').show(0);</script> |
| 304 | </div> |
| 305 | </div> |
| 306 | <div class="clearer"></div> |
| 307 | </div> |
| 308 | <div class="related"> |
| 309 | <h3>Navigation</h3> |
| 310 | <ul> |
| 311 | <li class="right" style="margin-right: 10px"> |
| 312 | <a href="genindex.html" title="General Index" |
| 313 | >index</a></li> |
| 314 | <li class="right" > |
| 315 | <a href="puppet.html" title="Using reclass with Puppet" |
| 316 | >next</a> |</li> |
| 317 | <li class="right" > |
| 318 | <a href="salt.html" title="Using reclass with Salt" |
| 319 | >previous</a> |</li> |
| 320 | <li><a href="index.html">reclass</a> »</li> |
| 321 | </ul> |
| 322 | </div> |
| 323 | <div class="footer"> |
| 324 | © Copyright 2013, martin f. krafft. |
| 325 | Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.3. |
| 326 | </div> |
| 327 | </body> |
| 328 | </html> |