blob: 6a9dde55c8b38daaedfcbb0da83a680e8531af78 [file] [log] [blame]
martin f. krafft8acd49d2013-08-26 21:22:25 +02001==========================
2Using reclass with Ansible
3==========================
4
5Not-so-nice disclaimer
6----------------------
7I was kicked out of the Ansible community, presumably for `asking the wrong
8questions`_, and therefore I have no interest in developing this adapter
9anymore. If you use it and have changes, I will take your patch.
10
11.. _asking the wrong questions: https://github.com/madduck/reclass/issues/6
12
13Quick start with Ansible
14------------------------
15The following steps should get you up and running quickly with |reclass| and
16`Ansible`_. Generally, we will be working in ``/etc/ansible``. However, if you
17are using a source-code checkout of Ansible, you might also want to work
18inside the ``./hacking`` directory instead.
19
20Or you can also just look into ``./examples/ansible`` of your |reclass|
21checkout, where the following steps have already been prepared.
22
23/…/reclass refers to the location of your |reclass| checkout.
24
25#. Complete the installation steps described in the :doc:`installation section
26 <install>`.
27
28#. Symlink ``/usr/share/reclass/reclass-ansible`` (or wherever your distro put
29 that file), or ``/…/reclass/reclass/adapters/ansible.py`` (if running from
30 source) to ``/etc/ansible/hosts`` (or ``./hacking/hosts``).
31
32#. Copy the two directories ``nodes`` and ``classes`` from the example
33 subdirectory in the |reclass| checkout to ``/etc/ansible``
34
35 If you prefer to put those directories elsewhere, you can create
36 ``/etc/ansible/reclass-config.yml`` with contents such as::
37
38 storage_type: yaml_fs
39 inventory_base_uri: /srv/reclass
40
41 Note that ``yaml_fs`` is currently the only supported ``storage_type``, and
42 it's the default if you don't set it.
43
44#. Check out your inventory by invoking
45
46 ::
47
48 $ ./hosts --list
49
50 which should return 5 groups in JSON format, and each group has exactly
51 one member ``localhost``.
52
534. See the node information for ``localhost``::
54
55 $ ./hosts --host localhost
56
57 This should print a set of keys and values, including a greeting,
58 a colour, and a sub-class called ``__reclas__``.
59
605. Execute some ansible commands, e.g.::
61
62 $ ansible -i hosts \* --list-hosts
63 $ ansible -i hosts \* -m ping
64 $ ansible -i hosts \* -m debug -a 'msg="${greeting}"'
65 $ ansible -i hosts \* -m setup
66 $ ansible-playbook -i hosts test.yml
67
686. You can also invoke |reclass| directly, which gives a slightly different
69 view onto the same data, i.e. before it has been adapted for Ansible::
70
71 $ /…/reclass/reclass.py --pretty-print --inventory
72 $ /…/reclass/reclass.py --pretty-print --nodeinfo localhost
73
74 Or, if |reclass| is properly installed, just use the |reclass| command.
75
76Integration with Ansible
77------------------------
78The integration between |reclass| and Ansible is performed through an adapter,
79and needs not be of our concern too much.
80
81However, Ansible has no concept of "nodes", "applications", "parameters", and
82"classes". Therefore it is necessary to explain how those correspond to
83Ansible. Crudely, the following mapping exists:
84
85================= ===============
86|reclass| concept Ansible concept
87================= ===============
88nodes hosts
89classes groups
90applications playbooks
91parameters host_vars
92================= ===============
93
94|reclass| does not provide any ``group_vars`` because of its node-centric
95perspective. While class definitions include parameters, those are inherited
96by the node definitions and hence become node_vars.
97
98|reclass| also does not provide playbooks, nor does it deal with any of the
99related Ansible concepts, i.e. ``vars_files``, vars, tasks, handlers, roles, etc..
100
101 Let it be said at this point that you'll probably want to stop using
102 ``host_vars``, ``group_vars`` and ``vars_files`` altogether, and if only
103 because you should no longer need them, but also because the variable
104 precedence rules of Ansible are full of surprises, at least to me.
105
106|reclass|' Ansible adapter massage the |reclass| output into Ansible-usable data,
107namely:
108
109- Every class in the ancestry of a node becomes a group to Ansible. This is
110 mainly useful to be able to target nodes during interactive use of
111 Ansible, e.g.::
112
113 $ ansible debiannode@wheezy -m command -a 'apt-get upgrade'
114 → upgrade all Debian nodes running wheezy
115
116 $ ansible ssh.server -m command -a 'invoke-rc.d ssh restart'
117 → restart all SSH server processes
118
119 $ ansible mailserver -m command -a 'tail -n1000 /var/log/mail.err'
120 → obtain the last 1,000 lines of all mailserver error log files
121
122 The attentive reader might stumble over the use of singular words, whereas
123 it might make more sense to address all ``mailserver*s*`` with this tool.
124 This is convention and up to you. I prefer to think of my node as
125 a (singular) mailserver when I add ``mailserver`` to its parent classes.
126
127- Every entry in the list of a host's applications might well correspond to
128 an Ansible playbook. Therefore, |reclass| creates a (Ansible-)group for
129 every application, and adds ``_hosts`` to the name. This postfix can be
130 configured with a CLI option (``--applications-postfix``) or in the
131 configuration file (``applications_postfix``).
132
133 For instance, the ssh.server class adds the ssh.server application to
134 a node's application list. Now the admin might create an Ansible playbook
135 like so::
136
137 - name: SSH server management
138 hosts: ssh.server_hosts ← SEE HERE
139 tasks:
140 - name: install SSH package
141 action: …
142
143
144 There's a bit of redundancy in this, but unfortunately Ansible playbooks
145 hardcode the nodes to which a playbook applies.
146
147 It's now trivial to apply this playbook across your infrastructure::
148
149 $ ansible-playbook ssh.server.yml
150
151 My suggested way to use Ansible site-wide is then to create a ``site.yml``
152 playbook that includes all the other playbooks (which shall hopefully be
153 based on Ansible roles), and then to invoke Ansible like this:
154
155 ansible-playbook site.yml
156
157 or, if you prefer only to reconfigure a subset of nodes, e.g. all
158 webservers::
159
160 $ ansible-playbook site.yml --limit webserver
161
162 Again, if the singular word ``webserver`` puts you off, change the
163 convention as you wish.
164
165 And if anyone comes up with a way to directly connect groups in the
166 inventory with roles, thereby making it unnecessary to write playbook
167 files (containing redundant information), please tell me!
168
169- Parameters corresponding to a node become ``host_vars`` for that host.
170
171Variable interpolation
172----------------------
173Ansible allows you to include `Jinja2`_-style variables in parameter values::
174
175 parameters:
176 motd:
177 greeting: Welcome to {{ ansible_fqdn }}!
178 closing: This system is part of {{ realm }}
179 dict_reference: {{ motd }}
180
181However, in resolving this, Ansible casts everything to a string, so in this
182example, ``dict_reference`` would be the string-representation of the
183dictionary under the ``motd`` key [#string_casts]_. To get at facts (such as
184``ansible_fqdn``), you still have to use this approach, but for pure parameter
185references, I strongly suggest to use |reclass| interpolation instead, as it
186supports deep references, does not clobber type information, and is more
187efficient anyway::
188
189 parameters:
190 motd:
191 greeting: Welcome to {{ ansible_fqdn }}!
192 closing: This system is part of ${realm}
193 dict_reference: ${motd}
194
195Now you just need to specify realm somewhere. The reference can reside in
196a parent class, while the variable is defined e.g. in the node definition.
197
198And as expected, ``dict_reference`` now points to a dictionary, not
199a string-representation thereof.
200
201.. [#string_casts] I pointed this out to Michael Dehaan, Ansible's chief
202 developer, but he denied this behaviour. When I tried to provide further
203 insights, I found myself banned from the mailing list, apparently because
204 I dared to point out flaws. If you care, you may look at
205 https://github.com/madduck/reclass/issues/6 for more information.
206
207.. include:: extrefs.inc
208.. include:: substs.inc