如何遍历复杂的ansible JSON变量的子元素
How to iterate through subelements of complicated ansible JSON variable
我想使用 ansible 任务,在 azure 中创建子网,我有以下剧本
---
- hosts: localhost
vars:
"vnets": [
{
"vnet_aks_re1": [
{
"region": "region1",
"resource_group_key": "aks_spoke_re1",
"specialsubnets": [
{
"AzureFirewallSubnet": [
{
"cidr": [
"10.100.83.128/26"
],
"name": "AzureFirewallSubnet"
}
],
"GatewaySubnet": [
{
"cidr": [
"10.100.83.224/27"
],
"name": "GatewaySubnet"
}
]
}
],
"subnets": [
{
"AzureBastionSubnet": [
{
"cidr": [
"10.100.83.32/27"
],
"name": "AzureBastionSubnet",
"nsg_key": "azure_bastion_nsg"
}
],
"aks_ingress": [
{
"cidr": [
"10.100.82.0/24"
],
"name": "aks_ingress",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"aks_nodepool_system": [
{
"cidr": [
"10.100.80.0/24"
],
"name": "aks_nodepool_system",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"aks_nodepool_user1": [
{
"cidr": [
"10.100.81.0/24"
],
"name": "aks_nodepool_user1",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"application_gateway": [
{
"cidr": [
"10.100.83.96/27"
],
"name": "agw",
"nsg_key": "application_gateway"
}
],
"jumpbox": [
{
"cidr": [
"10.100.83.64/28"
],
"name": "jumpbox",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"private_endpoints": [
{
"cidr": [
"10.100.83.0/27"
],
"enforce_private_link_endpoint_network_policies": true,
"name": "private_endpoints"
}
]
}
],
"vnet": [
{
"address_space": [
"10.100.80.0/22"
],
"name": "aks"
}
]
}
],
"vnet_hub_re1": [
{
"region": "region1",
"resource_group_key": "vnet_hub_re1",
"specialsubnets": [
{
"AzureFirewallSubnet": [
{
"cidr": [
"100.64.101.0/26"
],
"name": "AzureFirewallSubnet"
}
],
"GatewaySubnet": [
{
"cidr": [
"100.64.100.0/27"
],
"name": "GatewaySubnet"
}
]
}
],
"subnets": [
{
"AzureBastionSubnet": [
{
"cidr": [
"100.64.101.64/26"
],
"name": "AzureBastionSubnet",
"nsg_key": "azure_bastion_nsg"
}
],
"jumpbox": [
{
"cidr": [
"100.64.102.0/27"
],
"name": "jumpbox",
"nsg_key": "jumpbox"
}
],
"private_endpoints": [
{
"cidr": [
"100.64.103.128/25"
],
"enforce_private_link_endpoint_network_policies": true,
"name": "private_endpoints"
}
]
}
],
"vnet": [
{
"address_space": [
"100.64.100.0/22"
],
"name": "vnet_hub_re1"
}
]
}
]
}
]
tasks:
- name: Dbg variable
debug:
msg: |
Debug:
--------------------------------
Items: {{ item }}
================================
with_items:
- "{{ vnets[0] | dict2items | json_query('[].value|[*]|[].subnets') }}"
# this would be expected result
- name: Create a subnet
azure_rm_subnet:
resource_group: "{{ item.resource_group_key }}"
virtual_network_name: "{{ item.vnet[0].name }}"
name: "{{ combine(item.subnets[*].name, item.specialsubnets[*].name }}"
address_prefix_cidr: "{{ combine(item.subnets[*].cidr, item.specialsubnets[*].cidr }}"
with_items:
- "{{ vnets[0] | dict2items | json_query('[].value|[*]') }}"
在 JSON 中,变量 vnet 和 subnet 键可以有任何值,所以我不能通过名称访问它们,而是使用 * 遍历它们。同时subnets、vnets和specialsubnets是固定名称。
要创建 azure 子网,我不仅需要子网和特殊子网的内容,还需要同一级别的区域和 resource_group_key。
我无法找到一种方法如何遍历子网和特殊子网的所有元素,使用 with_items,总是打印两个项目,我在 json_query 中输入的内容没有计量。
预期结果是循环创建 13 个子网
# Hub VNET with 5 subnets
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "GatewaySubnet"
address_prefix_cidr: "["100.64.100.0/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "AzureFirewallSubnet"
address_prefix_cidr: "["100.64.101.0/26"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "AzureBastionSubnet"
address_prefix_cidr: "["100.64.101.64/26"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "jumpbox"
address_prefix_cidr: "["100.64.102.0/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "private_endpoints"
address_prefix_cidr: "["100.64.103.128/25"]"
# Spoke vnet with 8 subnets
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "AzureFirewallSubnet"
address_prefix_cidr: "["10.100.83.128/26"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "GatewaySubnet"
address_prefix_cidr: "["10.100.83.224/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "AzureBastionSubnet"
address_prefix_cidr: "["10.100.83.32/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "aks_ingress"
address_prefix_cidr: "["10.100.82.0/24"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "aks_nodepool_system"
address_prefix_cidr: "["10.100.80.0/24"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "aks_nodepool_user1"
address_prefix_cidr: "["10.100.81.0/24"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "agw"
address_prefix_cidr: "["10.100.83.96/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "jumpbox"
address_prefix_cidr: "["10.100.83.64/28"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "private_endpoints"
address_prefix_cidr: "["10.100.83.0/27"]"
问:"遍历子网和特殊子网的所有元素。"
A:Select 列表,例如
_subnets: "{{ vnets|json_query('[].*[][].subnets') }}"
_specialsubnets: "{{ vnets|json_query('[].*[][].specialsubnets') }}"
并迭代它们,例如
- debug:
msg: "{{ item.AzureBastionSubnet.0.cidr.0 }}"
loop: "{{ _subnets|flatten }}"
给予
msg: 10.100.83.32/27
msg: 100.64.101.64/26
和
- debug:
msg: "{{ item.AzureFirewallSubnet.0.cidr.0 }}"
loop: "{{ _specialsubnets|flatten }}"
给予
msg: 10.100.83.128/26
msg: 100.64.101.0/26
当我对文件有复杂的事情时,我更喜欢使用自定义过滤器:
您在剧本文件夹中创建了一个文件夹 filter_plugins(我已将文件命名为 myfilters.py 并且过滤器 自定义)
myfilters.py 文件夹 filter_plugins:
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'custom': self.custom
}
def trapvalues(self, items, vnet):
result = []
virtual_network_name = vnet['vnet'][0]['name']
resource_group = vnet['resource_group_key']
for item in items:
address_prefix_cidr = items[item][0]['cidr']
name = items[item][0]['name']
result.append({'resource_group': resource_group,
'virtual_network_name': virtual_network_name,
'name': name,
'address_prefix_cidr': address_prefix_cidr})
return result
def custom(self, vnets):
result = []
for it in vnets:
special = self.trapvalues(vnets[it][0]['specialsubnets'][0], vnets[it][0])
result.append(special)
sub = self.trapvalues(vnets[it][0]['subnets'][0], vnets[it][0])
result.append(sub)
#print(result)
return result
并且您在任务中调用了自定义过滤器:
tasks:
- name: create variable
set_fact:
result: "{{ vnets[0] | custom }}"
显示的结果:它是一个列表,因此您可以轻松地遍历...
"result": [
[
{
"address_prefix_cidr": [
"10.100.83.128/26"
],
"name": "AzureFirewallSubnet",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.224/27"
],
"name": "GatewaySubnet",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
}
],
[
{
"address_prefix_cidr": [
"10.100.83.32/27"
],
"name": "AzureBastionSubnet",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.82.0/24"
],
"name": "aks_ingress",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.80.0/24"
],
"name": "aks_nodepool_system",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.81.0/24"
],
"name": "aks_nodepool_user1",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.96/27"
],
"name": "agw",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.64/28"
],
"name": "jumpbox",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.0/27"
],
"name": "private_endpoints",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
}
],
[
{
"address_prefix_cidr": [
"100.64.101.0/26"
],
"name": "AzureFirewallSubnet",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
},
{
"address_prefix_cidr": [
"100.64.100.0/27"
],
"name": "GatewaySubnet",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
}
],
[
{
"address_prefix_cidr": [
"100.64.101.64/26"
],
"name": "AzureBastionSubnet",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
},
{
"address_prefix_cidr": [
"100.64.102.0/27"
],
"name": "jumpbox",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
},
{
"address_prefix_cidr": [
"100.64.103.128/25"
],
"name": "private_endpoints",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
}
]
]
我想使用 ansible 任务,在 azure 中创建子网,我有以下剧本
---
- hosts: localhost
vars:
"vnets": [
{
"vnet_aks_re1": [
{
"region": "region1",
"resource_group_key": "aks_spoke_re1",
"specialsubnets": [
{
"AzureFirewallSubnet": [
{
"cidr": [
"10.100.83.128/26"
],
"name": "AzureFirewallSubnet"
}
],
"GatewaySubnet": [
{
"cidr": [
"10.100.83.224/27"
],
"name": "GatewaySubnet"
}
]
}
],
"subnets": [
{
"AzureBastionSubnet": [
{
"cidr": [
"10.100.83.32/27"
],
"name": "AzureBastionSubnet",
"nsg_key": "azure_bastion_nsg"
}
],
"aks_ingress": [
{
"cidr": [
"10.100.82.0/24"
],
"name": "aks_ingress",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"aks_nodepool_system": [
{
"cidr": [
"10.100.80.0/24"
],
"name": "aks_nodepool_system",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"aks_nodepool_user1": [
{
"cidr": [
"10.100.81.0/24"
],
"name": "aks_nodepool_user1",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"application_gateway": [
{
"cidr": [
"10.100.83.96/27"
],
"name": "agw",
"nsg_key": "application_gateway"
}
],
"jumpbox": [
{
"cidr": [
"10.100.83.64/28"
],
"name": "jumpbox",
"nsg_key": "azure_kubernetes_cluster_nsg",
"route_table_key": "default_to_firewall_re1"
}
],
"private_endpoints": [
{
"cidr": [
"10.100.83.0/27"
],
"enforce_private_link_endpoint_network_policies": true,
"name": "private_endpoints"
}
]
}
],
"vnet": [
{
"address_space": [
"10.100.80.0/22"
],
"name": "aks"
}
]
}
],
"vnet_hub_re1": [
{
"region": "region1",
"resource_group_key": "vnet_hub_re1",
"specialsubnets": [
{
"AzureFirewallSubnet": [
{
"cidr": [
"100.64.101.0/26"
],
"name": "AzureFirewallSubnet"
}
],
"GatewaySubnet": [
{
"cidr": [
"100.64.100.0/27"
],
"name": "GatewaySubnet"
}
]
}
],
"subnets": [
{
"AzureBastionSubnet": [
{
"cidr": [
"100.64.101.64/26"
],
"name": "AzureBastionSubnet",
"nsg_key": "azure_bastion_nsg"
}
],
"jumpbox": [
{
"cidr": [
"100.64.102.0/27"
],
"name": "jumpbox",
"nsg_key": "jumpbox"
}
],
"private_endpoints": [
{
"cidr": [
"100.64.103.128/25"
],
"enforce_private_link_endpoint_network_policies": true,
"name": "private_endpoints"
}
]
}
],
"vnet": [
{
"address_space": [
"100.64.100.0/22"
],
"name": "vnet_hub_re1"
}
]
}
]
}
]
tasks:
- name: Dbg variable
debug:
msg: |
Debug:
--------------------------------
Items: {{ item }}
================================
with_items:
- "{{ vnets[0] | dict2items | json_query('[].value|[*]|[].subnets') }}"
# this would be expected result
- name: Create a subnet
azure_rm_subnet:
resource_group: "{{ item.resource_group_key }}"
virtual_network_name: "{{ item.vnet[0].name }}"
name: "{{ combine(item.subnets[*].name, item.specialsubnets[*].name }}"
address_prefix_cidr: "{{ combine(item.subnets[*].cidr, item.specialsubnets[*].cidr }}"
with_items:
- "{{ vnets[0] | dict2items | json_query('[].value|[*]') }}"
在 JSON 中,变量 vnet 和 subnet 键可以有任何值,所以我不能通过名称访问它们,而是使用 * 遍历它们。同时subnets、vnets和specialsubnets是固定名称。
要创建 azure 子网,我不仅需要子网和特殊子网的内容,还需要同一级别的区域和 resource_group_key。
我无法找到一种方法如何遍历子网和特殊子网的所有元素,使用 with_items,总是打印两个项目,我在 json_query 中输入的内容没有计量。
预期结果是循环创建 13 个子网
# Hub VNET with 5 subnets
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "GatewaySubnet"
address_prefix_cidr: "["100.64.100.0/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "AzureFirewallSubnet"
address_prefix_cidr: "["100.64.101.0/26"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "AzureBastionSubnet"
address_prefix_cidr: "["100.64.101.64/26"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "jumpbox"
address_prefix_cidr: "["100.64.102.0/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "vnet_hub_re1"
virtual_network_name: "vnet_hub_re1"
name: "private_endpoints"
address_prefix_cidr: "["100.64.103.128/25"]"
# Spoke vnet with 8 subnets
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "AzureFirewallSubnet"
address_prefix_cidr: "["10.100.83.128/26"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "GatewaySubnet"
address_prefix_cidr: "["10.100.83.224/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "AzureBastionSubnet"
address_prefix_cidr: "["10.100.83.32/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "aks_ingress"
address_prefix_cidr: "["10.100.82.0/24"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "aks_nodepool_system"
address_prefix_cidr: "["10.100.80.0/24"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "aks_nodepool_user1"
address_prefix_cidr: "["10.100.81.0/24"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "agw"
address_prefix_cidr: "["10.100.83.96/27"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "jumpbox"
address_prefix_cidr: "["10.100.83.64/28"]"
- name: Create a subnet
azure_rm_subnet:
resource_group: "aks_spoke_re1"
virtual_network_name: "aks"
name: "private_endpoints"
address_prefix_cidr: "["10.100.83.0/27"]"
问:"遍历子网和特殊子网的所有元素。"
A:Select 列表,例如
_subnets: "{{ vnets|json_query('[].*[][].subnets') }}"
_specialsubnets: "{{ vnets|json_query('[].*[][].specialsubnets') }}"
并迭代它们,例如
- debug:
msg: "{{ item.AzureBastionSubnet.0.cidr.0 }}"
loop: "{{ _subnets|flatten }}"
给予
msg: 10.100.83.32/27
msg: 100.64.101.64/26
和
- debug:
msg: "{{ item.AzureFirewallSubnet.0.cidr.0 }}"
loop: "{{ _specialsubnets|flatten }}"
给予
msg: 10.100.83.128/26
msg: 100.64.101.0/26
当我对文件有复杂的事情时,我更喜欢使用自定义过滤器:
您在剧本文件夹中创建了一个文件夹 filter_plugins(我已将文件命名为 myfilters.py 并且过滤器 自定义)
myfilters.py 文件夹 filter_plugins:
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'custom': self.custom
}
def trapvalues(self, items, vnet):
result = []
virtual_network_name = vnet['vnet'][0]['name']
resource_group = vnet['resource_group_key']
for item in items:
address_prefix_cidr = items[item][0]['cidr']
name = items[item][0]['name']
result.append({'resource_group': resource_group,
'virtual_network_name': virtual_network_name,
'name': name,
'address_prefix_cidr': address_prefix_cidr})
return result
def custom(self, vnets):
result = []
for it in vnets:
special = self.trapvalues(vnets[it][0]['specialsubnets'][0], vnets[it][0])
result.append(special)
sub = self.trapvalues(vnets[it][0]['subnets'][0], vnets[it][0])
result.append(sub)
#print(result)
return result
并且您在任务中调用了自定义过滤器:
tasks:
- name: create variable
set_fact:
result: "{{ vnets[0] | custom }}"
显示的结果:它是一个列表,因此您可以轻松地遍历...
"result": [
[
{
"address_prefix_cidr": [
"10.100.83.128/26"
],
"name": "AzureFirewallSubnet",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.224/27"
],
"name": "GatewaySubnet",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
}
],
[
{
"address_prefix_cidr": [
"10.100.83.32/27"
],
"name": "AzureBastionSubnet",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.82.0/24"
],
"name": "aks_ingress",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.80.0/24"
],
"name": "aks_nodepool_system",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.81.0/24"
],
"name": "aks_nodepool_user1",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.96/27"
],
"name": "agw",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.64/28"
],
"name": "jumpbox",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
},
{
"address_prefix_cidr": [
"10.100.83.0/27"
],
"name": "private_endpoints",
"resource_group": "aks_spoke_re1",
"virtual_network_name": "aks"
}
],
[
{
"address_prefix_cidr": [
"100.64.101.0/26"
],
"name": "AzureFirewallSubnet",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
},
{
"address_prefix_cidr": [
"100.64.100.0/27"
],
"name": "GatewaySubnet",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
}
],
[
{
"address_prefix_cidr": [
"100.64.101.64/26"
],
"name": "AzureBastionSubnet",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
},
{
"address_prefix_cidr": [
"100.64.102.0/27"
],
"name": "jumpbox",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
},
{
"address_prefix_cidr": [
"100.64.103.128/25"
],
"name": "private_endpoints",
"resource_group": "vnet_hub_re1",
"virtual_network_name": "vnet_hub_re1"
}
]
]