使用 Powershell 和 Nutanix API 更新 JSON Payload

使用 Powershell 和 Nutanix API 更新 JSON Payload

我目前正在编写一个允许更新 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 网络请求,类别也能正确更新!现在我会尝试提高脚本效率,我知道有些东西可能是多余的,或者可以简化。

相关内容