Connect cobbler with ansible (Dynamic Inventory)

In Exercise 3: Setting up a netboot environment with cobbler we introduced Cobbler as a provisioning tool for compute nodes in the cluster. The information of each node is stored in a database that can be accessed using Cobbler’s XMLRPC API. For instance, Cobbler’s management classes can be mapped into the groups of hosts of the inventory hosts file of ansible. In other words

[root@master ~]# cobbler system report | awk '/Management Classes|Name/ && !/DNS|Servers/'
Name                           : c01
Management Classes             : ['compute']
Name                           : c02
Management Classes             : ['compute']
Name                           : c03
Management Classes             : ['compute']
Name                           : c04
Management Classes             : ['compute']

can be mapped into

[root@master ~]# cat inventory_compute
# Inventory file
[compute]
c01
c02
c03
c04

Warning

Make sure you have the compute management class configured, if not, run the command cobbler mgmtclass add --name=compute and then add this class to the system with the command cobbler system edit --name=c01 --mgmt-classes=compute. Do this command for every system (compute node) in your cluster

This “mapping” is specially useful to keep the inventory automatically updated and consistent with changes of the cluster. To achieve this mapping we can use a script instead of the inventory host file. In the particular case of Cobbler, the script cobbler.py is required, as well as some additional configuration which is illustrated in the following ansible playbook:

Warning

Make sure the line orderby_keyname = 'owners'  # alternatively 'mgmt_classes' is changed to orderby_keyname = 'mgmt_classes' in the file cobbler.py

---
# ansiblemaster.yml

- name: Configure dynamic inventory for ansible using Cobbler database
  hosts: master

  vars:
   hosts_path: '/etc/ansible/hosts'

  tasks:
    - name: install ansible
      yum:
       name: ansible
       state: installed

    - name: Remove default hosts file if it exists
      file:
        state: absent
        path: "{{ hosts_path }}"
      when: hosts_path is is_file

    - name: create hosts directory
      file:
        path: "{{ hosts_path }}"
        owner: root
        group: root
        state: directory
        mode: "u+rwx,g=rx,o=rx"

    - name: copy static configuration files
      copy:
        src: "{{ item }}"
        dest: "{{ hosts_path }}/{{ item }}"
        owner: root
        group: root
        mode: "u=rw,g=r,o=r"
      with_items:
        - hosts
        - cobbler.ini

    - name: copy dynamic inventory file
      copy:
        src: cobbler.py
        dest: "{{ hosts_path }}/cobbler.py"
        owner: root
        group: root
        mode: "u=rwx,g=rx,o=rx"
...

The file hosts contains the declaration of the master node:

[master]
master.hpc ansible_connection=local

The file cobbler.ini must contain the correct IP address of the master node:

[cobbler]

# Set Cobbler's hostname or IP address
host = http://192.168.16.1/cobbler_api

cache_path = /tmp
cache_max_age = 900

And finally, the script cobbler.py, as the other files, must be in the same directory as the ansible playbook in order to work. Once all is prepared, the playbook can be executed in the following manner:

[root@master dynamic_inventory]# ansible-playbook -i inventory ansiblemaster.yml

Note that after the playbook is successfully executed, the file inventory is no longer be needed. For instance, run one more time the playbook:

[root@master dynamic_inventory]# ansible-playbook ansiblemaster.yml

PLAY [Configure dynamic inventory for ansible using Cobbler database] ************

TASK [Gathering Facts] ***********************************************************
ok: [master.hpc]

TASK [install ansible] ***********************************************************
ok: [master.hpc]

TASK [Remove default hosts file if it exists] ************************************
skipping: [master.hpc]

TASK [create hosts directory] ****************************************************
ok: [master.hpc]

TASK [copy static configuration files] *******************************************
ok: [master.hpc] => (item=hosts)
ok: [master.hpc] => (item=cobbler.ini)

TASK [copy dynamic inventory file] ***********************************************
ok: [master.hpc]

PLAY RECAP ***********************************************************************
master.hpc                 : ok=5    changed=0    unreachable=0    failed=0

Task

How do you explain the “skipping” result for the “Remove default hosts file if it exists” task?