在 Ansible 剧本中使用 parse_xml

Using parse_xml in an Ansible playbook

我一直在尝试在 Ansible 中解析 XML 数据。我可以使用 xml 模块让它工作,但我认为使用 parse_xml 更适合我的需要。

我似乎无法将 xml 中的任何数据与我的规格文件相匹配。

这是 xml 数据:

 <data xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">
  <ntp xmlns=\"http://cisco.com/ns/yang/Cisco-IOS-XR-ip-ntp-oper\">
   <nodes>
    <node>
     <node>0/0/CPU0</node>
     <associations>
      <is-ntp-enabled>true</is-ntp-enabled>
      <sys-leap>ntp-leap-no-warning</sys-leap>
      <peer-summary-info>
       <peer-info-common>
        <host-mode>ntp-mode-client</host-mode>
        <is-configured>true</is-configured>
        <address>10.1.1.1</address>
        <reachability>0</reachability>
       </peer-info-common>
       <time-since>-1</time-since>
      </peer-summary-info>
      <peer-summary-info>
       <peer-info-common>
        <host-mode>ntp-mode-client</host-mode>
        <is-configured>true</is-configured>
        <address>172.16.252.29</address>
        <reachability>255</reachability>
       </peer-info-common>
       <time-since>991</time-since>
      </peer-summary-info>
     </associations>
    </node>
   </nodes>
  </ntp>
 </data>

规范文件如下所示:

---
vars:
  ntp_peers:
    address: "{{ item.address }}"
    reachability: "{{ item.reachability}}"
keys:
  result:
    value: "{{ ntp_peers }}"
    top: data/ntp/nodes/node/associations
    items:
      address: peer-summary-info/peer-info-common/address
      reachability: peer-summary-info/peer-info-common/reachability

和 yaml 文件中的任务:

  - name: parse ntp reply
    set_fact:
      parsed_ntp_data: "{{ NTP_STATUS.stdout | parse_xml('specs/iosxr_ntp.yaml') }}"

但数据没有return任何结果:

TASK [debug parsed_ntp_data] **************************************************************************************************************************************************************************
ok: [core-rtr01] => {
    "parsed_ntp_data": {
        "result": []
    }
}
ok: [dist-rtr01] => {
    "parsed_ntp_data": {
        "result": []
    }
}

我以前从未见过parse_xml,所以这是一次有趣的冒险

似乎有两件事对您不利:top: 密钥是从根元素 计算的 ,以及您的 XML(与其他元素不同示例)使用 XML 命名空间(xmlns= 位),这意味着您的 XPath 必须以 Element.findall 方式编码

对于第一部分,由于 Element.findall<data> 元素上是 运行,这意味着不能在 XPath 中引用 data/...,因为那将是适用于结构 <data><data>。我试图通过使 XPath 绝对 /data/... 来偷偷摸摸,但是 Python 的 XPath 库在那种情况下抛出。所以,至少你的 top: 键不能以 data 任何东西开头

然后,你的代码片段中的 xmlns= 对我来说很突出,因为这意味着这些元素的名称实际上是每个元素的 NS+":"+localName,因此 ntp 的 XPath 不匹配ns0:ntp 因为它们被认为是完全独立的名称(毕竟这是命名空间的重点)。很可能使用足够的 //*[localname() = "ntp"] 愚蠢来避免必须一遍又一遍地指定名称空间,但我没有尝试

同样,作为对 Python 的 XPath 库的让步,他们将 xpath 中的完全限定名称编码为 {the-namespace}local-name 并且除了修改 network.py 传递命名空间:-(

因此,我用来证实我的理论的“hello world”版本:

vars:
  ntp_peers:
    address: "{{ item.address }}"
keys:
  result:
    value: "{{ ntp_peers }}"
    top: '{http://cisco.com/ns/yang/Cisco-IOS-XR-ip-ntp-oper}ntp/{http://cisco.com/ns/yang/Cisco-IOS-XR-ip-ntp-oper}nodes/{http://cisco.com/ns/yang/Cisco-IOS-XR-ip-ntp-oper}node'
    items:
      address: '{http://cisco.com/ns/yang/Cisco-IOS-XR-ip-ntp-oper}node'

开开心心制作

ok: [localhost] => {
    "msg": {
        "result": [
            {
                "address": "0/0/CPU0"
            }
        ]
    }
}