'Conditionally add argument to argv

I want to conditionally pass --detach into argv like this:

- name: run docker container with service
  command:
  args:
    argv:
      - docker
      - run
      - "{{ '' if wait else '--detach' }}"
      - "--restart=always"
      - "--network=host"
      - --log-driver
      - fluentd
      - --log-opt
      - fluentd-async-connect=true
      - --log-opt
      - fluentd-sub-second-precision=true
      - --log-opt
      - mode=non-blocking

But it doesn't work because empty argv arguments are incorrectly passed to docker. Is there any workaround?



Solution 1:[1]

I found a way to modify the solution from Frenchy so that there is no need to create a custom filter. Instead of difference we can use reject('equalto', ...) like this:

- name: run docker container with service
  command:
  args:
    argv: "{{ command_args | reject('equalto', omit) | list }}"
  vars:
    command_args:
      - docker
      - run
      - "{{ omit if wait is defined and wait else '--detach' }}"
      - "--network=host"
      - --log-driver
      - fluentd
      - --log-opt
      - fluentd-async-connect=true
      - --log-opt
      - fluentd-sub-second-precision=true
      - --log-opt
      - mode=non-blocking

Solution 2:[2]

i have had same problem so, i suggest you to use omit with a little tips because omit is not very well changed in arguments:

- name: echo test
  command:
  args:
    argv: "{{ command_args | difference(omit) }}"
  vars:
    command_args:
      - docker
      - run
      - "{{ omit if wait else '--detach' }}"
      - "--restart=always"
      - "--network=host"

i have read that somewhere but impossible to remember the post

if you have same options defined more times, the solution above is not functional, you could use a custom filter named here extractarg:

#!/usr/bin/python
class FilterModule(object):

    def filters(self):
        return {
            'extractarg': self.extractarg
        }
 
    def extractarg(self, args):
        result = []
        print(args)
        for k in args:
            if not k.startswith('__omit_place'):
                result.append(k)
        return result 

and you change the lines

  args:
    argv: "{{ command_args | difference(omit) }}"

by

  args:
    argv: "{{ command_args | extractarg }}"

if you dont like custom filter, you could use just jinja loop :

- name: echo test
  command:
  args:
    argv: "{{ _argv }}"
  vars:
    command_args:
      - docker
      - run
      - "{{ omit if wait else '--detach' }}"
      - "--restart=always"
      - "--network=host" 
   _argv: >-        
        {%- set ns = namespace() -%}
        {%- set ns.result = [] -%}
        {%- for v in command_args if not v.startswith('__omit_place') -%}
        {%- set ns.result = ns.result + [v] -%}
        {%- endfor -%}
        {{ ns.result }}

Solution 3:[3]

Just don't use the command module when there are dedicated modules to achieve what you need — in this case docker_container.

Then, your issue become trivial, since the detach parameter expects a boolean. In your case, then it would just be not wait.

So, your task become:

- docker_container:
    detach: "{{ not wait }}"
    restart: yes
    restart_policy: always
    log_driver: fluentd
    log_options:
      fluentd-async-connect: true
      fluentd-sub-second-precision: true
      mode: non-blocking

Solution 4:[4]

Create a switch on your own. For example, as a hint, the playbook below

shell> cat pb.yml
- hosts: localhost
  tasks:
    - debug:
        var: argv
      vars:
        argv: "{{ command_args|zip(switch)|
                               selectattr('1')|
                               map(attribute='0')|list }}"
        switch:
          - true
          - true
          - "{{ wait|d(false)|bool }}"
          - true
        command_args:
          - docker
          - run
          - --detach
          - --restart=always

gives (abridged)

shell> ansible-playbook pb.yml
...
  argv:
  - docker
  - run
  - --restart=always
shell> ansible-playbook pb.yml -e wait=true
...
  argv:
  - docker
  - run
  - --detach
  - --restart=always

Fit the lists to your needs.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vlad
Solution 2
Solution 3
Solution 4