0

Under my Playbook , i want to run a shell command which is the following :

for STACK in stackone  stacktwo;do  docker stack ps  --format "table {{.ID}}\t{{.Name}}\t{{.CurrentState}}\t{{.Error}}\t{{.Node}}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); done; 

As you can see my shell command is quite complex , so when i am running it like this , it fails throwing always syntax errors

 - name : Check running services
   shell: for STACK in stackone    srcd-pilote;do  docker stack ps  --format "table {{.ID}}\t{{.Name}}\t{{.CurrentState}}\t{{.Error}}\t{{.Node}}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); done; 
   register: result

I see there is many characters which need to be passed as strings such as {{.Name}} and |grep ...

So i ve tried this :

- name : Check running services
  shell: "for STACK in srcd-current  stacktwo;do  docker stack ps  --format 'table {{'"{{.ID}}"'}}\t{{'"{{.Name}}"'}}\t{{'"{{.CurrentState}}"'}}\t{{'"{{.Error}}"'}}\t{{'"{{.Node}}"'}}' $STACK | (read -r; printf '%s\n' '$REPLY'; sort -k 2'"{{|}}"'grep srcd '"{{|}}"'grep -v Shutdown ); done; "
  register: result

But it stills failing .

Suggesstions ??

firasKoubaa
  • 6,439
  • 25
  • 79
  • 148

1 Answers1

1

I had to use a shell for loop in one of my ansible tasks. I use a Literal Block Scalar '|' to do so. Try something like this:

- name : Check running services
  shell: |
    for STACK in stackone srcd-pilote;do
      docker stack ps  --format "table {{ '{{' }}.ID{{ '}}' }}\t{{ '{{' }}.Name{{ '}}' }}\t{{ '{{' }}.CurrentState{{ '}}' }}\t{{ '{{' }}.Error{{ '}}' }}\t{{ '{{' }}.Node{{ '}}' }}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); 
    done;

More doc on the scalar can be found on the Ansible doc about YAML syntax.

You should also escape the {{ and }} from the jinja2, by using {{ '{{' }} and {{ '}}' }}.

Note 1: Here is a nice sed command to do so:

s/{{\([^}]*\)}}/{{ '{{' }}\1{{ '}}' }}/g

Note 2: You should review the command to split it in several lines to improve the readability (with \ at the end of line or using the > scalar).

Ansible-Lint rules recommend line shorter than 160 characters (rule E204).

xenlo
  • 761
  • 1
  • 7
  • 21
  • i still ve problemes with special chara {{ }} and | which i should pass to shell and doesn't have to be translated by ansible – firasKoubaa Aug 19 '19 at 12:58
  • docker stack ps --format "table {{.ID}}\t{{.Name}}\t{{.CurrentState}}\t{{.Error}}\t{{.Node}}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); -> should be interpreted by shell not by ansible – firasKoubaa Aug 19 '19 at 13:02
  • FWIW (Step by step). 1) Write the script and test it in the remote. 2) Create [template](https://docs.ansible.com/ansible/latest/modules/template_module.html) to customize the script in the master 3) Make sure the script, created by the template, is what you want. 4) copy the script to remote 5) run the script. – Vladimir Botka Aug 19 '19 at 13:12
  • Ah Ok I get it. So you need to escape the `{{` and `}}` from the jinja2 expression. I will edit my code in the answer. – xenlo Aug 19 '19 at 13:24
  • @xenlo and also the | , to summarize i want to escape all special charaters of second line (docker stack ps ... ) – firasKoubaa Aug 19 '19 at 13:29
  • The pipe is not interpreted by the jinja2. I tested it inside an echo as I don't have docker infra in place to run the commands… `echo "docker stack ps --format \"table {{ '{{' }}.ID{{ '}}' }}\t{{ '{{' }}.Name{{ '}}' }}… $STACK | (read -r; printf \"%s\n\" \"$REPLY\"; sort -k 2|grep srcd |grep -v Shutdown );" >> /tmp/test.out`. So you should investigate into shell escaping stuff… – xenlo Aug 19 '19 at 13:34