Y.H
Y.H

Reputation: 51

How to add a string into an dictionary in Ansible with some conditions

I have a problem in my playbook, actually I want to do a ping test on some Windows hosts and I want to send the result via Slack. I have done all of this now the problem is the message that I want to send is just the list of what is ok and what's not.

This is the role of the ping :

---
- name: get powershell version
  ignore_unreachable: true
  raw: $PSVersionTable
- name: ping
  ignore_unreachable: true
  win_ping:
  register: ping_results

just to have a vision this is the ping_results output :

ok: [frsv000003.local.cloud.com] => {
    "msg": {
        "changed": false, 
        "failed": false, 
        "ping": "pong"
    }
}
ok: [frsv000023.local.cloud.com] => {
    "msg": {
        "changed": false, 
        "failed": false, 
        "ping": "pong"
    }
}
ok: [besv000075.local.cloud.com] => {
    "msg": {
        "changed": false, 
        "msg": "psrp connection failure during runspace open: Received a broken RunspacePoolState message: Requested registry access is not allowed.", 
        "skip_reason": "Host besv000075.local.cloud.com is unreachable", 
        "unreachable": true
    }
}
ok: [frsv000007.local.cloud.com] => {
    "msg": {
        "changed": false, 
        "msg": "psrp connection failure during runspace open: Received a WSManFault message. (Code: 2150858811, Machine: 172.9.1.xxx, Reason: The WS-Management service cannot process the request. The resource URI (http://schemas.microsoft.com/powershell/Microsoft.PowerShell) was not found in the WS-Management catalog. The catalog contains the metadata that describes resources, or logical endpoints.)", 
        "skip_reason": "Host frsv000007.local.cloud.com is unreachable", 
        "unreachable": true
    }
}

Now for the message to send for slack, I have created a condition to put hosts that are ok and non ok in two different lists

- name: set fact
  set_fact:
    ok_list: []
- name: set fact2  
  set_fact:
    ok_list: "{{ ok_list + [item.value] }}"
  when: item.value is match('pong')
  with_dict: "{{ ping_results }}"
- name: set fact
  set_fact:
    nok_list: []
- name: set fact2  
  set_fact:
    nok_list: "{{ nok_list + [item.value] }}"
  when:
   - item.value is not match('pong')
  with_items: "{{ ping_results | dict2items }}"

The problem I got is this :

TASK [Hello-windows : Print variable ok] ***************************************
ok: [frsv000003.local.cloud.com] => {
    "msg": [
        "pong"
    ]
}
ok: [frsv000023.local.cloud.com] => {
    "msg": [
        "pong"
    ]
}
ok: [besv000075.local.cloud.com] => {
    "msg": []
}
ok: [frsv000007.local.cloud.com] => {
    "msg": []
}

I need to get only hostname to print it in Slack the problem is how to get these hosts from one list and without the empty values. Thanks.

Edited Part : @larsks i will put this as a answer the inventory is based on ansible tower contains a lot of hosts like the first example :

  frsv000003.local.cloud.com
  frsv000004.local.cloud.com
  frsv000005.local.cloud.com
  frsv000006.local.cloud.com
  frsv000007.local.cloud.com
  frsv000008.local.cloud.com
  frsv000009.local.cloud.com
  frsv000010.local.cloud.com
 ...

For the playbook i use a role so the main file for the role is the same as you

- name: set ok_list
  set_fact:
    ok_list: "{{ ok_list + [item] }}"
  when: hostvars[item].ping_results.ping|default('') == "pong"
  loop: "{{ groups.all }}"

- name: set nok_list
  set_fact:
    nok_list: "{{ nok_list + [item] }}"
  when: hostvars[item].ping_results.ping|default('') != "pong"
  loop: "{{ groups.all }}"

- debug:
    msg:
      - "ok_list: {{ ok_list }}"
      - "nok_list: {{ nok_list }}"

and also for the main file (not the role) i have this :

- name: Test windows Connectivity
  hosts: all
  gather_facts: no
  vars:
    ping_results:
    slack_msg:
    ok_list: []
    nok_list: []
  roles:
    - Hello-windows

So when i run the job using jobtemplate with 5 hosts the problem is that i got a list like this means that the nok list contains all hosts :

