【问题标题】:How to add a string into an dictionary in Ansible with some conditions如何在某些条件下将字符串添加到 Ansible 中的字典中
【发布时间】:2021-09-09 21:13:47
【问题描述】:

我的剧本有问题,实际上我想在一些 Windows 主机上进行 ping 测试,我想通过 Slack 发送结果。我现在已经完成了所有这些,问题是我要发送的消息只是可以和不可以的列表。

这是ping的作用:

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

只是有一个愿景,这是 ping_results 输出:

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

现在为了发送 slack 消息,我创建了一个条件,将正常和不正常的主机放在两个不同的列表中

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

我遇到的问题是这样的:

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": []
}

我只需要获取主机名即可在 Slack 中打印它,问题是如何从一个列表中获取这些主机并且没有空值。谢谢。

编辑部分: @larsks 我将此作为答案,库存基于 ansible 塔包含很多主机,如第一个示例:

  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
 ...

对于剧本,我使用一个角色,因此该角色的主文件与您相同

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

对于主文件(不是角色)我也有这个:

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

所以当我使用带有 5 个主机的 jobtemplate 运行作业时,问题是我得到了一个这样的列表,这意味着 nok 列表包含所有主机:

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  

【问题讨论】:

    标签: ansible


    【解决方案1】:

    您的问题是ping_results 不是结果列表;这是单个主机的单个结果。运行时:

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

    这在每个主机上运行一次,并注册一个名为 ping_results 为该主机。您可以在调试输出中看到这一点。

    要获取两个列表,一个是可访问的主机,另一个是主机 那不是,你需要一个在单个主机上运行的游戏(例如, localhost) 并遍历所有目标主机以查找 ping_results 变量。例如:

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

    使用您的示例数据运行此程序会产生以下结果:

    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   
    

    我认为这就是你要找的。​​p>


    注意:我在 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
    

    像这样运行它:

    ansible-playbook -i hosts.yml playbook.yml
    

    【讨论】:

    • 你好@larsks,我想你明白了我的想法,这就是我一直在寻找的,但是当我尝试获取 nok 主机时出现问题我从库存中获取所有列表而不是限制让我给你看。我用了和你一样的代码。
    • 任务 [Hello-windows : set ok_list] 跳过:[frsv000003.local.cloud.com] => (item=frsv005207.local.cloud.com) 跳过:[frsv000003.local.cloud. com] => (item=frsv005336.local.cloud.com) 跳过:[frsv000003.local.cloud.com] => (item=uksv000232.local.cloud.com) 跳过:[frsv000003.local.cloud.com] => (item=frsv001871.local.cloud.com)
    • 我有 4 台主机在限制中,我得到了 2 台好的主机列表,但对于 nok 列表,我从库存中获得了整个列表
    • 此处提供的示例清单和剧本似乎产生了正确的输出。如果您可以提供一个可运行的剧本和清单来重现您所询问的问题,我会很乐意看一看。
    • 我使用带有简单清单的 ansible Tower,例如我每次使用限制 4/5 个主机
    猜你喜欢
    • 2021-03-12
    • 2021-11-29
    • 1970-01-01
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    相关资源
    最近更新 更多