ansibleansible-role

Ansible: build shell command depending on variables set


Let's say I would like to run the following task from ansible:

    - name: dns-cloudflare | Request certificate
      ansible.builtin.shell:
        cmd: certbot certonly \
              --dns-cloudflare \
              --dns-cloudflare-credentials {{ certbot_cloudflare_credentials_file }} \
              --non-interactive \
              --agree-tos \
              --expand \
              --email {{ certbot_email }} \
              --domain {{ __domains }}
      args:
        executable: /bin/bash
        creates: "{{ certbot_directory }}/{{ item.name }}/{{ item.name }}/cert.pem"

I build it with a block like this:

certbot_cert:
  - name: test1.example.com
    cn:
      - test2-cn.example.com
    post-hook: systemctl restart apache2
  - name: test3.example.com

I want to add the --post-hook argument to my certbot command depending on whether item.post-hook. And the content for this hook is not static, whatever I type in there should land in my certbot command like --post-hook 'systemctl restart apache2'

But when I don't define this variable, there should not be an empty post-hook, it should not be in the certbot command at all.

How can I achieve this?

I played around with variables and filters and I read through the documentation but I didn't find a proper way to handle is. Duplication this task several times for every possible optional argument should not be the way.


Solution

  • The way you've written the value of cmd does not preserve newlines -- which is what you want, since that means (a) you don't need to escape (\) the end of lines like you've done in your example, and (b) you can conveniently use jinja conditionals to suppress some lines.

    Like this:

    - hosts: localhost
      gather_facts: false
      vars:
        certbot_cloudflare_credentials_file: creds.conf
        certbot_email: alice@example.com
        __domains: example.com
        certbot_directory: certs
        certbot_cert:
        - name: test1.example.com
          cn:
            - test2-cn.example.com
          post-hook: systemctl restart apache2
        - name: test3.example.com
      tasks:
        - name: dns-cloudflare | Request certificate
          loop: "{{ certbot_cert }}"
          ansible.builtin.shell:
            cmd: certbot certonly
              --dns-cloudflare
              --dns-cloudflare-credentials "{{ certbot_cloudflare_credentials_file }}"
              --non-interactive
              --agree-tos
              --expand
              --email "{{ certbot_email }}"
              --domain "{{ __domains }}"
              {% if 'post-hook' in item %}
              --post-hook "{{ item["post-hook"] }}"
              {% endif %}
          args:
            executable: /bin/bash
            creates: "{{ certbot_directory }}/{{ item.name }}/{{ item.name }}/cert.pem"
    

    For the first item in certbot_cert, this will run:

    certbot certonly --dns-cloudflare --dns-cloudflare-credentials creds.conf --non-interactive --agree-tos --expand --email alice@example.com --domain example.com --post-hook systemctl restart apache2
    

    And for the second line it will run:

    certbot certonly --dns-cloudflare --dns-cloudflare-credentials creds.conf --non-interactive --agree-tos --expand --email alice@example.com --domain example.com