TASK [Hello-windows : debug] ***************************************************
ok: [frsv000003.local.cloud.com] => {
    "msg": [
        "ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']", 
        "nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
    ]
}
ok: [frsv000023.local.cloud.com] => {
    "msg": [
        "ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']", 
        "nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
    ]
}
ok: [besv000075.local.cloud.com] => {
    "msg": [
        "ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']", 
        "nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
    ]
}
ok: [frsv000007.local.cloud.com] => {
    "msg": [
        "ok_list: [u'frsv000003.local.cloud.com', u'frsv000023.local.cloud.com']", 
        "nok_list: [u'frsv005207.local.cloud.com', u'frsv005336.local.cloud.com', u'uksv000232.local.cloud.com', u'frsv001871.local.cloud.com', u'frsv005090.local.cloud.com', u'frsv005333.local.cloud.com', u'frsv002043.local.cloud.com', u'frsv001811.local.cloud.com', u'frsv005150.local.cloud.com', u'frsv000928.local.cloud.com', u'frsv005529.local.cloud.com', u'frsv001606.local.cloud.com', u'frsv000236.local.cloud.com', u'frsv000929.local.cloud.com', u'frsv000363.local.cloud.com', u'frsv000539.local.cloud.com', u'frsv000653.local.cloud.com', u'frsv000508.local.cloud.com', u'frsv000654.local.cloud.com', u'frsv000205.local.cloud.com', u'frsv000632.local.cloud.com', u'frsv000516.local.cloud.com', u'frsv000427.local.cloud.com', u'frsv000137.local.cloud.com', u'frsv000466.local.cloud.com', u'frsv000324.local.cloud.com', u'frsv000974.local.cloud.com', u'frsv001451.local.cloud.com', u'frsv005432.local.cloud.com', u'besv005627.local.cloud.com',
    ]
}

PLAY RECAP *********************************************************************
besv000075.local.cloud.com : ok=3    changed=0    unreachable=1    failed=0    skipped=1    rescued=0    ignored=0   
frsv000003.local.cloud.com : ok=10   changed=1    unreachable=0    failed=0    skipped=10   rescued=0    ignored=0   
frsv000007.local.cloud.com : ok=3    changed=0    unreachable=1    failed=0    skipped=1    rescued=0    ignored=0   
frsv000023.local.cloud.com : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

Upvotes: 0

Views: 482

Answers (1)

larsks
larsks

Reputation: 311606

Your problem is that ping_results isn't a list of results; it's a single result for a single host. When you run:

- name: ping
  ignore_unreachable: true
  win_ping:
  register: ping_results

This runs once on each host, and registers a variable named ping_results for that host. You can see that in your debug output.

To get two lists, one of hosts that were reachable and one of hosts that were not, you would need a play that runs on a single host (e.g., localhost) and loops over all the target hosts to look up the ping_results variable. For example:

- hosts: localhost
  gather_facts: false
  tasks:
    - name: set ok_list
      set_fact:
        ok_list: "{{ ok_list + [item] }}"
      when: hostvars[item].ping_results.ping|default('') == "pong"
      vars:
        ok_list: []
      loop: "{{ groups.all }}"

    - name: set nok_list
      set_fact:
        nok_list: "{{ nok_list + [item] }}"
      when: hostvars[item].ping_results.ping|default('') != "pong"
      vars:
        nok_list: []
      loop: "{{ groups.all }}"

    - debug:
        msg:
          - "ok_list: {{ ok_list }}"
          - "nok_list: {{ nok_list }}"

Running this with your sample data produces the following out:

PLAY [localhost] ***************************************************************

TASK [set ok_list] *************************************************************
ok: [localhost] => (item=frsv000003.local.cloud.com)
ok: [localhost] => (item=frsv000023.local.cloud.com)
skipping: [localhost] => (item=besv000075.local.cloud.com) 
skipping: [localhost] => (item=frsv000007.local.cloud.com) 

TASK [set nok_list] ************************************************************
skipping: [localhost] => (item=frsv000003.local.cloud.com) 
skipping: [localhost] => (item=frsv000023.local.cloud.com) 
ok: [localhost] => (item=besv000075.local.cloud.com)
ok: [localhost] => (item=frsv000007.local.cloud.com)

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": [
        "ok_list: ['frsv000003.local.cloud.com', 'frsv000023.local.cloud.com']",
        "nok_list: ['besv000075.local.cloud.com', 'frsv000007.local.cloud.com']"
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

And I think that's what you're looking for.


NB: I tested the above playbook using this inventory file in hosts.yml:

all:
  hosts:
    frsv000003.local.cloud.com:
      ansible_host: localhost
      ping_results:
        changed: false
        failed: false
        ping: pong
    frsv000023.local.cloud.com:
      ansible_host: localhost
      ping_results:
        changed: false
        failed: false
        ping: pong
    besv000075.local.cloud.com:
      ansible_host: localhost
      ping_results:
        changed: false
        msg: "psrp connection failure during runspace open: Received a broken RunspacePoolState message: Requested registry access is not allowed."
        skip_reason: "Host besv000075.local.cloud.com is unreachable"
        unreachable: true
    frsv000007.local.cloud.com:
      ansible_host: localhost
      ping_results:
        changed: false
        msg: "psrp connection failure during runspace open: Received a WSManFault message. (Code: 2150858811, Machine: 172.9.1.xxx, Reason: The WS-Management service cannot process the request. The resource URI (http://schemas.microsoft.com/powershell/Microsoft.PowerShell) was not found in the WS-Management catalog. The catalog contains the metadata that describes resources, or logical endpoints.)"
        skip_reason: "Host frsv000007.local.cloud.com is unreachable"
        unreachable: true

Running it like this:

ansible-playbook -i hosts.yml playbook.yml

Upvotes: 1

Related Questions