我目前正在编写一个允许更新 Nutanix VM 类别的脚本。类别格式为 key:value,并且 VM 可能没有类别,或者有 1 个或多个类别。
这个过程很简单:首先我创建一个请求获取现有虚拟机信息 (GET)(然后检索其 UUID)。
第二次,我创建另一个请求更新现有虚拟机 (PUT)通过使用之前检索到的 UUID,并更改我需要更改的内容(更新类别但应该添加磁盘、网卡等...)
目前,获取 VM 的请求很简单,运行也很顺利,但是当我需要使用第二个请求来更新 VM 时,出现了问题。我们如下:
此请求使用的负载在 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"
}
}
}
在 Powershell 中转换后看起来像这样(注意:我们只对元数据感兴趣,你会明白为什么)
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
从 PS 角度可以看出,$payload
它的属性是 PSCustomObject,所以我不能使用类似等方法.Add(), .Remove()
……+=
目前,我能够使用原始 JSON 负载手动更新虚拟机,并以 JSON 格式手动添加类别并通过 Postman 进行测试。效果很好。
事实是,正如您可能已经理解的那样,我必须保留 GET 方法的所有原始有效负载 > 实现添加新类别 > 发送 PUT 请求以完全更新它而没有错误。
我的问题是:从 PS 的角度来看,如何轻松创建和添加新的 key:value 对象,并通过保留现有对象将其正确添加到类别中?(=如何在“类别”中插入新值:{“AppType”:“Exchange”,“AppTier”:“Default”})
PS:供参考,这里是我在 PS 中用于 GET/PUT 的 Web 请求。PUT 请求有效,但除了 PUT 与原始值相同的值外什么也不做:
#### -- 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
答案1
最终在那些鼓舞人心的 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
因此,就我而言(提醒:类别 = 键:值),我创建了一个要更新的值
$to_update = 'My_Value'
然后使用此Add-Member
方法添加我需要的密钥
$get_vm.metadata.categories | Add-Member -value $to_update -MemberType NoteProperty -Name 'My_Key'
注意:这似乎适合 Nutanix,但我必须将spec_version
参数增加 1
($get_vm.metadata.spec_version)++
最后创建用于 Web 请求的有效负载
$payload = (($get_vm | select spec,api_version,metadata) | convertto-json -depth 100)
然后我就能成功启动 PUT 网络请求,类别也能正确更新!现在我会尝试提高脚本效率,我知道有些东西可能是多余的,或者可以简化。