Tenho um objeto do tipo dict/json que capturei da saída de uma chamada de API REST, digamos que esteja em uma variável/registrador chamado output . Os dados são os seguintes. Para completar, compartilhei o objeto inteiro e fiz uma limpeza básica. Sinta-se à vontade para focar apenas na linha que discutirei a seguir ;-)
{
"_create_time": 1724823837185,
"_create_user": "system",
"_last_modified_time": 1736218001919,
"_last_modified_user": "nsx_policy",
"_protection": "NOT_PROTECTED",
"_revision": 1,
"_system_owned": false,
"display_name": "w1-vc1-c4n17.example.com",
"host_switch_spec": {
"host_switches": [
{
"cpu_config": [],
"ecmp_mode": "L3",
"host_switch_id": "50 01 cb 21 be 19 cb 38-78 bd 67 bc b3 0e 91 f1",
"host_switch_mode": "STANDARD",
"host_switch_name": "w1-vc1-c4-dvs",
"host_switch_profile_ids": [
{
"key": "UplinkHostSwitchProfile",
"value": "/infra/host-switch-profiles/6d7a0ed8-c86a-4190-9121-ce6f863226ae"
},
{
"key": "VtepHAHostSwitchProfile",
"value": "/infra/host-switch-profiles/0de8282e-7385-4e8e-a905-0c11960db728"
}
],
"host_switch_type": "VDS",
"ip_assignment_spec": {
"ip_pool_id": "/infra/ip-pools/w1-nsx1-esxi-teps",
"resource_type": "StaticIpPoolSpec"
},
"is_migrate_pnics": false,
"not_ready": false,
"portgroup_transport_zone_id": "/infra/sites/default/enforcement-points/default/transport-zones/77166711-1f83-407f-8c27-a4e1b8b4e1e5",
"transport_zone_endpoints": [
{
"transport_zone_id": "/infra/sites/default/enforcement-points/default/transport-zones/4b367ddf-d4ac-460b-a884-24846ff4edf6",
"transport_zone_profile_ids": [
{
"profile_id": "/infra/transport-zone-profiles/52035bb3-ab02-4a08-9884-18631312e50a",
"resource_type": "BfdHealthMonitoringProfile"
}
]
},
{
"transport_zone_id": "/infra/sites/default/enforcement-points/default/transport-zones/bc19b340-f0b5-46d8-9454-6d94d3288821",
"transport_zone_profile_ids": [
{
"profile_id": "/infra/transport-zone-profiles/52035bb3-ab02-4a08-9884-18631312e50a",
"resource_type": "BfdHealthMonitoringProfile"
}
]
}
],
"uplinks": [
{
"uplink_name": "uplink-2",
"vds_uplink_name": "uplink2"
},
{
"uplink_name": "uplink-1",
"vds_uplink_name": "uplink1"
}
]
}
],
"resource_type": "StandardHostSwitchSpec"
},
"id": "w1-vc1-c4n17-6adb838f-669c-48ca-b76f-e1238984ef93host-2171",
"is_overridden": false,
"maintenance_mode": "DISABLED",
"marked_for_delete": false,
"node_deployment_info": {
"compute_collection_id": "6adb838f-669c-48ca-b76f-e1238984ef93:domain-c2147",
"discovered_ip_addresses": [
"x.x.x.x",
"x.x.x.x"
],
"discovered_node_id": "6adb838f-669c-48ca-b76f-e1238984ef93:host-2171",
"fqdn": "w1-vc1-c4n17.example.com",
"ip_addresses": [
"10.x.x.x"
],
"managed_by_server": "10.x.x.x",
"os_type": "ESXI",
"os_version": "x.x.x"
},
"overridden": false,
"owner_id": "1ae23909-d587-4683-a515-4c2001940803",
"parent_path": "/infra/sites/default/enforcement-points/default",
"path": "/infra/sites/default/enforcement-points/default/host-transport-nodes/w1-vc1-c4n17-6adb838f-669c-48ca-b76f-e1238984ef93host-2171",
"realization_id": "c2c69a21-698a-4586-869a-7c0b0a651601",
"relative_path": "w1-vc1-c4n17-6adb838f-669c-48ca-b76f-e1238984ef93host-2171",
"remote_path": "",
"resource_type": "HostTransportNode",
"unique_id": "c2c69a21-698a-4586-869a-7c0b0a651601"
}
Gostaria de atualizar este objeto alterando a seguinte linha:
"host_switch_mode": "STANDARD",
para:
"host_switch_mode": "LEGACY",
E alimentarei o resultado JSON como um corpo de mensagem para uma chamada de API POST. Tentei o filtro combine do anislbe, mas não obtive o resultado esperado. Algo como:
- Name: example post/put API call
uri:
url: "https://{{ nsx }}/policy/api/v1/infra/host-transport-node-profiles/{{ id }}"
force_basic_auth: yes
validate_certs: no
headers:
Accept: "application/json"
Content-Type: "application/json"
user: "{{ username }}"
password: "{{ password }}"
method: PUT
body: "{{ ouput | combine( {'host_switch_spec': {'host_switches': [ {'host_switch_mode': "LEGACY"},],}, }, recursive=true) }}"
status_code: "200"
body_format: json
Com o filtro de combinação, o que vejo é que, em vez de apenas mesclar a linha relevante, toda a seção host_switch_spec é substituída (perdendo, portanto, outros atributos, como host_switch_name, host_switch_id, etc.), o que não é o que eu quero:
"host_switch_spec": {
"host_switches": [
{
"host_switch_mode": "STANDARD"
}
],
"resource_type": "StandardHostSwitchSpec"
},
O que eu fiz de errado? Consultei a página de manual do filtro Combine e tentei todas as opções do list_merge , mas nenhuma delas ajudou.
atualizar:
Para simplificar, uma das complicações que não mencionei na minha postagem inicial é que tenho uma lista desses objetos de dados de "saída" e preciso processá-los em um loop como o mostrado abaixo. Digamos que a lista esteja na variável "tn":
# Modify the transport node json data on the fly and feed it to the API as message body
- debug:
msg:
- "{{ item }}"
- "{{ item | combine( {'host_switch_spec': {'host_switches': [ {'host_switch_mode': mode}, ], }, },) }}"
with_items: "{{ tn }}"
loop_control:
label: "{{ item.display_name }}"
Resumo:
Obrigado a todos pela ajuda e orientação. Ainda não concluí os testes de ponta a ponta, mas aqui está o que criei com base nos exemplos fantásticos de Vladimir Botka:
# how to modify the transport node json data on the fly and feed it to the API as message body
- name: Testing switch mode update on the fly
debug:
msg:
#- "hs: {{ (item.host_switch_spec.host_switches + [ hs_update ]) | combine }}"
#- "update: {{ {'host_switch_spec': {'host_switches': [ (item.host_switch_spec.host_switches + [ hs_update ]) | combine ]}} }}"
#- "result: {{ item | combine({'host_switch_spec': {'host_switches': [ (item.host_switch_spec.host_switches + [ hs_update ]) | combine ]}}) }}"
- "{{ item | combine({'host_switch_spec': {'host_switches': [ (item.host_switch_spec.host_switches + [ hs_update ]) | combine ]}}) }}"
loop: "{{ tn }}"
loop_control:
label: "{{ item.display_name }}"
index_var: counter
vars:
hs_update:
host_switch_mode: "LEGACY"
E o resultado parece promissor (mostrando o último - #24, e apenas parcial para evitar confusão):
ok: [localhost] => (item=w11-vc1-c1n24.example.com) => {
"msg": [
"24':' STANDARD",
{
"_create_time": 1743198123451,
"_create_user": "system",
"_last_modified_time": 1743445520238,
"_last_modified_user": "system",
"_protection": "NOT_PROTECTED",
"_revision": 2,
"_system_owned": false,
"display_name": "w11-vc1-c1n24.example.com",
"host_switch_spec": {
"host_switches": [
{
"cpu_config": [],
"ecmp_mode": "L3",
"host_switch_id": "50 1e 66 c9 c5 fb da b3-5e 1f 45 fc 2a 42 99 50",
"host_switch_mode": "LEGACY",
"host_switch_name": "w11-vc1-dvs",
"host_switch_profile_ids": [
{
"key": "UplinkHostSwitchProfile",
"value": "/infra/host-switch-profiles/ace9be64-9728-4340-968e-a62dae6a3d00"
},
{
"key": "VtepHAHostSwitchProfile",
"value": "/infra/host-switch-profiles/0de8282e-7385-4e8e-a905-0c11960db728"
}
],
"host_switch_type": "VDS",
output.host_switch_spec.host_switches
é uma lista com um itemColoque em um dicionário o que você deseja atualizar. Por exemplo,
combinar os dicionários
dá
Observação: se houvesse mais itens, você teria que criar um produto e mapear a função de combinação .
Criar a atualização do dicionário
e combinar o resultado
dá
Exemplo de um manual completo para testes
P: ** "O 'host_switch_spec' tem 'host_switches' e 'resource_type' """
A: Combine os dicionários recursivamente
dá
P: "Lista desses objetos de dados de 'saída'."
R: Se houver mais itens, por exemplo:
atualizar todos os itens
dá
Em seguida, combine os dicionários
dá