Ansible 映射嵌套结构的属性

Ansible 映射嵌套结构的属性,ansible,jinja2,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

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

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
现在,我想生成一个包含所有已定义接口名称的平面列表:

interfaces | selectattr('slaves') | map(attribute='slaves') | map(attribute='name') | list
  • 邦德
  • br0
  • eth0
  • eth1
  • 乙醚
  • eth3
理论上这应该很简单,但我无法提取从属接口的名称(
eth0
-
eth3

以下是工作部分:

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

    换句话说,首先减少接口列表,只获取那些具有
    从属属性的接口。然后使用
    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
    )。但是,当我再次尝试获取具有
    map
    的所有对象的
    name
    属性时,它将失败,结果是
    [Undefined]
    。(注意
    []
    。它似乎是一个未定义的列表,而不仅仅是未定义的列表)

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

    对对象序列应用过滤器或查找属性。这在处理对象列表时很有用,但实际上您只对它的某个值感兴趣

    基本用法是映射属性。假设您有一个用户列表,但您只对一个用户名列表感兴趣

    出于测试目的,我还尝试查看使用
    selectattr
    时会发生什么:

    interfaces | selectattr('slaves') | map(attribute='slaves') | selectattr('name') | list
    
    这应该没有什么区别,因为所有对象都有
    名称
    属性,但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
    
    interfaces | selectattr('slaves') | map(attribute='slaves') | selectattr('name') | list
    
    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