Search code examples
ansiblejinja2ansible-2.x

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


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


Solution

  • 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 }}"