0

Essentially, I am trying to use the when conditional to decide whether to proceed running a command based on the presence of a string. There seem to be all sorts of problems to overcome here, including the presence of the colon which I can't escape with "{{:}}" like I normally would because then the conditional complains.

If i truncate everything from the point of the colon and after, I get an integer evaluation error instead. I've looked through 200 posts on stackoverflow and none of the solutions seem to be able to do what I'm looking for.

Relvevant part of the sync_status.stderr_lines contents I am looking for if it comes up:

ERROR 1227 (42000) at line 1: Access denied

The code in the task which tries to run the command if the string is present with the colon:

     - name: Can we proceed?
       command: uptime
       when: ( 'ERROR 1227 (42000) at line 1"{{:}}" Access denied' in sync_status.stderr_lines )

This task's error during runtime:

fatal: [server1]: FAILED! => {"msg": "The conditional check '( 'ERROR 1227 (42000) at line 1\"{{:}}\" Access denied' in sync_status.stderr_lines )' failed. The error was: template error while templating string: unexpected ':'. String: ( 'ERROR 1227 (42000) at line 1\"{{:}}\" Access denied' in sync_status.stderr_lines )\n\nThe error appears to be in '/home/ansible/ssn-project/playbooks/i_mux-sql-upgrade.yml': line 54, column 8, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n     - name: Can we proceed?\n       ^ here\n"}

Now the "same" thing truncated:

     - name: Can we proceed?
       command: uptime
       when: ( 'ERROR 1227 (42000) at line 1' in sync_status.stderr_lines )

And it's runtime failure as well:

fatal: [mux-ds1]: FAILED! => {"msg": "The conditional check '( 'ERROR 1227 (42000) at line 1' in sync_status.stderr_lines )' failed. The error was: error while evaluating conditional (( 'ERROR 1227 (42000) at line 1' in sync_status.stderr_lines )): Unable to look up a name or access an attribute in template string ({% if ( 'ERROR 1227 (42000) at line 1' in sync_status.stderr_lines ) %} True {% else %} False {% endif %}).\nMake sure your variable name does not contain invalid characters like '-': argument of type 'AnsibleUndefined' is not iterable\n\nThe error appears to be in '/home/ansible/ssn-project/playbooks/i_mux-sql-upgrade.yml': line 54, column 8, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n     - name: Can we proceed?\n       ^ here\n"}

Is there a way to make this work as I expect? I was maybe thinking of some sort of regex filter, but maybe that's not the right way to go. Insights would be appreciated. Note, I am on ansible version 2.9

U880D
  • 8,601
  • 6
  • 24
  • 40
Viscosity
  • 311
  • 1
  • 2
  • 14
  • 1
    There's a lot going on here, but as for your `{{:}}` problem, just [fold the yaml scalar](https://yaml.org/spec/1.2.1/#id2779048) and save yourself the heartache: `when: >-`; the last one is pretty straightforward, is it not? `AnsibleUndefined' is not iterable` means `.stderr_lines` is undefined – mdaniel Sep 02 '22 at 19:15
  • 3
    This is a YAML string issue, nothing more, indeed, you don't have to escape a colon, just put the string in quotes: `when: "'ERROR 1227 (42000) at line 1: Access denied' in sync_status.stderr_lines"` – β.εηοιτ.βε Sep 02 '22 at 19:27
  • Thanks to both of you, this was bothering me for a while! The scalar folding solved a lot of issues I had extensive workarounds for even further back in the playbook. The quoted string I actually hit upon, but abandoned it due to the colon issue. Either way, both suggestions combined were helpful and the answer, thanks you two. – Viscosity Sep 03 '22 at 19:25

1 Answers1

1

I understand that you like to

"run ... a command based on the presence of a string"

on a not further specified STDERR output

ERROR 1227 (42000) at line 1: Access denied

Regarding

Relvevant part of the sync_status.stderr_lines contents I am looking for if it comes up

it seems for me that the Most Significant Information is less than the whole line and only ERROR 1227 and/or Access denied since the information/message is an ERROR 1227 42000 Access denied.

Therefore you can simplify your case as shown in the following example

---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    sync_status:
      stderr_lines:
        - 'line 1: Line 1'
        - 'ERROR 1227 (42000) at line 1: Access denied'
        - 'line 2: Line 2'

  tasks:

  # Show all STDERR lines joined into one line

  - name: Show vars
    debug:
      msg: "{{ sync_status.stderr_lines | join(' ') }}"

  # Looking for most significant information only

  - name: Can we proceed?
    debug:
      msg: "No!"
    when: "sync_status.stderr_lines | join(' ') is search('ERROR 1227|Access denied')"

resulting into an output of

TASK [Show vars] *****************************************************************
ok: [localhost] =>
  msg: 'line 1: Line 1 ERROR 1227 (42000) at line 1: Access denied line 2: Line 2'

TASK [Can we proceed?] ***********************************************************
ok: [localhost] =>
  msg: No!

As already mentioned in a comment of β.εηοιτ.βε, you could also just lookup the whole line.

  - name: Can we proceed?
    debug:
      msg: "No!"
    when: "'ERROR 1227 (42000) at line 1: Access denied' in sync_status.stderr_lines"

Further Q&A

Documentation

U880D
  • 8,601
  • 6
  • 24
  • 40
  • This is a more detailed version of the answer, I also implemented the scalar folding to deal with the colon in the single line solution, but yours is probably the more "modern" way to deal with it. – Viscosity Sep 13 '22 at 01:55