Search code examples
ansibleansible-2.x

How can I extract an attribute from a list of dictionaries and run it in a loop?


I have a list defined in Ansible group_vars as shown below:

ipa_ca_anchors:
  - { certmap_name: CERT1, cert_cn: 'CN=CA1, OU=ROOT', cert_file: cert1.pem }
  - { certmap_name: CERT2, cert_cn: 'CN=CA2, OU=ROOT', cert_file: cert2.pem }

I would first like to install the certificates by running the commands in a loop one at a time:

ipa-cacert-manage install /etc/pki/ca-trust/anchors/cert1.pem
ipa-cacert-manage install /etc/pki/ca-trust/anchors/cert2.pem

Then I would like to use ipa_ca_anchors variables to create a file that will ultimately look like this:

certmap CERT1       CN=CA1, OU=ROOT
CERT1:CmapLdapAttr  seeAlso
CERT1:verifycert    off
certmap CERT2       CN=CA2, OU=ROOT
CERT2:CmapLdapAttr  seeAlso
CERT2:verifycert    off

I tried the following:

---
- name: Install certs
  command: "ipa-cacert-manage install /etc/pki/ca-trust/anchors/{{ ipa_ca_anchors|map(attribute='cert_file') | list }}"

- name: Populate certmap.conf
  lineinfile:
    path: /etc/dirsrv/slapd-REALM/certmap.conf
    state: present
    line: "{{ item }}"
  with_items:
    - "certmap {{ ipa_ca_anchors|map(attribute='certmap_name') | list }}  {{ ipa_ca_anchors|map(attribute='cert_cn') | list }}"
    - "{{ ipa_ca_anchors|map(attribute='certmap_name') | list }}:CmapLdapAttr seeAlso"
    - "{{ ipa_ca_anchors|map(attribute='certmap_name') | list }}:verifycert off"

The command failed because of the [ ], and it is not looping as one at a time.

Any help is greatly appreciated.

Thanks!


Solution

    • The template of the command seems to be trivial
      cmd: "ipa-cacert-manage install /etc/pki/ca-trust/anchors/{{ item.cert_file }}"
    

    Testing it in the loop

        - debug:
            var: cmd
          loop: "{{ ipa_ca_anchors }}"
    

    gives (abridged)

      cmd: ipa-cacert-manage install /etc/pki/ca-trust/anchors/cert1.pem
      cmd: ipa-cacert-manage install /etc/pki/ca-trust/anchors/cert2.pem
    

    If this is what you want run the command

        - command: "{{ cmd }}"
          loop: "{{ ipa_ca_anchors }}"
    
    • Use the filter format and create the template
      content: |
        {% for i in ipa_ca_anchors %}
        {{ '%s %s %+21s' % ('certmap', i.certmap_name, i.cert_cn) }}
        {{ '%s:%s %+8s' % (i.certmap_name, 'CmapLdapAttr', 'seeAlso') }}
        {{ '%s:%s %+6s' % (i.certmap_name, 'verifycert', 'off') }}
        {% endfor %}
    

    Testing it

        - debug:
            var: content
    

    gives

      content: |-
        certmap CERT1       CN=CA1, OU=ROOT
        CERT1:CmapLdapAttr  seeAlso
        CERT1:verifycert    off
        certmap CERT2       CN=CA2, OU=ROOT
        CERT2:CmapLdapAttr  seeAlso
        CERT2:verifycert    off
    

    If this is what you want write the content to a file. For example,

        - copy:
            dest: /tmp/test.txt
            content: "{{ content }}"
    

    will create the file

    shell> cat /tmp/test.txt
    certmap CERT1       CN=CA1, OU=ROOT
    CERT1:CmapLdapAttr  seeAlso
    CERT1:verifycert    off
    certmap CERT2       CN=CA2, OU=ROOT
    CERT2:CmapLdapAttr  seeAlso
    CERT2:verifycert    off
    

    Example of a complete playbook for testing

     hosts: localhost
    
      vars:
    
        ipa_ca_anchors:
          - {certmap_name: CERT1, cert_cn: 'CN=CA1, OU=ROOT', cert_file: cert1.pem}
          - {certmap_name: CERT2, cert_cn: 'CN=CA2, OU=ROOT', cert_file: cert2.pem}
    
        cmd: "ipa-cacert-manage install /etc/pki/ca-trust/anchors/{{ item.cert_file }}"
        content: |
          {% for i in ipa_ca_anchors %}
          {{ '%s %s %+21s' % ('certmap', i.certmap_name, i.cert_cn) }}
          {{ '%s:%s %+8s' % (i.certmap_name, 'CmapLdapAttr', 'seeAlso') }}
          {{ '%s:%s %+6s' % (i.certmap_name, 'verifycert', 'off') }}
          {% endfor %}
    
      tasks:
    
        - debug:
            var: cmd
          loop: "{{ ipa_ca_anchors }}"
        - debug:
            var: content
    
        - copy:
            dest: /tmp/test.txt
            content: "{{ content }}"
    
        # - command: "{{ cmd }}"
        #   loop: "{{ ipa_ca_anchors }}"
    

    Q: "How can I use this template to append the content to an existing file?"

    A: Use blockinfile

        - blockinfile:
            dest: /tmp/certmap.conf
            block: "{{ content }}"