Run a task only when registered output (which is a list) has changed

Viewed 82

I am running the below task which registers the output to a status variable, which is a list.

- name: Check status before client set up
  shell: |
    curl -k -s -S -i -u logstash:logstash 'https://localhost:5665/v1/status?pretty=1'| jq  .results[0].status.api.zones.master.endpoints[0]
  register: status
- debug:
    var: status.stdout_lines 

Which outputs:

[
  "stage-master-icinga.int.cloud.ruckuswireless.com",
  "stage-master2-icinga.int.cloud.ruckuswireless.com"
]

Now I have the following task to run, conditionally, if the output of the above task doesn't contain the items stage-master-icinga.int.cloud.ruckuswireless.com and stage-master2-icinga.int.cloud.ruckuswireless.com, or, in other words, run the task only when the output has changed.

I tried the find module, but list wouldn't allow it.

Here is the taks with the condition for a better picture:

- name: Setup client
  shell: |
    icinga2 node setup --ticket {{ticket.stdout}} \
    --cn {{agent_fqdn}} \
    --endpoint {{groups.icinga_primary_master[0]}} \
    --zone master \
    --parent_zone master \
    --parent_host {{master_ip}} \
    --trustedcert {{icinga_certs_dir}}{{icinga_master_cert_file}} \
    --accept-config \
    --disable-confd
  register: setup
  when: ???
  ##     ^-- Which condition can I use here? 

Full debug output:

ok: [stage-master2-icinga.int.cloud.ruckuswireless.com] => {
    "status.stdout_lines": [
        "[",
        "  \"stage-master-icinga.int.cloud.ruckuswireless.com\",",
        "  \"stage-master2-icinga.int.cloud.ruckuswireless.com\"",
        "]"
    ]
}
 Updated debug output:
    
    2022-08-04 16:14:00  TASK [icinga : debug] **********************************************************
    2022-08-04 16:14:00  An exception occurred during task execution. To see the full traceback, use -vvv. The error was: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    2022-08-04 16:14:00  fatal: [stage-master2-icinga.int.cloud.ruckuswireless.com]: FAILED! => {"msg": "Unexpected failure during module execution."}
    2022-08-04 16:14:00  

code:

- name: Check status before client set up
  shell: |
    curl -k -s -S  -u logstash:logstash 'https://localhost:5665/v1/status?pretty=1' | jq  .results[0].status.api.zones.master.endpoints
  register: status
- debug:
    var: status.stdout | from_json

Condition:

  when: >-
    status.stdout | from_json | difference([
      "stage-master-icinga.int.cloud.ruckuswireless.com",
      "stage-master2-icinga.int.cloud.ruckuswireless.com",
    ]) | length > 0
1 Answers

Before doing anything, you have to realise that you do have a string representation of a JSON array, not a JSON array.

So, in order to get a list, like you claim you have in your question, you should use:

status.stdout | from_json

and not

status.stdout_lines

There are two cases here:

  1. you want to act if the items in the list are the different, but also if they come in a different order, then you can run a simple comparison of the lists
    when: >-
      status.stdout | from_json != [
        "stage-master-icinga.int.cloud.ruckuswireless.com",
        "stage-master2-icinga.int.cloud.ruckuswireless.com",
      ]
    
  2. you only want to act if there are new elements or elements removed from the list, regardless of the positions of the elements, then you can use the difference filter
    when: >-
      status.stdout | from_json | difference([
        "stage-master-icinga.int.cloud.ruckuswireless.com",
        "stage-master2-icinga.int.cloud.ruckuswireless.com",
      ]) | length > 0
    

For further reference, the usage of >- is a YAML multiline construction.
See:

Related