映射嵌套结构的属性

时间:2016-05-03 10:57:27

标签: ansible jinja2

我有一个嵌套的网络接口结构。

interfaces:
  - name: bond0
    bonding_xmit_hash_policy: layer3+4
    bridge:
      name: br0
      inet: 12.34.56.78/24
    slaves:
      - name: eth0
        mac: xx:xx:xx:xx:xx:xx
      - name: eth1
        mac: xx:xx:xx:xx:xx:xx
      - name: eth2
        mac: xx:xx:xx:xx:xx:xx
      - name: eth3
        mac: xx:xx:xx:xx:xx:xx

我现在想要生成所有已定义接口名称的平面列表:

  • bond0
  • BR0
  • 的eth0
  • eth1的
  • 的eth2
  • ETH3

理论上这应该很简单,但我无法提取从属接口的名称(eth0 - eth3

以下是工作部分:

  1. 根级别的接口列表(本例中为bond0

    interfaces | map(attribute='name') | list
  2. 桥接接口列表

    interfaces | selectattr('bridge', 'mapping') | map(attribute='bridge') | map(attribute='name') | list
  3. 这是我尝试获取所有从属接口名称:

    interfaces | selectattr('slaves') | map(attribute='slaves') | map(attribute='name') | list
    

    简而言之,首先减少接口列表,只获取那些具有slaves属性的接口。然后使用map过滤器获取奴隶。直到这里它起作用,如果我输出结果,它看起来像这样:

    [
        {
            "mac": "xx:xx:xx:xx:xx:xx", 
            "name": "eth0"
        }, 
        {
            "mac": "xx:xx:xx:xx:xx:xx", 
            "name": "eth1"
        }, 
        {
            "mac": "xx:xx:xx:xx:xx:xx", 
            "name": "eth2"
        }, 
        {
            "mac": "xx:xx:xx:xx:xx:xx", 
            "name": "eth3"
        }
    ]
    

    这显然是一个对象列表。这实际上与结构根级别的接口格式相同(bond0)。但是,当我尝试再次使用name获取所有对象的map属性时,它将失败,结果为[Undefined]。 (注意[]。它似乎是未定义的列表,而不仅仅是未定义的)

    但这正是map过滤器应该做的事情:

      

    对一系列对象应用过滤器或查找属性。这在处理对象列表时很有用,但你真的只对它的某个值感兴趣。

         

    基本用法是在属性上进行映射。想象一下,您有一个用户列表,但您只对用户名列表感兴趣

    出于测试目的,我还试图了解使用selectattr时会发生什么:

    interfaces | selectattr('slaves') | map(attribute='slaves') | selectattr('name') | list
    

    这应该没有区别,因为所有对象都有name属性,但Ansible失败了:

      

    失败! => {“failed”:true,“msg”:“ERROR!'list object'没有属性'name'”}

    不知怎的,似乎列表中有一个列表,调试任务没有显示,因为输出似乎是一个对象列表,但从Jinja的角度看,它似乎正在使用列表列表?

    有谁知道发生了什么以及如何简单地从该列表中获取接口名称?

    现在我用自定义过滤器插件解决了这个问题,但我不明白为什么这个开箱即用不起作用。如果这仍然没有解决,任何人遇到同样的问题,这是我的插件:

    class FilterModule(object):
    
        def filters(self):
            return {
                'interfaces_flattened': self.interfaces_flattened
            }
        def interfaces_flattened(*args):
            names = []
            for interface in args[1]:
                names.extend(get_names(interface))
            return names
    
    def get_names(interface):
        names = []
        if "name" in interface:
            names.append(interface["name"])
        if "bridge" in interface:
            names.append(interface["bridge"]["name"])
        if "slaves" in interface:
            for slave in interface["slaves"]:
                names.extend(get_names(slave))
        return names
    

1 个答案:

答案 0 :(得分:1)

问:所有已定义接口名称的平面列表。

蛮力

    - set_fact:
        names: "{{ names|d([]) + [item.split(':')|last|trim] }}"
      loop: "{{ (interfaces|to_nice_yaml).splitlines() }}"
      when: item is match('^.*\\s+name:\\s+.*$')

给予

  names:
  - br0
  - bond0
  - eth0
  - eth1
  - eth2
  - eth3
相关问题