0

I'm trying to figure out a port test task in a playbook. I have two different sets of ports that need to be checked, but only checked if the server hostname has dev/test/stg/eng in it. Then everything else will be considered a production host and the production ports will be checked.

Here is my playbook:

- name: Filebeat Firewall port check | Dev
  wait_for:
    host: "{{ item.name }}"
    port: "{{ item.port }}"
    state: started
    delay: 0
    timeout: 5
  loop: "{{ dev_ports }}"
  register: devresults
  when: ansible_facts['hostname'] | regex_search('dev|tst|test|eng')

- name: Filebeat Firewall port check | Prod
  wait_for:
    host: "{{ item.name }}"
    port: "{{ item.port }}"
    state: started
    delay: 0
    timeout: 5
  loop: "{{ prod_ports }}"
  when: devresults is skipped

The first task runs as expected when ran against a production server (is skipped) and a development server (ports are checked). However, the second task is skipped when ran against a production server, as well as a development server (this should happen).

Basically, if the first task is skipped the second task should run, and if the first ran the second task should be skipped, this isn't happening. I'm not sure what I'm missing, I'm thinking its the when statement in the second task, or if the loop is causing my issue, any help would be welcomed.

U880D
  • 8,601
  • 6
  • 24
  • 40
d1530
  • 151
  • 8

1 Answers1

0

Regarding your question

Basically, if the first task is skipped the second task should run, and if the first ran the second task should be skipped, this isn't happening.

I've setup a short first example

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

  tasks:

  - name: Create result set
    shell:
      cmd: echo 'I am not skipped.'
    register: result
    when: not ansible_check_mode

  - name: Show result when not skipped
    debug:
      var: result
    when: not result.skipped | default('false') | bool

  - name: Show result when skipped
    debug:
      var: result
    when: result.skipped | default('false') | bool

and found it working when running with ansible-playbook skip.yml and ansible-playbook skip.yml --check.

Depending on the task and used modules, the reason seems to be when a task becomes skipped the result set is

TASK [Show result when skipped] **************************
ok: [localhost] =>
  result:
    changed: false
    skip_reason: Conditional result was False
    skipped: true

whereby when not skipped the result set is

TASK [Show result when not skipped] *********************
ok: [localhost] =>
  result:
    changed: true
    cmd: echo 'I am not skipped.'
    delta: '0:00:00.123456'
    end: '2022-02-16 20:00:00.123456'
    failed: false
    rc: 0
    start: '2022-02-16 20:00:00.000000'
    stderr: ''
    stderr_lines: []
    stdout: I am not skipped.
    stdout_lines:
    - I am not skipped.

and don't has the skipped flag. Therefore you may introduce filter to Provide default values and to Force the data type.


Regarding your objection

"the example doesn't really applies as it isn't doing any loops"

you may have a look into the result set of the following second example with loop and Extended loop variables.

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

  tasks:

  - name: Create result set
    shell:
      cmd: echo 'I am not skipped.'
    register: result
    when: item is even
    loop: "{{ [1,2] }}"
    loop_control:
      extended: true
      label: "{{ item }}"

  - name: Show result
    debug:
      var: result

which produce an output of

TASK [Create result set] *******
changed: [localhost] => (item=2)

TASK [Show result] ******************************
ok: [localhost] =>
  result:
    changed: true
    msg: All items completed
    results:
    - ansible_loop:
        allitems:
        - 1
        - 2
        first: true
        index: 1
        index0: 0
        last: false
        length: 2
        nextitem: 2
        revindex: 2
        revindex0: 1
      ansible_loop_var: item
      changed: false
      item: 1
      skip_reason: Conditional result was False
      skipped: true
    - ansible_loop:
        allitems:
        - 1
        - 2
        first: false
        index: 2
        index0: 1
        last: true
        length: 2
        previtem: 1
        revindex: 1
        revindex0: 0
      ansible_loop_var: item
      changed: true
      cmd: echo 'I am not skipped.'
      delta: '0:00:00.123456'
      end: '2022-02-16 22:15:00.123456'
      failed: false
      invocation:
        module_args:
          _raw_params: echo 'I am not skipped.'
          _uses_shell: true
          argv: null
          chdir: null
          creates: null
          executable: null
          removes: null
          stdin: null
          stdin_add_newline: true
          strip_empty_ends: true
          warn: true
      item: 2
      rc: 0
      start: '2022-02-16 22:15:00.000000'
      stderr: ''
      stderr_lines: []
      stdout: I am not skipped.
      stdout_lines:
      - I am not skipped.

As you can see it is a data structure containing a list of items and it does contain the information about the first skipped item. To access it you may enhance the second example with

  - name: Show result when skipped
    debug:
      msg: "{{ item.item }}"
    when: item.skipped | default('false') | bool
    loop: "{{ result.results }}"
    loop_control:
      extended: true
      label: "{{ item }}"

and have a look into the output. It also works according the examples of Conditions based on registered variables.

  - name: Show result when skipped
    debug:
      msg: "{{ item.item }}"
    when: item is skipped
    loop: "{{ result.results }}"

Further Reading

U880D
  • 8,601
  • 6
  • 24
  • 40
  • When I attempt this suggestion in my code. I get the following error when running against the prod ports: `The conditional check 'not devresults.skipped' failed. The error was: error while evaluating conditional (not devresults.skipped): 'dict object' has no attribute 'skipped'` – d1530 Feb 16 '22 at 20:07
  • Right, that why I have a filter set `not result.skipped | default('false') | bool`. You may have a look into the provided minimal example, let it run, debug the variables and see how the result set is changing under different conditions. You could also introduce debug statements into your playbook and see how the result set looks like. – U880D Feb 16 '22 at 20:10
  • When I debug the `devresults.skipped` variable after the first task, this returns `VARIABLE IS NOT DEFINED!` this makes it seems like I cannot use skipped in my variables. – d1530 Feb 16 '22 at 20:17
  • As the small test shows you can use `skipped`, in example if you set a filter `| default('false') | bool` and define it to false if it is not defined. I've extended the small test for both cases. The debug options will now show if the initial task was skipped or not. – U880D Feb 16 '22 at 20:28
  • right but I'm still not getting the results I want. When I run the playbook against a development server it's running both tasks, where it should only be running the first task. Then this working correctly when ran against a production server, skipping the first task and running the second. Each time I ran the playbook I'm still seeing the `devresults.skipped` variable as not defined. Plus the example isn't really apples to apples since the example isn't doing any loops – d1530 Feb 16 '22 at 20:42
  • According your comment "_Then this working correctly when ran against a production server, skipping the first task and running the second._" I understand that the approach is working for `prod` servers, since your when clause contains only `dev`, `test`, `stage`, `eng`, etc. – U880D Feb 16 '22 at 20:49