1***********************************************
2Build Your Inventory
3***********************************************
4
5Running a playbook without an inventory requires several command-line flags. Also, running a playbook against a single device is not a huge efficiency gain over making the same change manually. The next step to harnessing the full power of Ansible is to use an inventory file to organize your managed nodes into groups with information like the ``ansible_network_os`` and the SSH user. A fully-featured inventory file can serve as the source of truth for your network. Using an inventory file, a single playbook can maintain hundreds of network devices with a single command. This page shows you how to build an inventory file, step by step.
6
7.. contents::
8  :local:
9
10Basic inventory
11==================================================
12
13First, group your inventory logically. Best practice is to group servers and network devices by their What (application, stack or microservice), Where (datacenter or region), and When (development stage):
14
15- **What**: db, web, leaf, spine
16- **Where**: east, west, floor_19, building_A
17- **When**: dev, test, staging, prod
18
19Avoid spaces, hyphens, and preceding numbers (use ``floor_19``, not ``19th_floor``) in your group names. Group names are case sensitive.
20
21This tiny example data center illustrates a basic group structure. You can group groups using the syntax ``[metagroupname:children]`` and listing groups as members of the metagroup. Here, the group ``network`` includes all leafs and all spines; the group ``datacenter`` includes all network devices plus all webservers.
22
23.. code-block:: yaml
24
25  ---
26
27  leafs:
28    hosts:
29      leaf01:
30        ansible_host: 10.16.10.11
31      leaf02:
32        ansible_host: 10.16.10.12
33
34  spines:
35    hosts:
36      spine01:
37        ansible_host: 10.16.10.13
38      spine02:
39        ansible_host: 10.16.10.14
40
41  network:
42    children:
43      leafs:
44      spines:
45
46  webservers:
47    hosts:
48      webserver01:
49        ansible_host: 10.16.10.15
50      webserver02:
51        ansible_host: 10.16.10.16
52
53  datacenter:
54    children:
55      network:
56      webservers:
57
58
59
60You can also create this same inventory in INI format.
61
62.. code-block:: ini
63
64   [leafs]
65   leaf01
66   leaf02
67
68   [spines]
69   spine01
70   spine02
71
72   [network:children]
73   leafs
74   spines
75
76   [webservers]
77   webserver01
78   webserver02
79
80   [datacenter:children]
81   network
82   webservers
83
84
85Add variables to the inventory
86================================================================================
87
88Next, you can set values for many of the variables you needed in your first Ansible command in the inventory, so you can skip them in the ``ansible-playbook`` command. In this example, the inventory includes each network device's IP, OS, and SSH user. If your network devices are only accessible by IP, you must add the IP to the inventory file. If you access your network devices using hostnames, the IP is not necessary.
89
90.. code-block:: yaml
91
92  ---
93
94  leafs:
95    hosts:
96      leaf01:
97        ansible_host: 10.16.10.11
98        ansible_network_os: vyos.vyos.vyos
99        ansible_user: my_vyos_user
100      leaf02:
101        ansible_host: 10.16.10.12
102        ansible_network_os: vyos.vyos.vyos
103        ansible_user: my_vyos_user
104
105  spines:
106    hosts:
107      spine01:
108        ansible_host: 10.16.10.13
109        ansible_network_os: vyos.vyos.vyos
110        ansible_user: my_vyos_user
111      spine02:
112        ansible_host: 10.16.10.14
113        ansible_network_os: vyos.vyos.vyos
114        ansible_user: my_vyos_user
115
116  network:
117    children:
118      leafs:
119      spines:
120
121  webservers:
122    hosts:
123      webserver01:
124        ansible_host: 10.16.10.15
125        ansible_user: my_server_user
126      webserver02:
127        ansible_host: 10.16.10.16
128        ansible_user: my_server_user
129
130  datacenter:
131    children:
132      network:
133      webservers:
134
135
136Group variables within inventory
137================================================================================
138
139When devices in a group share the same variable values, such as OS or SSH user, you can reduce duplication and simplify maintenance by consolidating these into group variables:
140
141.. code-block:: yaml
142
143  ---
144
145  leafs:
146    hosts:
147      leaf01:
148        ansible_host: 10.16.10.11
149      leaf02:
150        ansible_host: 10.16.10.12
151    vars:
152      ansible_network_os: vyos.vyos.vyos
153      ansible_user: my_vyos_user
154
155  spines:
156    hosts:
157      spine01:
158        ansible_host: 10.16.10.13
159      spine02:
160        ansible_host: 10.16.10.14
161    vars:
162      ansible_network_os: vyos.vyos.vyos
163      ansible_user: my_vyos_user
164
165  network:
166    children:
167      leafs:
168      spines:
169
170  webservers:
171    hosts:
172      webserver01:
173        ansible_host: 10.16.10.15
174      webserver02:
175        ansible_host: 10.16.10.16
176    vars:
177      ansible_user: my_server_user
178
179  datacenter:
180    children:
181      network:
182      webservers:
183
184Variable syntax
185================================================================================
186
187The syntax for variable values is different in inventory, in playbooks, and in the ``group_vars`` files, which are covered below. Even though playbook and ``group_vars`` files are both written in YAML, you use variables differently in each.
188
189- In an ini-style inventory file you **must** use the syntax ``key=value`` for variable values: ``ansible_network_os=vyos.vyos.vyos``.
190- In any file with the ``.yml`` or ``.yaml`` extension, including playbooks and ``group_vars`` files, you **must** use YAML syntax: ``key: value``.
191
192- In ``group_vars`` files, use the full ``key`` name: ``ansible_network_os: vyos.vyos.vyos``.
193- In playbooks, use the short-form ``key`` name, which drops the ``ansible`` prefix: ``network_os: vyos.vyos.vyos``.
194
195
196Group inventory by platform
197================================================================================
198
199As your inventory grows, you may want to group devices by platform. This allows you to specify platform-specific variables easily for all devices on that platform:
200
201.. code-block:: yaml
202
203  ---
204
205  leafs:
206    hosts:
207      leaf01:
208        ansible_host: 10.16.10.11
209      leaf02:
210        ansible_host: 10.16.10.12
211
212  spines:
213    hosts:
214      spine01:
215        ansible_host: 10.16.10.13
216      spine02:
217        ansible_host: 10.16.10.14
218
219  network:
220    children:
221      leafs:
222      spines:
223    vars:
224      ansible_connection: ansible.netcommon.network_cli
225      ansible_network_os: vyos.vyos.vyos
226      ansible_user: my_vyos_user
227
228  webservers:
229    hosts:
230      webserver01:
231        ansible_host: 10.16.10.15
232      webserver02:
233        ansible_host: 10.16.10.16
234    vars:
235      ansible_user: my_server_user
236
237  datacenter:
238    children:
239      network:
240      webservers:
241
242With this setup, you can run ``first_playbook.yml`` with only two flags:
243
244.. code-block:: console
245
246   ansible-playbook -i inventory.yml -k first_playbook.yml
247
248With the ``-k`` flag, you provide the SSH password(s) at the prompt. Alternatively, you can store SSH and other secrets and passwords securely in your group_vars files with ``ansible-vault``. See :ref:`network_vault` for details.
249
250Verifying the inventory
251=========================
252
253You can use the :ref:`ansible-inventory` CLI command to display the inventory as Ansible sees it.
254
255.. code-block:: console
256
257  $ ansible-inventory -i test.yml --list
258    {
259      "_meta": {
260          "hostvars": {
261              "leaf01": {
262                  "ansible_connection": "ansible.netcommon.network_cli",
263                  "ansible_host": "10.16.10.11",
264                  "ansible_network_os": "vyos.vyos.vyos",
265                  "ansible_user": "my_vyos_user"
266              },
267              "leaf02": {
268                  "ansible_connection": "ansible.netcommon.network_cli",
269                  "ansible_host": "10.16.10.12",
270                  "ansible_network_os": "vyos.vyos.vyos",
271                  "ansible_user": "my_vyos_user"
272              },
273              "spine01": {
274                  "ansible_connection": "ansible.netcommon.network_cli",
275                  "ansible_host": "10.16.10.13",
276                  "ansible_network_os": "vyos.vyos.vyos",
277                  "ansible_user": "my_vyos_user"
278              },
279              "spine02": {
280                  "ansible_connection": "ansible.netcommon.network_cli",
281                  "ansible_host": "10.16.10.14",
282                  "ansible_network_os": "vyos.vyos.vyos",
283                  "ansible_user": "my_vyos_user"
284              },
285              "webserver01": {
286                  "ansible_host": "10.16.10.15",
287                  "ansible_user": "my_server_user"
288              },
289              "webserver02": {
290                  "ansible_host": "10.16.10.16",
291                  "ansible_user": "my_server_user"
292              }
293          }
294      },
295      "all": {
296          "children": [
297              "datacenter",
298              "ungrouped"
299          ]
300      },
301      "datacenter": {
302          "children": [
303              "network",
304              "webservers"
305          ]
306      },
307      "leafs": {
308          "hosts": [
309              "leaf01",
310              "leaf02"
311          ]
312      },
313      "network": {
314          "children": [
315              "leafs",
316              "spines"
317          ]
318      },
319      "spines": {
320          "hosts": [
321              "spine01",
322              "spine02"
323          ]
324      },
325      "webservers": {
326          "hosts": [
327              "webserver01",
328              "webserver02"
329          ]
330      }
331    }
332
333.. _network_vault:
334
335Protecting sensitive variables with ``ansible-vault``
336================================================================================
337
338The ``ansible-vault`` command provides encryption for files and/or individual variables like passwords. This tutorial will show you how to encrypt a single SSH password. You can use the commands below to encrypt other sensitive information, such as database passwords, privilege-escalation passwords and more.
339
340First you must create a password for ansible-vault itself. It is used as the encryption key, and with this you can encrypt dozens of different passwords across your Ansible project. You can access all those secrets (encrypted values) with a single password (the ansible-vault password) when you run your playbooks. Here's a simple example.
341
3421. Create a file and write your password for ansible-vault to it:
343
344.. code-block:: console
345
346   echo "my-ansible-vault-pw" > ~/my-ansible-vault-pw-file
347
3482. Create the encrypted ssh password for your VyOS network devices, pulling your ansible-vault password from the file you just created:
349
350.. code-block:: console
351
352   ansible-vault encrypt_string --vault-id my_user@~/my-ansible-vault-pw-file 'VyOS_SSH_password' --name 'ansible_password'
353
354If you prefer to type your ansible-vault password rather than store it in a file, you can request a prompt:
355
356.. code-block:: console
357
358   ansible-vault encrypt_string --vault-id my_user@prompt 'VyOS_SSH_password' --name 'ansible_password'
359
360and type in the vault password for ``my_user``.
361
362The :option:`--vault-id <ansible-playbook --vault-id>` flag allows different vault passwords for different users or different levels of access. The output includes the user name ``my_user`` from your ``ansible-vault`` command and uses the YAML syntax ``key: value``:
363
364.. code-block:: yaml
365
366   ansible_password: !vault |
367          $ANSIBLE_VAULT;1.2;AES256;my_user
368          66386134653765386232383236303063623663343437643766386435663632343266393064373933
369          3661666132363339303639353538316662616638356631650a316338316663666439383138353032
370          63393934343937373637306162366265383461316334383132626462656463363630613832313562
371          3837646266663835640a313164343535316666653031353763613037656362613535633538386539
372          65656439626166666363323435613131643066353762333232326232323565376635
373   Encryption successful
374
375This is an example using an extract from a  YAML inventory, as the INI format does not support inline vaults:
376
377.. code-block:: yaml
378
379  ...
380
381  vyos: # this is a group in yaml inventory, but you can also do under a host
382    vars:
383      ansible_connection: ansible.netcommon.network_cli
384      ansible_network_os: vyos.vyos.vyos
385      ansible_user: my_vyos_user
386      ansible_password:  !vault |
387           $ANSIBLE_VAULT;1.2;AES256;my_user
388           66386134653765386232383236303063623663343437643766386435663632343266393064373933
389           3661666132363339303639353538316662616638356631650a316338316663666439383138353032
390           63393934343937373637306162366265383461316334383132626462656463363630613832313562
391           3837646266663835640a313164343535316666653031353763613037656362613535633538386539
392           65656439626166666363323435613131643066353762333232326232323565376635
393
394   ...
395
396To use an inline vaulted variables with an INI inventory you need to store it in a 'vars' file in YAML format,
397it can reside in host_vars/ or group_vars/ to be automatically picked up or referenced from a play via ``vars_files`` or ``include_vars``.
398
399To run a playbook with this setup, drop the ``-k`` flag and add a flag for your ``vault-id``:
400
401.. code-block:: console
402
403   ansible-playbook -i inventory --vault-id my_user@~/my-ansible-vault-pw-file first_playbook.yml
404
405Or with a prompt instead of the vault password file:
406
407.. code-block:: console
408
409   ansible-playbook -i inventory --vault-id my_user@prompt first_playbook.yml
410
411To see the original value, you can use the debug module. Please note if your YAML file defines the `ansible_connection` variable (as we used in our example), it will take effect when you execute the command below. To prevent this, please make a copy of the file without the ansible_connection variable.
412
413.. code-block:: console
414
415   cat vyos.yml | grep -v ansible_connection >> vyos_no_connection.yml
416
417   ansible localhost -m debug -a var="ansible_password" -e "@vyos_no_connection.yml" --ask-vault-pass
418   Vault password:
419
420   localhost | SUCCESS => {
421       "ansible_password": "VyOS_SSH_password"
422   }
423
424
425.. warning::
426
427   Vault content can only be decrypted with the password that was used to encrypt it. If you want to stop using one password and move to a new one, you can update and re-encrypt existing vault content with ``ansible-vault rekey myfile``, then provide the old password and the new password. Copies of vault content still encrypted with the old password can still be decrypted with old password.
428
429For more details on building inventory files, see :ref:`the introduction to inventory<intro_inventory>`; for more details on ansible-vault, see :ref:`the full Ansible Vault documentation<vault>`.
430
431Now that you understand the basics of commands, playbooks, and inventory, it's time to explore some more complex Ansible Network examples.
432