Jean-Louis FEREY Jean-Louis FEREY - 4 months ago 84
Ini Question

How to write an Ansible task using with_dict in a loop (with_items)

I want to update INI configuration files.

Today, I store my informations in a var file (in group_vars) this way :

# Identity configuration information
identity_servers_conf:
DEFAULT:
admin_token: "{{identity_admin_token}}"
verbose: True
database:
connection: "mysql://{{ identity_db_user }:{{ identity_db_password }}@{{ db_lb_name }}/{{ identity_db }}"
token:
provider: keystone.token.providers.uuid.Provider
driver: keystone.token.persistence.backends.sql.Token


In my Ansible task, I use these informations this way:

- name: configuration / modify keystone.conf ini file DEFAULT section
ini_file:
section: DEFAULT
dest: /etc/keystone/keystone.conf
option: "{{item.key}}"
value: "{{item.value}}"
with_dict: identity_servers_conf['DEFAULT']


Is there a way to iterate through my dict file with each "section" parameters, i.e DEFAULT, database, token. In fact, I try to find a way to do a with_dict nested in a with_items loop.

Answer

I find very interesting this way of organizing variables for .ini files.

I wanted to use it myself, so I worked on a plugin that allows to generate all the keys of an .ini file in one pass with the inifile module.

It works fine and I use to manage my OpenStack configuration files.

I am not a specialist in development, but I think this plugin can be useful for everyone, so if someone wants to take over to maintain and integrate it into ansible, he is welcome.

The plugin transforms the hierarchy data in a list (section, key, value) for use directly with the inifile module with_inidata as below:

vars file :

...
glanceapi_conf:
  DEFAULT:
    verbose: "{{ image_log_verbose }}"
    rabbit_host: "{{ amqp_host }}"
    rabbit_port: "{{ amqp_port }}"
    rabbit_userid: "{{ amqp_userid }}"
    rabbit_password: "{{ amqp_password }}"
    rabbit_ha_queues: "{{ amqp_ha_queues }}"
  database:
    connection: "mysql://{{ image_db_user }}:{{ image_db_password }}@{{ db_host }}/{{ image_db }}"
  keystone_authtoken:
    auth_uri: "http://{{ identity_admin_host }}:{{ identity_api_port }}/v2.0"
    identity_uri: "http://{{ identity_admin_host }}:{{ identity_admin_port }}"
    admin_tenant_name: "{{ image_ks_tenant }}"
    admin_user: "{{ image_ks_user }}"
    admin_password: "{{ image_ks_password }}"
  paste_deploy:
    flavor: keystone
  glance_store:
    default_store: file
    filesystem_store_datadir: /var/lib/glance/images/
...

plugin code :

# (c) 2014, Pierre-Yves KERVIEL <pierreyves.kerviel@orange.com>
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

# inidata is used to manage ini

import ansible.utils as utils
import ansible.errors as errors

class LookupModule(object):

    def __init__(self, basedir=None, **kwargs):
        self.basedir = basedir


    def run(self, terms, inject=None, **kwargs):
        terms = utils.listify_lookup_plugin_terms(terms, self.basedir, inject)

        if not isinstance(terms, dict):
            raise errors.AnsibleError("inidata lookup expects a dictionnary , got '%s'" %terms)

        ret = []
        for item0 in terms:
            if not isinstance(terms[item0], dict):
                raise errors.AnsibleError("inidata lookup expects a dictionary, got '%s'" %terms[item0])
            for item1 in terms[item0]:
                ret.append((item0, item1, terms[item0][item1]))

        return ret

Task code :

- name: configuration.modify_glance-api_conf_file / modify glance-api.conf ini file
  ini_file:
    section: "{{ item.0 }}"
    dest: /etc/glance/glance-api.conf
    option: "{{ item.1 }}"
    value: "{{ item.2 }}"
    backup: yes
  with_inidata: glanceapi_conf

To use it, simply copy the plugin code with the name "dataini" in the directory defined in /etc/ansible.cfg.

This should be /usr/share/ansible_plugins/lookup_plugins for the Ubuntu distribution and write your tasks as in my example.

I hope that this plugin will allow you to simplify your ini files management.

Comments