Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ansible-如何组合列表属性?_Ansible_Jinja2_Jq_Ansible Inventory - Fatal编程技术网

Ansible-如何组合列表属性?

Ansible-如何组合列表属性?,ansible,jinja2,jq,ansible-inventory,Ansible,Jinja2,Jq,Ansible Inventory,我有两个单独的清单。第一个是包含基本参数的列表(基本列表),第二个是包含特定机架参数的列表(开发列表) "base_list": [ { "name": "kibana", "path": "kibana/conf/kibana.xml", "src": "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml" }, { "nam

我有两个单独的清单。第一个是包含基本参数的列表(基本列表),第二个是包含特定机架参数的列表(开发列表)

"base_list": [
    {
        "name": "kibana",
        "path": "kibana/conf/kibana.xml",
        "src": "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml"
    },
    {
        "name": "logstash",
        "path": "logstash/conf/logstash.yml",
        "src": "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml"
    },
    {
        "name": "grafana",
        "path": "grafana/conf/grafana.json",
        "src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json"
    },
    {
        "name": "grafana",
        "path": "grafana/conf/nginx.json",
        "src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/nginx.json"
    },
    {
        "name": "grafana",
        "path": "grafana/conf/config.json",
        "src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/config.json"
    },
]

"dev_list": [
    {
        "name": "kibana",
        "path": "kibana/conf/kibana.xml",
        "src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
    },
    {
        "name": "logstash",
        "path": "logstash/conf/jvm.options",
        "src": "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
    }
]
我的目标是将这两个列表结合起来,得到一个item.name和几个item.path和item.src。如下所示的路径:

"end_list": [
        {
            "name": "kibana", 
            "path": "kibana/conf/kibana.xml",
            "src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
        }, 
        {
            "name": "logstash", 
            "path": [
                "logstash/conf/logstash.yml", 
                "logstash/conf/jvm.options"
            ], 
            "src": [
                "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml", 
                "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
            ]
        }, 
        {
            "name": "grafana",
            "path": [
                "grafana/conf/grafana.json",
                "grafana/conf/nginx.json",
                "grafana/conf/config.json"
            ]
            "src": [
                "/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json",
                "/Users/ansible/inventories/_base/group_vars/grafana/conf/nginx.json",
                "/Users/ansible/inventories/_base/group_vars/grafana/conf/config.json"
            ]
        },
    ]
{
'name': item.0.name,
'path': item.1.path|ternary([item.0.path, item.1.path], item.0.path),
'src': item.1.src|ternary([item.0.src, item.1.src], item.1.src)
}

做这件事的最佳方法是什么?

使用自定义Python过滤器可能会更容易,但这里有一个使用Ansible内置过滤器的解决方案:

---
- hosts: localhost
  gather_facts: false
  vars:
    "base_list": [
        {
            "name": "kibana",
            "path": "kibana/conf/kibana.xml",
            "src": "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml"
        },
        {
            "name": "logstash",
            "path": "logstash/conf/logstash.yml",
            "src": "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml"
        },
        {
            "name": "grafana",
            "path": "grafana/conf/grafana.json",
            "src": "/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json"
        },
    ]

    "dev_list": [
        {
            "name": "kibana",
            "path": "kibana/conf/kibana.xml",
            "src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
        },
        {
            "name": "logstash",
            "path": "logstash/conf/jvm.options",
            "src": "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
        }
    ]
  tasks:
    - set_fact:
        end_list: >-
          {{ end_list|default([]) + [
          {
          'name': item.0.name,
          'path': item.1.path|ternary([item.0.path, item.1.path], item.0.path),
          'src': item.1.src|ternary([item.0.src, item.1.src], item.1.src)
          }
          ]}}
      loop: >-
        {{ base_list|zip_longest(dev_list,
        fillvalue={'path': false, 'src': false})|list }}

    - debug:
        var: end_list
这是一个有点棘手的组合,所以我将尝试描述各个部分:

循环使用过滤器。给定列表
list1=[1,2,3]
list2=[11,12]
list1 | zip|u longest(list2)
将生成
[[1,11],[2,12],[3,None]]
(即默认情况下,
zip|最长
将使用
None
作为一个列表短于另一个列表的填充值)。通过设置
fillvalue
参数,我们可以使用
None
以外的值。在这种情况下

loop: >-
  {{ base_list|zip_longest(dev_list,
  fillvalue={'path': false, 'src': false})|list }}
…我们将填充值设置为一个字典,其中包含
path
src
的存根值,因为这使表达式的其余部分更简单

解决方案的核心当然是
set\u fact
操作,其简化形式如下:

end_list: "{{ end_list|default([]) + [{...a dictionary...}] }}"
ok: [localhost] => {
    "end_list": [
        {
            "name": "kibana", 
            "path": [
                "kibana/conf/kibana.xml", 
                "kibana/conf/kibana.xml"
            ], 
            "src": [
                "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml", 
                "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
            ]
        }, 
        {
            "name": "logstash", 
            "path": [
                "logstash/conf/logstash.yml", 
                "logstash/conf/jvm.options"
            ], 
            "src": [
                "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml", 
                "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
            ]
        }, 
        {
            "name": "grafana", 
            "path": "grafana/conf/grafana.json", 
            "src": false
        }
    ]
}
换句话说,对于
循环的每次迭代
,这将向
结束列表
附加一个新字典

我们创建的字典如下所示:

"end_list": [
        {
            "name": "kibana", 
            "path": "kibana/conf/kibana.xml",
            "src": "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
        }, 
        {
            "name": "logstash", 
            "path": [
                "logstash/conf/logstash.yml", 
                "logstash/conf/jvm.options"
            ], 
            "src": [
                "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml", 
                "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
            ]
        }, 
        {
            "name": "grafana",
            "path": [
                "grafana/conf/grafana.json",
                "grafana/conf/nginx.json",
                "grafana/conf/config.json"
            ]
            "src": [
                "/Users/ansible/inventories/_base/group_vars/grafana/conf/grafana.json",
                "/Users/ansible/inventories/_base/group_vars/grafana/conf/nginx.json",
                "/Users/ansible/inventories/_base/group_vars/grafana/conf/config.json"
            ]
        },
    ]
{
'name': item.0.name,
'path': item.1.path|ternary([item.0.path, item.1.path], item.0.path),
'src': item.1.src|ternary([item.0.src, item.1.src], item.1.src)
}
我们在这里使用
三元
过滤器,它将输入作为布尔值进行计算;如果它是
true
,则选择第一个参数,否则选择第二个参数。这里我们利用传递给
zip\u longest
过滤器的
fillvalue
:如果
dev\u list
base\u list
短,我们将有一些
item的项目。1.路径
item.1.src
false
,导致三元过滤器选择第二个值(无论是
item.0.path
还是
item.1.src
)。在其他情况下,我们通过组合
base\u list
dev\u list
中的每个值来构建一个列表

运行此剧本的结果如下所示:

end_list: "{{ end_list|default([]) + [{...a dictionary...}] }}"
ok: [localhost] => {
    "end_list": [
        {
            "name": "kibana", 
            "path": [
                "kibana/conf/kibana.xml", 
                "kibana/conf/kibana.xml"
            ], 
            "src": [
                "/Users/ansible/inventories/_base/group_vars/kibana/conf/kibana.xml", 
                "/Users/ansible/inventories/dev-st/group_vars/kibana/conf/kibana.xml"
            ]
        }, 
        {
            "name": "logstash", 
            "path": [
                "logstash/conf/logstash.yml", 
                "logstash/conf/jvm.options"
            ], 
            "src": [
                "/Users/ansible/inventories/_base/group_vars/logstash/conf/logstash.yml", 
                "/Users/ansible/inventories/dev-st/group_vars/logstash/conf/jvm.options"
            ]
        }, 
        {
            "name": "grafana", 
            "path": "grafana/conf/grafana.json", 
            "src": false
        }
    ]
}

让我知道这是否有帮助,以及生成的数据结构是否是您想要的。我不得不做一些假设,因为您的示例
end\u list
包含无效语法,所以我猜测了您想要的内容。

假设您有格式良好的json,并且这些都是根对象上的属性,那么jq是完美的按名称对数组的内容进行分组,然后生成相应的结果对象

$ jq '{
    end_combine: (
        .base_list + .dev_list
          | group_by(.name)
          | map({ name: .[0].name, path: map(.path), src: map(.src) })
    )
}' input.json

这个Q有[jq]标记,但“预期输出”不是有效的JSON,所以我想知道JSON输出是否可以接受。你说得对,我的“预期输出”不正确。@larsks输出了正确的JSON。感谢您的回复和评论。但这并不是我想要得到的。事实证明,您只需要将第一个列表中的元素与第二个列表中的元素进行比较并对它们进行分组。如果第一个列表中的元素与第二个列表中的元素合并,则只从第二个列表(开发列表)。