Search code examples
ansiblejinja2

Ansible/Jinja: Conditional port publishing in Docker/Podman


My intention is pretty simple: IF I specify a port in my Ansible playbook, expose it in the container being created/updated. Otherwise, do not expose any port.

I think my intention is easier to picture with this attempt:

- name: Create MySQL Docker Container
  containers.podman.podman_container:
    name: "mysql"
    state: present
    image: "mysql:8.0.26"
    publish:
      - "{{ omit if mysql_access_port is not defined else 'mysql_access_port:3306' }}"

This is Podman, but the syntax is just like Docker. So, the port assignment should be in the usual format 3306:3306.

My first issue is that I'm not able to concatenate the mysql_access_port variable and the string :3306 within the jinja expression. It's a mere syntax issue. Googled, but couldn't figure it out.

Now, assuming that the syntax issue above is resolved, let's say, I hardcode the following:

    publish:
      - "{{ omit if mysql_access_port is not defined else '3306:3306' }}"

If mysql_access_port is defined, the port gets assigned as expected. If not defined, instead of skipping the port assignment, I get the following error message:

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Can't create container mysql", "stderr": "Error: error parsing container port: invalid port number: strconv.Atoi: parsing \"__omit_place_holder__0ad9ccf9b7e738c9d218e9d65dd2de8a359ac72c\": invalid syntax\n", "stderr_lines": ["Error: error parsing container port: invalid port number: strconv.Atoi: parsing \"__omit_place_holder__0ad9ccf9b7e738c9d218e9d65dd2de8a359ac72c\": invalid syntax"], "stdout": "", "stdout_lines": []}

It seems there are different ways to get what I need (using omit + ternary etc), but I just can't get it right.


Solution

  • You cannot omit an element of a list, and even if you could, you would have an empty publish, which would probably also be invalid.

    The way to do it is to move the list assignation in a list defined this way:

    publish: ['foobar']
    

    With this, the omit would start to act on the publish parameter, and your behaviour would be the expected one.

    So, in your case:

    publish: >-
      {{ 
        [mysql_access_port ~ ':3306'] 
        if mysql_access_port is defined else omit 
      }}
    

    Notes

    • regarding your syntax issue for mysql_access_port, the concatenation operator in Jinja is the tilde ~
    • a good practice is to try to favour positive assertion rather than negative one, when possible i.e. [mysql_access_port ~ ':3306'] if mysql_access_port is defined as opposed to omit if mysql_access_port is not defined

    A playbook containing the task:

    - debug:
        msg:
          publish: >-
            {{
              [mysql_access_port ~ ':3306']
              if mysql_access_port is defined else omit
            }}
    

    Will yield

    TASK [debug] ***********************************************************
    ok: [localhost] => 
      msg: {}
    

    But, if the same playbook is run with --extra-vars mysql_access_port=3306, it will yield

    TASK [debug] ***********************************************************
    ok: [localhost] => 
      msg:
        publish:
        - 3306:3306