No momento, estou escrevendo um script que permite atualizar as categorias de VM do Nutanix. O formato das categorias é chave:valor e uma VM pode não ter categorias, 1 ou múltiplas.
O processo para fazer isso é bastante simples: primeiro eu crio uma solicitação para obter informações de uma VM existente (GET) (depois recupero seu UUID).
Em uma segunda vez, crio outra solicitação para atualizar uma VM existente (PUT) usando o UUID recuperado anteriormente e alterando o que preciso alterar (atualizar categoria, mas deve adicionar discos, nic etc ...)
No momento, a solicitação para obter a VM é simples e funciona sem problemas, mas tive um problema enquanto precisava usar a segunda solicitação para atualizar a VM. Aqui estamos :
A carga útil usada para esta solicitação se parece com isso em JSON
{
"spec": {
"cluster_reference": {
"kind": "cluster",
"name": "my_cluster",
"uuid": "0004f63d-6664-35ce-0126-88e9a456d3fc"
},
"name": "test-vm",
"resources": {
"num_threads_per_core": 1,
"vnuma_config": {
"num_vnuma_nodes": 0
},
"serial_port_list": [],
"nic_list": [
{
"nic_type": "NORMAL_NIC",
"uuid": "334e302a-db6a-48fb-b138-c3e3b2f1d8f6",
"ip_endpoint_list": [
{
"ip": "10.230.172.84",
"type": "ASSIGNED"
}
],
"vlan_mode": "ACCESS",
"mac_address": "50:6b:8d:c5:6c:f0",
"subnet_reference": {
"kind": "subnet",
"name": "vlanXXX",
"uuid": "6de66666-05ec-46ac-6666-aea60e8e831f"
},
"is_connected": true,
"trunked_vlan_list": []
}
],
"num_vcpus_per_socket": 1,
"num_sockets": 1,
"gpu_list": [],
"is_agent_vm": false,
"memory_size_mib": 4096,
"boot_config": {
"boot_device_order_list": [
"CDROM",
"DISK",
"NETWORK"
],
"boot_type": "LEGACY"
},
"hardware_clock_timezone": "UTC",
"power_state_mechanism": {
"guest_transition_config": {
"should_fail_on_script_failure": false,
"enable_script_exec": false
},
"mechanism": "HARD"
},
"power_state": "ON",
"machine_type": "PC",
"vga_console_enabled": true,
"memory_overcommit_enabled": false,
"disk_list": [
{
"uuid": "6f6ad0ba-5b81-487d-8c7b-6c5249a51f4b",
"disk_size_bytes": 48318382080,
"storage_config": {
"storage_container_reference": {
"kind": "storage_container",
"uuid": "13611573-1364-4065-a03d-67a7da51c14d",
"name": "SelfServiceContainer"
}
},
"device_properties": {
"disk_address": {
"device_index": 0,
"adapter_type": "SCSI"
},
"device_type": "DISK"
},
"data_source_reference": {
"kind": "image",
"uuid": "50a186ef-2538-43f3-9d6c-9150dd464ad7"
},
"disk_size_mib": 46080
}
]
},
"description": "test sync categorie"
},
"api_version": "3.1",
"metadata": {
"last_update_time": "2023-06-29T14:25:48Z",
"kind": "vm",
"uuid": "6e1b8781-8a2a-4830-a15a-0af30daccf89",
"project_reference": {
"kind": "project",
"name": "_internal",
"uuid": "706f34c2-98be-4034-92e2-859be84040f3"
},
"creation_time": "2023-06-29T14:25:48Z",
"spec_version": 3,
"categories_mapping": {
"AppType": [
"Exchange"
],
"AppTier": [
"Default"
]
},
"entity_version": "2",
"owner_reference": {
"kind": "user",
"name": "OWNER",
"uuid": "6caba9b0-00a9-57ea-8ba0-10162c0b1dd4"
},
"categories": {
"AppType": "Exchange",
"AppTier": "Default"
}
}
}
E fique assim depois de convertido no Powershell (Nota: estamos interessados apenas nos metadados, você verá o porquê)
PS C:\Users\XXX> $payload.metadata
last_update_time : 29/06/2023 14:25:48
kind : vm
uuid : 6e1b8781-8a2a-4830-a15a-0af30daccf89
project_reference : @{kind=project; name=_internal; uuid=706f34c2-98be-4034-92e2-859be84040f3}
creation_time : 29/06/2023 14:25:48
spec_version : 3
categories_mapping : @{AppType=System.Object[]; AppTier=System.Object[]}
entity_version : 2
owner_reference : @{kind=user; name=owner; uuid=6caba9b0-00a9-57ea-8ba0-10162c0b1dd4}
categories : @{AppType=Exchange; AppTier=Default}
PS C:\Users\XXX> $payload.metadata.categories
AppType AppTier
------- -------
Exchange Default
Como você pode ver de uma perspectiva PS, $payload
e suas propriedades são PSCustomObject, então não posso usar métodos como .Add(), .Remove()
etc...+=
No momento, posso atualizar uma VM manualmente usando a carga útil JSON original, adicionar categoria manualmente no formato JSON e testá-la por meio do Postman. Funciona muito bem.
O problema é que, como você deve ter entendido, tenho que manter toda a carga útil original do método GET> conseguir adicionar uma nova categoria> enviar uma solicitação PUT para atualizá-la totalmente sem erros.
Minha pergunta é: do ponto de vista do PS, como posso criar e adicionar facilmente um novo objeto chave:valor e adicioná-lo adequadamente nas categorias, mantendo o existente? (= como inserir um novo valor dentro de "categories": { "AppType": "Exchange", "AppTier": "Default" } )
PS: para referências, aqui está o Web Request que uso para GET/PUT dentro do PS. A solicitação PUT está funcionando, mas não faz nada, exceto PUT o mesmo valor do original:
#### -- HEADER
$Header_Prism = @{
'Accept' = 'application/json'
'Content-Type' = 'application/json'
'Authorization' = $basicAuthValue
}
#### --- GET VM
$get_vm = Invoke-RestMethod -Uri "https://mynutanix.net/vms/6e1b8781-6666-4830-a15a-0af30daccf89" `
-Method GET `
-Headers $Header_Prism
### --- PUT VM
$payload = $get_vm | select spec,api_version,metadata | convertTo-Json -depth 100
$put_vm = Invoke-RestMethod -Uri "https://mynutanix.net/vms/6e1b8781-6666-4830-a15a-0af30daccf89" `
-Method PUT `
-Headers $Header_Prism `
-Body $payload
Finalmente descobri uma solução graças às postagens inspiradoras do StackOverflow:
https://stackoverflow.com/questions/48597871/how-to-add-an-object-in-array-on-parsed-json
https://stackoverflow.com/questions/23720045/powershell-how-to-add-something-on-parsed-json
Portanto, no meu caso (lembrete: categoria = chave:valor), crio um valor para atualizar
então use este
Add-Member
método para adicionar a chave que eu precisoNota: parece adequado para Nutanix, mas tenho que aumentar
spec_version
os parâmetros em 1E, finalmente, crie a carga útil usada na solicitação da web
Então, consigo iniciar a solicitação da Web PUT com sucesso e a categoria é atualizada corretamente! Agora vou tentar melhorar a eficiência do meu script, sei que algumas coisas podem ser redundantes ou podem ser facilitadas.