martin f. krafft | 5ee69b3 | 2013-06-24 13:41:06 +0200 | [diff] [blame] | 1 | ============================================================= |
| 2 | reclass — recursive external node classification |
| 3 | ============================================================= |
| 4 | reclass is © 2007–2013 martin f. krafft <madduck@madduck.net> |
| 5 | and available under the terms of the Artistic Licence 2.0 |
| 6 | ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' |
| 7 | |
| 8 | Please make sure to read the generic information in the README file first, or |
| 9 | alongside this document. |
| 10 | |
| 11 | Quick start with Ansible |
| 12 | ~~~~~~~~~~~~~~~~~~~~~~~~ |
| 13 | The following steps should get you up and running quickly. Generally, we will |
| 14 | be working in /etc/ansible. However, if you are using a source-code checkout |
| 15 | of Ansible, you might also want to work inside the ./hacking directory |
| 16 | instead. |
| 17 | |
| 18 | Or you can also just look into ./examples/ansible of your reclass checkout, |
| 19 | where the following steps have already been prepared. |
| 20 | |
| 21 | /…/reclass refers to the location of your reclass checkout. |
| 22 | |
martin f. krafft | a745101 | 2013-06-26 18:09:20 +0200 | [diff] [blame] | 23 | 0. Run 'make' in the root of the reclass checkout (see the section |
| 24 | 'Installation' in the README file for the reason). |
| 25 | |
martin f. krafft | 5ee69b3 | 2013-06-24 13:41:06 +0200 | [diff] [blame] | 26 | 1. Symlink /…/reclass/adapters/ansible to /etc/ansible/hosts (or |
| 27 | ./hacking/hosts) |
| 28 | |
| 29 | 2. Copy the two directories 'nodes' and 'classes' from the example |
| 30 | subdirectory in the reclass checkout to /etc/ansible |
| 31 | |
| 32 | If you prefer to put those directories elsewhere, you can create |
| 33 | /etc/ansible/reclass-config.yml with contents such as |
| 34 | |
| 35 | storage_type: yaml_fs |
| 36 | nodes_uri: /srv/reclass/nodes |
| 37 | classes_uri: /srv/reclass/classes |
| 38 | |
| 39 | Note that yaml_fs is currently the only supported storage_type, and it's |
| 40 | the default if you don't set it. |
| 41 | |
| 42 | 3. Check out your inventory by invoking |
| 43 | |
| 44 | ./hosts --list |
| 45 | |
| 46 | which should return 5 groups in JSON-format, and each group has exactly |
| 47 | one member 'localhost'. |
| 48 | |
| 49 | 4. See the node information for 'localhost': |
| 50 | |
| 51 | ./hosts --host localhost |
| 52 | |
| 53 | This should print a set of keys and values, including a greeting, |
martin f. krafft | 4cf004b | 2013-06-26 18:38:23 +0200 | [diff] [blame] | 54 | a colour, and a sub-class called '__reclas__'. |
martin f. krafft | 5ee69b3 | 2013-06-24 13:41:06 +0200 | [diff] [blame] | 55 | |
| 56 | 5. Execute some ansible commands, e.g. |
| 57 | |
| 58 | ansible -i hosts \* --list-hosts |
| 59 | ansible -i hosts \* -m ping |
| 60 | ansible -i hosts \* -m debug -a 'msg="${greeting}"' |
| 61 | ansible -i hosts \* -m setup |
| 62 | ansible-playbook -i hosts test.yml |
| 63 | |
| 64 | 6. You can also invoke reclass directly, which gives a slightly different |
| 65 | view onto the same data, i.e. before it has been adapted for Ansible: |
| 66 | |
| 67 | /…/reclass.py --pretty-print --inventory |
| 68 | /…/reclass.py --pretty-print --nodeinfo localhost |
| 69 | |
| 70 | Integration with Ansible |
| 71 | ~~~~~~~~~~~~~~~~~~~~~~~~ |
| 72 | The integration between reclass and Ansible is performed through an adapter, |
| 73 | and needs not be of our concern too much. |
| 74 | |
| 75 | However, Ansible has no concept of "nodes", "applications", "parameters", and |
| 76 | "classes". Therefore it is necessary to explain how those correspond to |
| 77 | Ansible. Crudely, the following mapping exists: |
| 78 | |
| 79 | nodes hosts |
| 80 | classes groups |
| 81 | applications playbooks |
| 82 | parameters host_vars |
| 83 | |
| 84 | reclass does not provide any group_vars because of its node-centric |
| 85 | perspective. While class definitions include parameters, those are inherited |
| 86 | by the node definitions and hence become node_vars. |
| 87 | |
| 88 | reclass also does not provide playbooks, nor does it deal with any of the |
| 89 | related Ansible concepts, i.e. vars_files, vars, tasks, handlers, roles, etc.. |
| 90 | |
| 91 | Let it be said at this point that you'll probably want to stop using |
| 92 | host_vars, group_vars and vars_files altogether, and if only because you |
| 93 | should no longer need them, but also because the variable precedence rules |
| 94 | of Ansible are full of surprises, at least to me. |
| 95 | |
| 96 | reclass' Ansible adapter massage the reclass output into Ansible-usable data, |
| 97 | namely: |
| 98 | |
| 99 | - Every class in the ancestry of a node becomes a group to Ansible. This is |
| 100 | mainly useful to be able to target nodes during interactive use of |
| 101 | Ansible, e.g. |
| 102 | |
| 103 | ansible debiannode@wheezy -m command -a 'apt-get upgrade' |
| 104 | → upgrade all Debian nodes running wheezy |
| 105 | |
| 106 | ansible ssh.server -m command -a 'invoke-rc.d ssh restart' |
| 107 | → restart all SSH server processes |
| 108 | |
| 109 | ansible mailserver -m command -a 'tail -n1000 /var/log/mail.err' |
| 110 | → obtain the last 1,000 lines of all mailserver error log files |
| 111 | |
| 112 | The attentive reader might stumble over the use of singular words, whereas |
| 113 | it might make more sense to address all 'mailserver*s*' with this tool. |
| 114 | This is convention and up to you. I prefer to think of my node as |
| 115 | a (singular) mailserver when I add 'mailserver' to its parent classes. |
| 116 | |
| 117 | - Every entry in the list of a host's applications might well correspond to |
| 118 | an Ansible playbook. Therefore, reclass creates a (Ansible-)group for |
| 119 | every application, and adds '_hosts' to the name. This postfix can be |
| 120 | configured with a CLI option (--applications-postfix) or in the |
| 121 | configuration file (applications_postfix). |
| 122 | |
| 123 | For instance, the ssh.server class adds the ssh.server application to |
| 124 | a node's application list. Now the admin might create an Ansible playbook |
| 125 | like so: |
| 126 | |
| 127 | - name: SSH server management |
| 128 | hosts: ssh.server_hosts ← SEE HERE |
| 129 | tasks: |
| 130 | - name: install SSH package |
| 131 | action: … |
| 132 | … |
| 133 | |
| 134 | There's a bit of redundancy in this, but unfortunately Ansible playbooks |
| 135 | hardcode the nodes to which a playbook applies. |
| 136 | |
| 137 | It's now trivial to apply this playbook across your infrastructure: |
| 138 | |
| 139 | ansible-playbook ssh.server.yml |
| 140 | |
| 141 | My suggested way to use Ansible site-wide is then to create a 'site' |
| 142 | playbook that includes all the other playbooks (which shall hopefully be |
| 143 | based on Ansible roles), and then to invoke Ansible like this: |
| 144 | |
| 145 | ansible-playbook site.yml |
| 146 | |
| 147 | or, if you prefer only to reconfigure a subset of nodes, e.g. all |
| 148 | webservers: |
| 149 | |
| 150 | ansible-playbook site.yml --limit webserver |
| 151 | |
| 152 | Again, if the singular word 'webserver' puts you off, change the |
| 153 | convention as you wish. |
| 154 | |
| 155 | And if anyone comes up with a way to directly connect groups in the |
| 156 | inventory with roles, thereby making it unnecessary to write playbook |
| 157 | files (containing redundant information), please tell me! |
| 158 | |
| 159 | - Parameters corresponding to a node become host_vars for that host. |
| 160 | |
| 161 | It is possible to include Jinja2-style variables like you would in Ansible, |
| 162 | in parameter values. This is especially powerful in combination with the |
| 163 | recursive merging, e.g. |
| 164 | |
| 165 | parameters: |
| 166 | motd: |
| 167 | greeting: Welcome to {{ ansible_fqdn }}! |
| 168 | closing: This system is part of {{ realm }} |
| 169 | |
| 170 | Now you just need to specify realm somewhere. The reference can reside in |
| 171 | a parent class, while the variable is defined e.g. in the node. |