When working with an Ansible dynamic inventory, you may want to update it from your playbook on the fly. For instance, you may want to create a server and then install an application on it without calling a second playbook or developing specific code to create a runtime group (e.g. “add_host” module). Or you may want to update the inventory on the fly without having to wait for an asynchronous mechanism to be triggered. This all this project is about: providing you a simple, fully encrypted, interactive dynamic inventory made to measure for your environment.

Back-end setup

1) Install the database software:

This will serve as a data storage for your Ansible inventory data (More details here)

wget https://siodb.io/packages/InstallSiodb.sh
chmod u+x ./InstallSiodb.sh
sudo ./InstallSiodb.sh

2) Get the last version of the dynamic inventory:

git clone https://github.com/siodb/ansible-dynamic-inventory.git
cd ansible-dynamic-inventory

3) Create the inventory data model and the database user:

sudo -i -u siodb siocli --user root < sio_inv_data_model.sql
sudo -i -u siodb siocli --user root < sio_inv_user.sql

4) Create your groups, groupvars, hosts and hostvars:

On this step, you can add your groups, groupvars, hosts and hostvars by inserting them into the correct table. Also, you can link them together using the columns:

  • groups_variables.group_id: to link variables to a group from the group table.
  • hosts.group_id: to link a group from the group table.
  • hosts_variables.host_id: to link variables to a host from the hosts table.

Here is a overview of the data model used for this inventory (red number indicating the order in which to insert data):

So, first connect to the database freshly installed from step 1):

sudo -i -u siodb siocli --user root

Then insert your data. For instance:

use database sioinv ;
insert into groups
values
    ( 'production' ),
    ( 'test' ),
    ( 'development' )
;
insert into groups_variables
values
    ( 1, 'domain_name', 'company.com' ),
    ( 2, 'environment_name', 'production' ),
    ( 2, 'subnet', '10.10.0.0/16' ),
    ( 3, 'environment_name', 'test' ),
    ( 3, 'subnet', '10.20.0.0/16' ),
    ( 4, 'environment_name', 'development' ),
    ( 4, 'subnet', '10.30.0.0/16' )
;

insert into hosts
values
    ( 2, 'server-01', CURRENT_TIMESTAMP ),
    ( 3, 'server-02', CURRENT_TIMESTAMP ),
    ( 4, 'server-03', CURRENT_TIMESTAMP )
;

insert into hosts_variables
values
    ( 1, 'public_ip', '0.1.2.3' ),
    ( 1, 'application', 'app01' ),
    ( 2, 'public_ip', '0.1.2.4' ),
    ( 2, 'application', 'app02' ),
    ( 3, 'public_ip', '0.1.2.4' ),
    ( 3, 'application', 'app02' )
;

Configure the inventory

You must tell the inventory script where to lookup for its data. That is done configuring the file sio_inv.ini:

[sio_inv]
siodb_rest_ip = localhost
siodb_rest_port = 50443
siodb_rest_user = sioinv
siodb_rest_token = [token-generated-from-script-sio_inv_user.sql]
siodb_rest_tls_verify_certificate = no

Validate the inventory

Use the command ansible-inventory to validate your inventory. For instance:

$ ansible-inventory -i ./sio_inv.py  --graph --vars
@all:
  |--@development:
  |  |--server-03
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = development}
  |  |  |--{subnet = 10.30.0.0/16}
  |  |--{environment_name = development}
  |  |--{subnet = 10.30.0.0/16}
  |--@production:
  |  |--hypervisor-01
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = production}
  |  |  |--{subnet = 10.10.0.0/16}
  |  |--hypervisor-02
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = production}
  |  |  |--{subnet = 10.10.0.0/16}
  |  |--server-01
  |  |  |--{application = app01}
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = production}
  |  |  |--{public_ip = 0.1.2.3}
  |  |  |--{subnet = 10.10.0.0/16}
  |  |--server-04
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = production}
  |  |  |--{subnet = 10.10.0.0/16}
  |  |--{environment_name = production}
  |  |--{subnet = 10.10.0.0/16}
  |--@test:
  |  |--server-02
  |  |  |--{application = app02}
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = test}
  |  |  |--{public_ip = 0.1.2.4}
  |  |  |--{subnet = 10.20.0.0/16}
  |  |--server-05
  |  |  |--{domain_name = company.com}
  |  |  |--{environment_name = test}
  |  |  |--{subnet = 10.20.0.0/16}
  |  |--{environment_name = test}
  |  |--{subnet = 10.20.0.0/16}
  |--@ungrouped:
  |--{domain_name = company.com}

Example of playbook

Here is an example of how to interactively deal with the dynamic inventory while the playbook is running
(Set the variable {{ sioinv_user_token }} where it makes sense for you and store the token in Ansible Vault):


---
- name: Full Stack Service creation
  hosts: hypervisor-01
  tasks:

    - name: Create machine
      shell: >
        echo "Module or command to create a new Virtual Machine {{ vm_name }}"

    - name: Update the custom dynamic inventory on the fly with the just-created vm
      uri:
        url: https://localhost:50443/databases/sioinv/tables/hosts/rows
        validate_certs: false
        user: sioinv
        password: "{{ sioinv_user_token }}"
        method: POST
        body: >
          [{
            "name": "{{ vm_name }}"
          }]
        force_basic_auth: yes
        status_code: 201
        body_format: json
      register: r_vm_post

    - name: Add hostvars on the fly to the just-created vm
      uri:
        url: https://localhost:50443/databases/sioinv/tables/hosts_variables/rows
        validate_certs: false
        user: sioinv
        password: "{{ sioinv_user_token }}"
        method: POST
        body: >
          [{
            "host_id": {{ r_vm_post.json.trids[0] }},
            "name": "ip_address",
            "value": "10.10.0.0"
          }]
        force_basic_auth: yes
        status_code: 201
        body_format: json

    - name: Refresh the inventory in current run to include the new VM and its variables before moving to the next play
      meta: refresh_inventory

- name: Full Stack Service creation
  hosts: "{{ vm_name }}"
  tasks:

    - name: Create the new database on the new VM
      shell: >
        echo "Module or command to create a new database on {{ vm_name }}"

Last words before you go

The inventory is the foundation of your Ansible strategy. It must be dynamic as possible and avoiding complexity to ensure smooth maintenance in the future. Modifying the inventory may lead you to change all your roles and playbooks and is something you may want to avoid. With this simple inventory describe here, you’ll have a strong foundation for your Ansible automation.

I hope this helps you, and please do contact us or comment below if you need more details.