blob: e0f7934af0a1fee611248e05da74298016d09566 [file] [log] [blame]
martin f. krafft3cd2a332014-10-28 15:58:23 +01001<!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 &mdash; 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> &raquo;</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
57questions</a>, and therefore I have no interest in developing this adapter
58anymore. 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
64are using a source-code checkout of Ansible, you might also want to work
65inside 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>
67checkout, 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
73that file), or <tt class="docutils literal"><span class="pre">/…/reclass/reclass/adapters/ansible.py</span></tt> (if running from
74source) 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
77subdirectory 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
81inventory_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
85it&#8217;s the default if you don&#8217;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
92one 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,
101a 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 &#39;msg=&quot;${greeting}&quot;&#39;
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
113view 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,
125and needs not be of our concern too much.</p>
126<p>However, Ansible has no concept of &#8220;nodes&#8221;, &#8220;applications&#8221;, &#8220;parameters&#8221;, and
127&#8220;classes&#8221;. Therefore it is necessary to explain how those correspond to
128Ansible. 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
155perspective. While class definitions include parameters, those are inherited
156by 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
158related 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&#8217;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
162because you should no longer need them, but also because the variable
163precedence rules of Ansible are full of surprises, at least to me.</div></blockquote>
164<p><strong>reclass</strong>&#8216; Ansible adapter massage the <strong>reclass</strong> output into Ansible-usable data,
165namely:</p>
166<ul>
167<li><p class="first">Every class in the ancestry of a node becomes a group to Ansible. This is
168mainly useful to be able to target nodes during interactive use of
169Ansible, e.g.:</p>
170<div class="highlight-python"><div class="highlight"><pre>$ ansible debiannode@wheezy -m command -a &#39;apt-get upgrade&#39;
171 → upgrade all Debian nodes running wheezy
172
173$ ansible ssh.server -m command -a &#39;invoke-rc.d ssh restart&#39;
174 → restart all SSH server processes
175
176$ ansible mailserver -m command -a &#39;tail -n1000 /var/log/mail.err&#39;
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
181it might make more sense to address all <tt class="docutils literal"><span class="pre">mailserver*s*</span></tt> with this tool.
182This is convention and up to you. I prefer to think of my node as
183a (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&#8217;s applications might well correspond to
186an Ansible playbook. Therefore, <strong>reclass</strong> creates a (Ansible-)group for
187every application, and adds <tt class="docutils literal"><span class="pre">_hosts</span></tt> to the name. This postfix can be
188configured with a CLI option (<tt class="docutils literal"><span class="pre">--applications-postfix</span></tt>) or in the
189configuration 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
191a node&#8217;s application list. Now the admin might create an Ansible playbook
192like 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&#8217;s a bit of redundancy in this, but unfortunately Ansible playbooks
202hardcode the nodes to which a playbook applies.</p>
203<p>It&#8217;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>
208playbook that includes all the other playbooks (which shall hopefully be
209based 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
214webservers:</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
219convention as you wish.</p>
220<p>And if anyone comes up with a way to directly connect groups in the
221inventory with roles, thereby making it unnecessary to write playbook
222files (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
239example, <tt class="docutils literal"><span class="pre">dict_reference</span></tt> would be the string-representation of the
240dictionary 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
242references, I strongly suggest to use <strong>reclass</strong> interpolation instead, as it
243supports deep references, does not clobber type information, and is more
244efficient 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
253a 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
255a 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&#8217;s chief
260developer, but he denied this behaviour. When I tried to provide further
261insights, I found myself banned from the mailing list, apparently because
262I 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> &raquo;</li>
321 </ul>
322 </div>
323 <div class="footer">
324 &copy; 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>