1

I have a playbook that goes like this:

    - name: Install php extensions
      ansible.builtin.apt:
        pkg:
        - php{{ php_version }}{{ item.pkg_extension }}
       loop:
        - { pkg_extension: -mysql }
        - { pkg_extension: -bz2 }
        - { pkg_extension: -curl }
        - { pkg_extension: -gd }
        - { pkg_extension: -imap }
        - { pkg_extension: -mbstring }
        - { pkg_extension: -xml }
        - { pkg_extension: -zip }
      when: php_key_setup is succeeded and nginx_install is succeeded and php_base_install is succeeded
      register: php_install

Sometimes for reasons unknown to me, this fails for one of the packages in the loop. I want to pass these packages as a list or a dictionary to the apt module instead, like in

https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#iterating-over-a-simple-list :

- name: Optimal yum
  ansible.builtin.yum:
    name: "{{ list_of_packages }}"
    state: present

How can I create this list from this loop, concatenating everything without adding an extra step to create this list and reuse it afterwards?

siryx
  • 139
  • 1
  • 2
  • 12

2 Answers2

3

If you have the list of extensions in a list, you can use map to apply the regex_replace filter to each item, like this:

- hosts: localhost
  gather_facts: false
  vars:
    php_version: 8.3
    php_pkg_extensions:
        - mysql
        - bz2
        - curl
        - gd
        - imap
        - mbstring
        - xml
        - zip
  tasks:
    - name: Install php extensions
      ansible.builtin.apt:
        pkg: "{{ packages }}"
      vars:
        packages: >-
          {{
            php_pkg_extensions |
            map('regex_replace', '^(.*)$', 'php%s-\1' % (php_version,))
          }}

You don't need the php_pkg_extensions variable, but it makes things much cleaner. You could instead write:

- hosts: localhost
  gather_facts: false
  vars:
    php_version: 8.3
  tasks:
    - name: Install php extensions
      ansible.builtin.apt:
        pkg: "{{ packages }}"
      vars:
        packages: >-
          {{
            ["mysql", "bz2", "curl", "gd", "imap", "mbstring", "xml", "zip"] |
            map('regex_replace', '^(.*)$', 'php%s-\1' % (php_version,))
          }}
larsks
  • 277,717
  • 41
  • 399
  • 399
2

Given the variables

  php_version: 8.3
  php_pkg_extensions:
    - mysql
    - bz2
    - curl
    - gd
    - imap
    - mbstring
    - xml
    - zip

Declare the list

  packages: "{{ ['php' ~ php_version]|
                product(php_pkg_extensions)|
                map('join', '-') }}"

gives what you want

  packages:
  - php8.3-mysql
  - php8.3-bz2
  - php8.3-curl
  - php8.3-gd
  - php8.3-imap
  - php8.3-mbstring
  - php8.3-xml
  - php8.3-zip

Example of a complete playbook for testing

- hosts: localhost

  vars:

    php_version: 8.3
    php_pkg_extensions:
        - mysql
        - bz2
        - curl
        - gd
        - imap
        - mbstring
        - xml
        - zip
    packages: "{{ ['php' ~ php_version]|
                  product(php_pkg_extensions)|
                  map('join', '-') }}"

  tasks:

    - debug:
        var: packages

    - name: Install php extensions
      ansible.builtin.apt:
        pkg: "{{ packages }}"
      when: install_php_extensions|d(false)|bool
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63