Draft — unlisted, for review only
vcf vcf91 vlcm images personalities lifecycle api postman day2

Day-2: Image Management (vLCM Images) via the API

Managing vLCM cluster images in VCF Operations 9.1 with the SDDC Manager API — get a token, list the images (personalities), and delete a custom exported image the GUI won't let you remove. Postman- and curl-friendly.

Draft — VCF 9.1 lab series. Hostnames are from the pgvcf1 lab (pgvcf1sddcm.pgnet.io); swap them for your own. Live secrets — the admin password and the service-account apiKey — stay as <PLACEHOLDER>; never paste those into a shared doc. Sits between Operations and Lifecycle & Updates as a Day-2 task.

📘 Official documentation. vLCM image management is documented by Broadcom. This page just shows the API flow for one common Day-2 gap. Always defer to the vendor docs — see Sources. Where they differ, the official docs win.

Why the API for images?

In VCF 9.1, a vLCM cluster image — the desired-state ESX version + vendor add-on + firmware/components a cluster runs — is exposed in the SDDC Manager API as a personality. If you’ve moved a cluster from the old vLCM baselines model to images (see the transition doc), you’re already managing personalities whether you call them that or not.

Most image work happens in the UI. One thing does not: you can export a cluster’s image to a reusable custom image, but VCF Operations 9.1 gives you no button to delete an exported / custom image again. They accumulate. The supported way to remove one is a single API call — Broadcom documents exactly this in KB 321672.

So this page is the practical Day-2 loop for anyone driving it from Postman (or curl):

StepCallPurpose
1POST /v1/tokensGet a bearer token
2GET /v1/personalitiesList images, find the id / name
3DELETE /v1/personalitiesRemove the custom / exported image

What you need

  • The SDDC Manager FQDN — in 9.1 this is the appliance that fronts the Fleet / lifecycle APIs, e.g. https://pgvcf1sddcm.pgnet.io.
  • An account that can authenticate to it — either admin@local (or your admin user) with its password, or a SERVICE account apiKey if you’ve minted one for automation.
  • TLS: production callers should pin the SDDC Manager CA. In a lab it’s common to skip verification (-k in curl, Settings → SSL certificate verification → off in Postman). Pin the CA if you can.

All calls below use https://pgvcf1sddcm.pgnet.io as the base URL. In Postman, set it once as a collection variable {{base}} so you can point the same collection at any environment.

Step 1 — Get a token

POST {{base}}/v1/tokens. The body is JSON. Two ways to authenticate — pick one:

A. Username + password (simplest for interactive Postman use):

{
  "username": "admin@local",
  "password": "<ADMIN_PASSWORD>"
}

B. SERVICE account apiKey (what automation uses — long-lived key, short-lived token):

{
  "apiKey": "<SERVICE_ACCOUNT_API_KEY>"
}

Headers: Accept: application/json and Content-Type: application/json. The response gives you a short-lived bearer plus a refresh token:

{
  "accessToken": "eyJhbGciOi...",
  "refreshToken": "abc123..."
}

📸 Screenshot: Postman — POST /v1/tokens with the username/password body and the 200 response showing accessToken.

Capture it automatically in Postman. Add this to the request’s Scripts → Post-response (formerly Tests) tab so every later call inherits the token:

const body = pm.response.json();
pm.collectionVariables.set("token", body.accessToken);

Then set the collection (or folder) Authorization to Bearer Token with value {{token}}, and leave every other request on Inherit auth from parent. Now steps 2 and 3 are just send-and-go.

Token lifetime. The accessToken is short-lived — if a later call returns 401, re-run Step 1 to mint a fresh one (or use the refreshToken against /v1/tokens/access-token). Automation should re-mint on expiry rather than caching a token.

Step 2 — List the images

GET {{base}}/v1/personalities with Authorization: Bearer {{token}}. The response is a page of elements; each element is one image:

{
  "elements": [
    {
      "personalityId": "b1f2...-...",
      "personalityName": "prod-cluster-image",
      "baseImageVersion": "9.1.0-24000000",
      "source": "EXPORTED"
    }
  ],
  "pageMetadata": { "totalElements": 1 }
}

Note the personalityId (GUID) and personalityName of the image you want to remove — either one is enough for Step 3. Exported/custom images typically show a source of EXPORTED (vs a cluster-derived image), which is how you tell the disposable ones apart.

📸 Screenshot: Postman — GET /v1/personalities response, highlighting personalityName / personalityId of the exported image.

Step 3 — Delete the custom / exported image

DELETE {{base}}/v1/personalities with the target passed as a query parameter — by name or id:

DELETE {{base}}/v1/personalities?personalityName=prod-cluster-image

or

DELETE {{base}}/v1/personalities?personalityId=b1f2...-...

Header: Authorization: Bearer {{token}}. A 200 / 202 / 204 means it’s gone. Re-run Step 2 to confirm it’s no longer in the list.

📸 Screenshot: Postman — DELETE /v1/personalities?personalityName=... returning 204, then the empty/updated list.

Careful — this is a delete. There’s no undo. Delete only images you exported and no longer need. An image a cluster is actively using shouldn’t be removed out from under it; remove the disposable exported copies. Confirm the name/id against Step 2 before you send.

Quick reference — curl

The same three calls without Postman. Lab-style (skip TLS verify with -k); pin the CA in production.

SM=https://pgvcf1sddcm.pgnet.io

# 1. Token (username/password shown; swap the body for {"apiKey":"..."} for a service account)
TOKEN=$(curl -sk -X POST $SM/v1/tokens -H 'Content-Type: application/json' \
  -d '{"username":"admin@local","password":"<ADMIN_PASSWORD>"}' \
  | python3 -c 'import sys,json;print(json.load(sys.stdin)["accessToken"])')

# 2. List images (personalities) — find the id/name
curl -sk $SM/v1/personalities -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

# 3. Delete the exported/custom image (by name or id)
curl -sk -X DELETE "$SM/v1/personalities?personalityName=prod-cluster-image" \
  -H "Authorization: Bearer $TOKEN" -i

Automating with Salt (pgnet)

In the lab this is wrapped in the sddc_api runner so it’s a one-liner and confirm-gated. The token is minted from the svc-salt-sddc SERVICE account’s apiKey, read straight from OpenBao (never a password on the CLI):

# list images (personalities)
salt-run sddc_api.report kind=personalities

# delete one — confirm-gated and idempotent
salt-run sddc_api.personality_delete personality_name=prod-cluster-image confirm=yes

The runner mints a short-lived bearer via sddc_rest.mint_token, re-mints on expiry, and pins the SDDC Manager CA — the same three calls above, just made safe to run unattended. The Salt wiring is intentionally kept out of the step-by-step so the API flow stays readable.

Sources