skip to Main Content

I want to template php.ini configs for apache2 and cli. I filtered out the default options and added them to a dictionary like this:

php_config_options:
  cli:
    engine: "On"
    short_open_tag: "Off"
    precision: 14
    [...]
  apache2:
    engine: "On"
    short_open_tag: "Off"
    precision: 14
    [...]

I have put this under vars/Ubuntu-22.yaml so that I can configure it ongoing for the releases. My template looks like this:

{% if php_config_options[environment] is defined %}
{% for option, value in php_config_options[environment].items() %}
{{ option }} = {{ value }}
{% endfor %}
{% endif %}

and my task like this:

- name: setup | Template php.ini
  ansible.builtin.template:
    src: "{{ php_version }}/php.ini.j2"
    dest: /etc/php/{{ php_version }}/apache2/php.ini
    owner: root
    group: root
    mode: 0644
  vars:
    environment: "apache2"

When I try to run it I got the Error dict object has no element [] but I don’t know why. Can anyone help me here?

My idea is to use these default variables, but when I want to change one I will set this in either group_vars or host_vars and he picks this + the other default ones.

2

Answers


  1. You should use community.general.ini_file module, which was designed exactly for your usecase – to tweak existing settings, without maintaining defaults yourself.

    I created a minimal reproducible playbook to illustrate how you can map your yaml settings into existing ini file

    Let’s say we have a config.ini file inside playbook directory, with following contents:

    [section0]
    key0 = value0
    [section1]
    key1 = old_value
    

    We can then execute the following playbook.yaml

    - name: Generate ini from yaml
      hosts: localhost
      vars:
        default_php_config_options:
          section1:
            key1: default_value
          section2:
            key2: default_value
          section3:
            key3: default_value
        php_config_options:
          section1:
            key1: value1
          section2:
            key2: value2
            key3: value4
      tasks:
        - name: Generate INI file from YAML variable
          community.general.ini_file:
            path: "{{ playbook_dir }}/config.ini"
            section: "{{ item.0 }}"
            option: "{{ item.1 }}"
            value: "{{ item.2 }}"
            mode: "0644"
          loop: >-
              {%- set results = [] -%}
              {%- for section in default_php_config_options | combine(php_config_options) | items -%}
              {%- for item in section.1.items() -%}
              {%- set _ = results.append([section.0, item.0, item.1]) %}
              {%- endfor -%}
              {%- endfor -%}
              {{ results }}
    

    In this playbook we define 2 variables, default_php_config_options with default settings that need to be overriden and php_config_options which contain overrides for default options.

    The output of command ansible-playbook playbook.yaml will contain

    TASK [Generate INI file from YAML variable] 
    changed: [localhost] => (item=['section1', 'key1', 'value1'])
    changed: [localhost] => (item=['section2', 'key2', 'value2'])
    changed: [localhost] => (item=['section2', 'key3', 'value4'])
    changed: [localhost] => (item=['section3', 'key3', 'default_value'])
    

    and the contents of file config.ini are

    [section0]
    key0 = value0
    [section1]
    key1 = value1
    [section2]
    key2 = value2
    key3 = value4
    [section3]
    key3 = default_value
    

    Notice that value of key1 in section1 was replaced, and missing options were added, while original section0 values remain unchanged.

    Now about this loop, what are we doing – we are combining default_php_config_options with php_config_options, thus overriding former with values from later if present (see combine filter docs), and then for each key/value pair in each section we are creating list, containing

    • section
    • key name
    • value of that key

    And executing init_file module for each generated list. I’m sure that other jinja-gurus can come up with clever function to solve same task, but I like my playbooks to be explicit.

    The caveat is that if you’ll delete something from default_php_config_options or in php_config_options, but in key, that wasn’t present in defaults, it wont change already changed keys or sections back to default values. In that case you should either explicitly specify old value, or create a separate task to remove unneeded keys.

    Edit: added combine example. default_php_config_options | combine(php_config_options) can be used with @Vladimir Botka example as well, but I’ll leave my answer which gives an ability to work with existing ini files.

    Login or Signup to reply.
  2. Given the simplified dictionary

    php_config_options:
      cli:
        engine: "On"
        short_open_tag: "Off"
        precision: 14
    

    Use the filter community.general.to_ini. For example, the template

    {{ php_config_options | community.general.to_ini }}
    

    gives

    [cli]
    engine = On
    short_open_tag = Off
    precision = 14
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        php_config_options:
          cli:
            engine: "On"
            short_open_tag: "Off"
            precision: 14
    
      tasks:
    
        - copy:
            dest: /tmp/ansible/php.ini
            content: |
              {{ php_config_options | community.general.to_ini }}
    

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search