Search code examples
kubernetesansible

How to properly escape symbols in ansible command?


I want to execute the command on each node:

docker ps --format '{{.Names}}' -a | egrep -v '^k8s.*$'

I tried millions of variants to execute command in ansible, including:

- hosts: kubernetes
  tasks:
    - name: check docker
      command:
        cmd: docker ps --format '{{.Names}}' -a | egrep -v '^k8s.*$'
      register: doc

    - debug: var=doc.stdout_lines

I tried to escape characters. But nothing works. So, how to make ansible execute the my docker command on each host?

PS I want to list containers that ain't controlled by k8s


Solution

  • You have several problems with your task:

    1. you are using the command module with shell syntax (pipelining multiple commands)

      The error in this case:

      unknown shorthand flag: 'v' in -v See 'docker ps --help'.

      As you can see, the pipe is ignored and the -v parameter is passed to the Docker command.

    2. double curly braces in a string. Double curly braces are interpreted as Jinja2 syntax in Ansible and attempts to templatize.

      The error in this case:

      template error while templating string: unexpected '.'.

    Solution for problem 1

    • You can use the shell module, here you can execute all commands that are possible in a shell.

    • Alternatively, you can simply execute the Docker command with the command module and filter the resulting data in Ansible.

    See below for examples.

    Solution for problem 2

    • Define the curly brackets as variables and insert them at the appropriate place.

      - name: check docker
        command:
          cmd: "docker ps --format '{{ cbo }} .Names {{ cbc }}' -a"
        vars:
          cbo: "{{ '{{' }}"  # curly braces open
          cbc: "{{ '}}' }}"  # curly braces close
        register: doc
      
    • You can define the entire string as raw string with marker !unsafe. Then it is not templated by Ansible with Jinja2, but then you can't templatize other variables in this string.

      - name: check docker
        command:
          cmd: !unsafe "docker ps --format '{{.Names}}' -a"
        register: doc
      

    Final resulting task

    • using command module, filter data in Ansible and !unsafe marker

      - name: check docker
        command:
          cmd: !unsafe "docker ps --format '{{.Names}}' -a"
        register: doc
      
      - name: filter docker container names
        set_fact:
          container_names: "{{ doc.stdout_lines | reject('match', '^k8s') }}"
      
      - debug: var=container_names
      

      With the reject filter, all list elements that match ^k8s are discarded.

    • using shell module and !unsafe marker

      - name: check docker
        shell:
          cmd: !unsafe "docker ps --format '{{.Names}}' -a | egrep -v '^k8s.*$'"
        register: doc
      
      - debug: var=doc.stdout_lines