Ansible resolving logical comparison `1 < 1` to true in a loop item test despite filtering/casting to int

49 Views Asked by At

I'm running a play against a number of servers where the first task performs a sql query to get the schema version for a database. The query returns "1" (string) for instance when the schema version is 1. This is the structure of the response...

ok: [server.tld] => {
    "db_result": {
        "changed": false,
        "executed_queries": [
            "SELECT `value` FROM `registry` WHERE `setting` = 'schema_version'"
        ],
        "failed": false,
        "query_result": [
            [
                {
                    "value": "1"
                }
            ]
        ],
        "rowcount": [
            1
        ]
    }
}

In the next task I test to see if the schema version returned is less than the current version... in this case also 1 (int) but after a future upgrade we would test against 2 (int) which would cause all servers to run the patch that still return 1. I use the Jinja filter | int to cast to integer for a proper comparison.

  - name: Copy schema update SQL file
    copy: src=roles/db/files/{{ item.src }} dest=/tmp/{{ item.src }}
    when: item.when
    loop:
      - src: schema_changes_v1.sql 
        when: "{{ db_result.query_result[0][0]['value'] | int }} < 1"

The problem is that even though the logical comparison is when: 1 < 1 which should resolve to false, it's still proceeding with the item in the loop rather than skipping to the next one....

changed: [server.tld] => (item={'src': 'schema_changes_v1.sql', 'when': '1 < 1'})

Why??

Ansible 2.12.2

1

There are 1 best solutions below

4
Alexander Pletnev On BEST ANSWER

The condition in when is evaluated as it's already within the curly braces.

Edited: But I didn't notice the most important thing in your example. The condition you're referring to is set as the value of when key within the loop element - that means that it's evaluated as a string first. And a non-empty string in a real when evaluates to true - that's the reason why you task gets executed each time.

So, simply put the whole string into the curly braces so that you get a boolean instead of a string:

  - name: Copy schema update SQL file
    copy: src=roles/db/files/{{ item.src }} dest=/tmp/{{ item.src }}
    when: item.when
    loop:
      - src: schema_changes_v1.sql 
        when: "{{ db_result.query_result[0][0]['value'] | int < 1 }}"