<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Cosmin.us</title><link>https://cosmin.us/</link><description>Recent content on Cosmin.us</description><generator>Hugo</generator><language>en-US</language><dc:creator>Cosmin Trif</dc:creator><lastBuildDate>Tue, 08 Sep 2026 16:30:00 +0000</lastBuildDate><atom:link href="https://cosmin.us/index.xml" rel="self" type="application/rss+xml"/><item><title>Upgrading VCF Log Management to 9.1.1 Step by Step</title><link>https://cosmin.us/upgrading-vcf-log-management-to-9-1-1-step-by-step/</link><pubDate>Tue, 08 Sep 2026 16:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/upgrading-vcf-log-management-to-9-1-1-step-by-step/</guid><description>&lt;p&gt;With VCF 9.1.1 released on September 3, 2026, I wanted to continue patching the management services in my lab. This post is a follow-up to my &lt;a href="https://cosmin.us/upgrading-vcf-9-1-management-services-to-9-1-0-0400-step-by-step/"&gt;VCF 9.1 management services upgrade walkthrough&lt;/a&gt; and focuses on &lt;strong&gt;Log Management&lt;/strong&gt; through VCF Operations.&lt;/p&gt;
&lt;p&gt;VCF 9.1.1 is a maintenance release focused mostly on supportability improvements. The main &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;VCF 9.1.1 release notes&lt;/a&gt; and the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;VCF Operations 9.1.1 release notes&lt;/a&gt; are the references I used for this upgrade.&lt;/p&gt;
&lt;p&gt;In VCF 9.1, Log Management is a VCF management service hosted on the VCF services runtime. The supported lifecycle workflow is therefore in VCF Operations under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;. This walkthrough covers a 9.1.0.x maintenance upgrade; an environment coming from an older VCF or Aria release should follow the matching &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/upgrading-cloud-foundation/upgrade-vcf-operations-for-logs.html"&gt;Log Management upgrade procedure&lt;/a&gt; first.&lt;/p&gt;</description><content:encoded>&lt;p&gt;With VCF 9.1.1 released on September 3, 2026, I wanted to continue patching the management services in my lab. This post is a follow-up to my &lt;a href="https://cosmin.us/upgrading-vcf-9-1-management-services-to-9-1-0-0400-step-by-step/"&gt;VCF 9.1 management services upgrade walkthrough&lt;/a&gt; and focuses on &lt;strong&gt;Log Management&lt;/strong&gt; through VCF Operations.&lt;/p&gt;
&lt;p&gt;VCF 9.1.1 is a maintenance release focused mostly on supportability improvements. The main &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;VCF 9.1.1 release notes&lt;/a&gt; and the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;VCF Operations 9.1.1 release notes&lt;/a&gt; are the references I used for this upgrade.&lt;/p&gt;
&lt;p&gt;In VCF 9.1, Log Management is a VCF management service hosted on the VCF services runtime. The supported lifecycle workflow is therefore in VCF Operations under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;. This walkthrough covers a 9.1.0.x maintenance upgrade; an environment coming from an older VCF or Aria release should follow the matching &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/upgrading-cloud-foundation/upgrade-vcf-operations-for-logs.html"&gt;Log Management upgrade procedure&lt;/a&gt; first.&lt;/p&gt;
&lt;h2 id="versions-in-this-upgrade"&gt;Versions in This Upgrade&lt;/h2&gt;
&lt;p&gt;These are the versions reported by the VCF Operations UI in my lab:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;Current Version&lt;/th&gt;
					&lt;th&gt;Target Version&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Log Management&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25544947&lt;/td&gt;
					&lt;td&gt;9.1.1.0.25679624&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The target build is also listed in the VCF Operations 9.1.1 release notes.&lt;/p&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;p&gt;For an existing &lt;strong&gt;9.1.0.x&lt;/strong&gt; environment, patch &lt;strong&gt;Fleet Lifecycle to 9.1.1.0 before any other VCF component&lt;/strong&gt;. After Fleet Lifecycle is updated, the release notes allow the remaining components to be patched according to the documented dependencies. I ran this Log Management operation by itself so that the task and validation were easy to follow.&lt;/p&gt;
&lt;p&gt;Before starting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify that the external SFTP backup location is configured and reachable under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Backup &amp;amp; Restore&lt;/strong&gt;. Keep the backup encryption passphrase available for a restore.&lt;/li&gt;
&lt;li&gt;Take an &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation.html"&gt;on-demand component backup&lt;/a&gt; and verify that it completed successfully before patching Log Management.&lt;/li&gt;
&lt;li&gt;Confirm that the lifecycle metadata is current and that the required 9.1.1 binaries are available in the configured software depot. If the depot is offline, prepare the binaries with the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/binary-management-for-vmware-cloud-foundation.html"&gt;VCF Download Tool&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure no other upgrade or patch operation is running. The &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/using-the-depot-configuration-tab/upgrade-a-vcf-management-component.html"&gt;individual-component procedure&lt;/a&gt; says another component cannot be upgraded or patched while an operation is in progress.&lt;/li&gt;
&lt;li&gt;Plan a maintenance window and record the Log Management integrations and log sources you need to test afterward.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is also a 9.1.1 known issue when &lt;strong&gt;Log Management&lt;/strong&gt; and &lt;strong&gt;VCF Operations for networks&lt;/strong&gt; are installed in parallel: the platform can be disrupted, causing Real-time Metrics to fail and the Operations for networks task to remain stuck for more than three hours. Install those components sequentially instead.&lt;/p&gt;
&lt;h2 id="selecting-log-management"&gt;Selecting Log Management&lt;/h2&gt;
&lt;p&gt;Log in to VCF Operations with an Administrator account and go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The target in my lab is already &lt;code&gt;9.1.1.*&lt;/code&gt;. If the target is still on an older release, click &lt;strong&gt;Select Version&lt;/strong&gt;, choose &lt;code&gt;9.1.1.*&lt;/code&gt;, and apply the target before selecting the component. If the page shows a warning that VCF Operations must be patched independently, finish that patch and wait for it to succeed before continuing with the other management components.&lt;/p&gt;
&lt;p&gt;Filter the component list for &lt;strong&gt;log&lt;/strong&gt;, select &lt;strong&gt;Log management&lt;/strong&gt;, and make sure the intended instance is selected. In my lab the instance is &lt;strong&gt;instance-a&lt;/strong&gt;. Expand &lt;strong&gt;Check Required Binaries&lt;/strong&gt; and resolve any missing binary before continuing.&lt;/p&gt;
&lt;p&gt;The upgrade path should read &lt;strong&gt;9.1.0.0400.25544947 -&amp;gt; 9.1.1.0.25679624&lt;/strong&gt;. The screenshot below shows the target version, the selected Log Management instance, and the &lt;strong&gt;Ready for upgrade&lt;/strong&gt; state.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-log-management-9-1-1-upgrade/001-capture-001.webp" alt="VCF Operations VCF Management Upgrade page showing Log Management instance-a ready to upgrade from 9.1.0.0400.25544947 to 9.1.1.0.25679624." width="1666" height="665" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="running-the-prechecks"&gt;Running the Prechecks&lt;/h2&gt;
&lt;p&gt;With only Log Management selected, click &lt;strong&gt;Run Prechecks (1)&lt;/strong&gt;. Follow the task by opening &lt;strong&gt;Precheck details&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-log-management-9-1-1-upgrade/003-capture-003.webp" alt="Log Management precheck workflow showing the component package being staged in VCF services runtime." width="1128" height="621" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The precheck workflow in my lab completed successfully in about 14 minutes. It passed the package staging, vCenter, database upgrade, and single-component backup checks.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-log-management-9-1-1-upgrade/004-capture-004.webp" alt="Completed Log Management precheck workflow with an overall Passed result and six checks passed." width="1126" height="510" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Do not start the upgrade until the precheck status is &lt;strong&gt;Passed&lt;/strong&gt;. If a check fails, open its details, remediate the reported issue, and run the precheck again.&lt;/p&gt;
&lt;h2 id="starting-the-upgrade"&gt;Starting the Upgrade&lt;/h2&gt;
&lt;p&gt;Return to the component list and click &lt;strong&gt;Upgrade&lt;/strong&gt; on the Log Management row. The row changes to &lt;strong&gt;Upgrade in progress&lt;/strong&gt;. Click &lt;strong&gt;Upgrade details&lt;/strong&gt; to follow the workflow.&lt;/p&gt;
&lt;p&gt;The workflow runs through these subtasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set Log Management upgrade context for the workflow.&lt;/li&gt;
&lt;li&gt;Stage the Log Management plugin in VCF services runtime.&lt;/li&gt;
&lt;li&gt;Run the Log Management prechecks.&lt;/li&gt;
&lt;li&gt;Stage the Log Management package in VCF services runtime.&lt;/li&gt;
&lt;li&gt;Prepare Log Management for upgrade.&lt;/li&gt;
&lt;li&gt;Perform the Log Management upgrade.&lt;/li&gt;
&lt;li&gt;Run the post-upgrade inventory sync.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-log-management-9-1-1-upgrade/007-capture-007.webp" alt="Log Management upgrade workflow in progress while the component upgrade is being performed." width="1122" height="637" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The workflow started at &lt;strong&gt;10:53 AM&lt;/strong&gt; in my lab. The task took about &lt;strong&gt;1 hour and 11 minutes&lt;/strong&gt;, completing at &lt;strong&gt;12:04 PM&lt;/strong&gt;. That is the total workflow time shown in my task, not a promise about service downtime in another environment. Wait for the final inventory sync and confirm that the overall task is &lt;strong&gt;Completed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-log-management-9-1-1-upgrade/008-capture-008.webp" alt="Completed Log Management upgrade workflow with all seven subtasks completed." width="1128" height="480" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="verifying-the-new-version"&gt;Verifying the New Version&lt;/h2&gt;
&lt;p&gt;Go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Components&lt;/strong&gt; and open the &lt;strong&gt;Log Management&lt;/strong&gt; component for the instance you upgraded.&lt;/p&gt;
&lt;p&gt;Under &lt;strong&gt;Summary&lt;/strong&gt;, verify that the status is &lt;strong&gt;Running&lt;/strong&gt;, the version is &lt;strong&gt;9.1.1.0.25679624&lt;/strong&gt;, and the component is managed by the expected VCF services runtime. In my lab the deployment size is &lt;strong&gt;Small&lt;/strong&gt; with one replica.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-log-management-9-1-1-upgrade/009-capture-009.webp" alt="Log Management component summary showing Running status and version 9.1.1.0.25679624." width="419" height="376" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;After the component reports Running, validate the parts of the service that matter in your environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open &lt;strong&gt;Operate -&amp;gt; Logs&lt;/strong&gt; and run a known query.&lt;/li&gt;
&lt;li&gt;Confirm that new events are arriving from representative vSphere, ESXi, and application sources.&lt;/li&gt;
&lt;li&gt;Check dashboards, alerts, notification targets, and any custom integrations.&lt;/li&gt;
&lt;li&gt;Verify that any custom log forwarding configuration still points to the correct Log Management instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="911-changes-to-keep-in-mind"&gt;9.1.1 Changes to Keep in Mind&lt;/h2&gt;
&lt;p&gt;The release notes call out a few Log Management changes that are easy to miss during validation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Additional Storage Required&lt;/strong&gt; metric and its related symptoms, alerts, and dashboards were removed because the old value could report a misleading storage shortfall when no retention period was defined.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Server Side Encryption&lt;/strong&gt; field was removed from the &lt;strong&gt;Add New Storage&lt;/strong&gt; screen. AWS S3 uses its default AES-256 behavior; for non-AWS S3-compatible storage, configure bucket-level encryption on the storage server itself.&lt;/li&gt;
&lt;li&gt;If a Log Management Disaster Recovery restore leaves the Log Analysis page showing &lt;strong&gt;Unable to access logs due to user permissions&lt;/strong&gt;, the documented workaround is to restart the Log Management service through Fleet Lifecycle using the component &lt;strong&gt;Stop / Start&lt;/strong&gt; action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the component and log sources have been validated, keep or expire the backup artifacts according to your retention policy. I also recommend clearing the browser cache before using the updated VCF Operations interface.&lt;/p&gt;
&lt;p&gt;Log Management in my lab is now on &lt;strong&gt;9.1.1&lt;/strong&gt;. If this is part of a larger VCF 9.1.1 maintenance run, continue with the remaining components in the order and dependency boundaries documented in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;VCF 9.1.1 release notes&lt;/a&gt;.&lt;/p&gt;
&lt;!-- Editorial review, 2026-09-08:
Broadcom's VCF 9.1.1 release notes and the current individual-component lifecycle
procedure were reviewed on September 8, 2026. The supplied session contains nine
captures; 002, 005, and 006 are cropped state-transition views that repeat the
fuller workflow evidence, so the six higher-value captures are used here. The
included images are lossless WebP conversions with no visual edits. The captures
establish the source and target builds, precheck result, workflow subtasks, task
duration, and final Running state. They do not establish backup completion or
service downtime, so those are written as prerequisites and validation guidance.
The release-note guidance permits parallel work after Fleet Lifecycle where
component dependencies allow it; this walkthrough intentionally runs one
component at a time and follows the individual-component procedure.
--&gt;</content:encoded></item><item><title>Upgrading VCF SDDC Lifecycle to 9.1.1 Step by Step</title><link>https://cosmin.us/upgrading-vcf-sddc-lifecycle-to-9-1-1-step-by-step/</link><pubDate>Tue, 08 Sep 2026 12:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/upgrading-vcf-sddc-lifecycle-to-9-1-1-step-by-step/</guid><description>&lt;p&gt;With &lt;a href="https://cosmin.us/upgrading-vcf-services-runtime-to-9-1-1-step-by-step/"&gt;VCF Services Runtime upgraded to 9.1.1&lt;/a&gt;, the next component I wanted to upgrade in my lab was SDDC Lifecycle. In this post I will go over upgrading it from &lt;strong&gt;9.1.0.0400&lt;/strong&gt; to &lt;strong&gt;9.1.1.0&lt;/strong&gt; through VCF Operations.&lt;/p&gt;
&lt;p&gt;VCF 9.1.1 was released on September 3, 2026. This is a maintenance release focused mostly on supportability improvements. The release notes can be found &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;p&gt;For an existing &lt;strong&gt;9.1.0.x&lt;/strong&gt; environment, upgrade &lt;strong&gt;Fleet Lifecycle to 9.1.1 first&lt;/strong&gt;, before any other VCF component. In my lab it is already on &lt;strong&gt;9.1.1.0.25713934&lt;/strong&gt;. Continue to follow the release-specific dependencies in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;9.1.1 release notes&lt;/a&gt; when planning the remaining components.&lt;/p&gt;</description><content:encoded>&lt;p&gt;With &lt;a href="https://cosmin.us/upgrading-vcf-services-runtime-to-9-1-1-step-by-step/"&gt;VCF Services Runtime upgraded to 9.1.1&lt;/a&gt;, the next component I wanted to upgrade in my lab was SDDC Lifecycle. In this post I will go over upgrading it from &lt;strong&gt;9.1.0.0400&lt;/strong&gt; to &lt;strong&gt;9.1.1.0&lt;/strong&gt; through VCF Operations.&lt;/p&gt;
&lt;p&gt;VCF 9.1.1 was released on September 3, 2026. This is a maintenance release focused mostly on supportability improvements. The release notes can be found &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;p&gt;For an existing &lt;strong&gt;9.1.0.x&lt;/strong&gt; environment, upgrade &lt;strong&gt;Fleet Lifecycle to 9.1.1 first&lt;/strong&gt;, before any other VCF component. In my lab it is already on &lt;strong&gt;9.1.1.0.25713934&lt;/strong&gt;. Continue to follow the release-specific dependencies in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;9.1.1 release notes&lt;/a&gt; when planning the remaining components.&lt;/p&gt;
&lt;p&gt;Before starting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify that the external SFTP backup location is configured and reachable under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Backup &amp;amp; Restore&lt;/strong&gt;. Keep the encryption passphrase available for a restore. The configuration steps are &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation/configure-sftp-backup-target-in-vmware-cloud-foundation-operations.html"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Take an &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation/backup-vcf-automation.html"&gt;on-demand backup&lt;/a&gt;. Go to &lt;strong&gt;Backup &amp;amp; Restore -&amp;gt; Backup -&amp;gt; Backup Now&lt;/strong&gt;, select the VCF instance and &lt;strong&gt;SDDC Lifecycle&lt;/strong&gt;, and verify that the backup completes successfully. Review the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation.html"&gt;supported backup methods&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure the required upgrade binaries are available through the assigned depot. For offline or disconnected environments, prepare them with the VCF Download Tool using the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/binary-management-for-vmware-cloud-foundation.html"&gt;binary management documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I ran this as a single component operation and waited for it to complete before starting another management-service operation. That keeps the workflow easy to follow and avoids competing lifecycle tasks during the maintenance window.&lt;/p&gt;
&lt;p&gt;Here are the versions from my lab:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;Before&lt;/th&gt;
					&lt;th&gt;After&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;SDDC Lifecycle&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25570103&lt;/td&gt;
					&lt;td&gt;9.1.1.0.25713940&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The target version and build match the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vmware-cloud-foundation-9-1-1-0-bill-of-material.html"&gt;VCF 9.1.1 Bill of Materials&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="selecting-sddc-lifecycle"&gt;Selecting SDDC Lifecycle&lt;/h2&gt;
&lt;p&gt;To get started, log in to VCF Operations with an Administrator account and go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Target VCF version&lt;/strong&gt; in my lab is already set to &lt;strong&gt;9.1.1.*&lt;/strong&gt; from the previous upgrade. If yours is still on &lt;strong&gt;9.1.0.*&lt;/strong&gt;, click on &lt;strong&gt;Select Version&lt;/strong&gt; and set the target to &lt;strong&gt;9.1.1.*&lt;/strong&gt;, as covered in the &lt;a href="https://cosmin.us/upgrading-vcf-services-runtime-to-9-1-1-step-by-step/#selecting-the-target-version"&gt;runtime walkthrough&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Clear any existing component selections, filter the list for &lt;strong&gt;sddc&lt;/strong&gt;, and select &lt;strong&gt;SDDC lifecycle&lt;/strong&gt; for the instance you want to upgrade. In my lab this is &lt;strong&gt;instance-a&lt;/strong&gt;. Make sure only the intended component is selected; the buttons should show &lt;strong&gt;Run Prechecks (1)&lt;/strong&gt; and &lt;strong&gt;Upgrade (1)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Expand &lt;strong&gt;Check Required Binaries&lt;/strong&gt; and resolve any missing binaries before proceeding. Check that the upgrade path is &lt;strong&gt;9.1.0.0400.25570103 -&amp;gt; 9.1.1.0.25713940&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/001-capture-001.webp" alt="VCF Management Upgrade page with SDDC Lifecycle selected for instance-a and the upgrade path to 9.1.1.0.25713940." width="1800" height="646" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="running-the-prechecks"&gt;Running the Prechecks&lt;/h2&gt;
&lt;p&gt;Click on &lt;strong&gt;Run Prechecks (1)&lt;/strong&gt;. The row changes to &lt;strong&gt;Prechecks in progress&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/002-capture-002.webp" alt="SDDC Lifecycle showing Prechecks in progress for the upgrade from 9.1.0.0400.25570103 to 9.1.1.0.25713940." width="1006" height="95" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Click on &lt;strong&gt;Precheck details&lt;/strong&gt; to follow the workflow. The detail view shows the precheck context being set and the SDDC Lifecycle precheck binaries being staged.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/003-capture-003.webp" alt="SDDC Lifecycle precheck workflow showing the precheck binaries being staged." width="1123" height="495" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;In my lab the precheck started at &lt;strong&gt;8:56 AM&lt;/strong&gt; and completed at &lt;strong&gt;9:11 AM&lt;/strong&gt; on September 8. The final result was &lt;strong&gt;Passed&lt;/strong&gt;, including the component package, vCenter, database upgrade, and single-component backup checks.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/004-capture-004.webp" alt="Completed SDDC Lifecycle precheck workflow with an overall Passed result and six checks passed." width="1374" height="565" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Once the prechecks pass, return to the upgrade list. The row should show &lt;strong&gt;Ready for upgrade&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/005-capture-005.webp" alt="SDDC Lifecycle ready for upgrade after the prechecks completed." width="1038" height="51" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Resolve any failed check before continuing, following Broadcom&amp;rsquo;s &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/using-the-depot-configuration-tab/upgrade-a-vcf-management-component.html"&gt;individual component upgrade procedure&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="starting-the-upgrade"&gt;Starting the Upgrade&lt;/h2&gt;
&lt;p&gt;Click on &lt;strong&gt;Upgrade&lt;/strong&gt; on the SDDC Lifecycle row.&lt;/p&gt;
&lt;p&gt;The status changes to &lt;strong&gt;Upgrade in progress&lt;/strong&gt;. Click on &lt;strong&gt;Upgrade details&lt;/strong&gt; to follow the workflow.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/006-capture-006.webp" alt="SDDC Lifecycle showing Upgrade in progress from 9.1.0.0400.25570103 to 9.1.1.0.25713940." width="1021" height="95" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The workflow sets the upgrade context, stages the SDDC Lifecycle plugin in VCF Services Runtime, runs the component prechecks, stages the package, prepares and performs the upgrade, and finishes with an inventory sync.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/007-capture-007.webp" alt="SDDC Lifecycle upgrade workflow in progress while the component prechecks run." width="1124" height="481" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Wait for the workflow to finish. If a task fails, open its details, resolve the reported issue, and retry it before moving on.&lt;/p&gt;
&lt;h2 id="verifying-the-upgrade"&gt;Verifying the Upgrade&lt;/h2&gt;
&lt;p&gt;Once the upgrade is complete, the workflow shows &lt;strong&gt;Completed&lt;/strong&gt;. In my lab all seven subtasks completed, including &lt;strong&gt;Inventory sync post SDDC lifecycle upgrade&lt;/strong&gt;. The upgrade started at &lt;strong&gt;9:15 AM&lt;/strong&gt; and finished at &lt;strong&gt;10:04 AM&lt;/strong&gt; on September 8, about &lt;strong&gt;49 minutes&lt;/strong&gt; for the full workflow.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/008-capture-008.webp" alt="Completed SDDC Lifecycle upgrade workflow with all seven subtasks completed." width="444" height="483" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;We can verify the installed version by going to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Components&lt;/strong&gt; and opening &lt;strong&gt;SDDC Lifecycle&lt;/strong&gt; for the instance.&lt;/p&gt;
&lt;p&gt;Under &lt;strong&gt;Summary&lt;/strong&gt;, check that the status is &lt;strong&gt;Running&lt;/strong&gt; and the version is &lt;strong&gt;9.1.1.0.25713940&lt;/strong&gt;. Also confirm that it is managed by the expected VCF Services Runtime instance.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-sddc-lifecycle-9-1-1-upgrade/009-capture-009.webp" alt="SDDC Lifecycle Summary showing Running status, version 9.1.1.0.25713940, and management by VCF Services Runtime." width="488" height="525" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;One known issue to keep in mind: if you plan to scale VCF Services Runtime from &lt;strong&gt;Small&lt;/strong&gt; to &lt;strong&gt;Small (High Availability)&lt;/strong&gt;, upgrade &lt;strong&gt;SDDC Lifecycle to 9.1.1&lt;/strong&gt; before doing that. The &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;VCF Operations 9.1.1 release notes&lt;/a&gt; document a failure when Fleet Lifecycle is on 9.1.1 while SDDC Lifecycle is still on 9.1.0.&lt;/p&gt;
&lt;p&gt;SDDC Lifecycle in my lab is now on &lt;strong&gt;9.1.1&lt;/strong&gt;. We can continue with the remaining management components, following the release-specific dependencies above.&lt;/p&gt;
&lt;!-- Editorial review, 2026-09-08:
The supplied manifest identifies this as "VCF 9.1.1 SDDC lifecycle upgrade"; all nine
captures show SDDC Lifecycle. Captures are used as supplied, with no visual edits.
The lab evidence establishes the source and target builds, precheck progress and
pass result, upgrade progress and completion, workflow duration, and final Running
status. It does not establish backup completion or service downtime.
Official Broadcom release notes and lifecycle-management documentation were reviewed
on September 8, 2026. The generic component procedure requires one upgrade operation
at a time; release-specific patch guidance still governs any parallel work.
The previous URL is retained as a permanent redirect in static/_redirects because
the draft was initially named for Software Depot before the screenshot component was
confirmed.
--&gt;</content:encoded></item><item><title>Upgrading VCF Services Runtime to 9.1.1 Step by Step</title><link>https://cosmin.us/upgrading-vcf-services-runtime-to-9-1-1-step-by-step/</link><pubDate>Mon, 07 Sep 2026 18:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/upgrading-vcf-services-runtime-to-9-1-1-step-by-step/</guid><description>&lt;p&gt;With Fleet Lifecycle upgraded to 9.1.1, the next component I wanted to upgrade in my lab was VCF Services Runtime. In this post I will go over upgrading it from &lt;strong&gt;9.1.0.0200&lt;/strong&gt; to &lt;strong&gt;9.1.1.0&lt;/strong&gt; through VCF Operations.&lt;/p&gt;
&lt;p&gt;VCF 9.1.1 was released on September 3, 2026. The release notes can be found &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;. The runtime fixes listed in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;VCF Operations release notes&lt;/a&gt; include improvements for mixed-case FQDNs, services recovering after a cluster power-on, and log buffers filling the logging disk.&lt;/p&gt;</description><content:encoded>&lt;p&gt;With Fleet Lifecycle upgraded to 9.1.1, the next component I wanted to upgrade in my lab was VCF Services Runtime. In this post I will go over upgrading it from &lt;strong&gt;9.1.0.0200&lt;/strong&gt; to &lt;strong&gt;9.1.1.0&lt;/strong&gt; through VCF Operations.&lt;/p&gt;
&lt;p&gt;VCF 9.1.1 was released on September 3, 2026. The release notes can be found &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;. The runtime fixes listed in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;VCF Operations release notes&lt;/a&gt; include improvements for mixed-case FQDNs, services recovering after a cluster power-on, and log buffers filling the logging disk.&lt;/p&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;p&gt;For an existing &lt;strong&gt;9.1.0.x&lt;/strong&gt; environment, upgrade &lt;strong&gt;Fleet Lifecycle to 9.1.1 first&lt;/strong&gt;, before any other VCF component. Broadcom also requires the hosting runtime to be upgraded before the dependent Identity Broker and Salt RaaS upgrades to 9.1.1. The release-specific order is documented &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/using-the-depot-configuration-tab.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before starting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify that an external SFTP backup location is configured and reachable under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Backup &amp;amp; Restore&lt;/strong&gt;. This is a prerequisite for patching VCF management services. Check the configuration status and keep the encryption passphrase available for a restore. The configuration steps are &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation/configure-sftp-backup-target-in-vmware-cloud-foundation-operations.html"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Take an &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation/backup-vcf-automation.html"&gt;on-demand backup&lt;/a&gt; before the upgrade. Go to &lt;strong&gt;Backup &amp;amp; Restore -&amp;gt; Backup -&amp;gt; Backup Now&lt;/strong&gt;, select the VCF instance and component, and verify that the backup completes. Include the runtime and the hosted services that support backup in your recovery plan. Broadcom lists the runtime&amp;rsquo;s file-based backup as covering &lt;strong&gt;service accounts only&lt;/strong&gt;; it does not replace the individual service backups. Review the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/fleet-management/backup-and-restore-of-cloud-foundation.html"&gt;supported backup methods&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Check the runtime and hosted-service health before starting, including node CPU, memory, and disk utilization. Plan a maintenance window: hosted services can restart during maintenance. Broadcom describes these checks in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/infrastructure-operations/using-vcf-operations-diagnostics/monitor-your-environment-and-prevent-issues-with-vcf-health/vcf-management-services-metrics-and-health-in-vcf-diagnostics.html"&gt;VCF Management Services health documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure the required binaries are available through the assigned software depot. For offline or disconnected environments, prepare them with the VCF Download Tool using the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/binary-management-for-vmware-cloud-foundation.html"&gt;binary management documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this walkthrough we will upgrade one runtime instance and let it finish before starting another management-service operation. If VCF Operations itself is being patched, wait for that patch to complete first, as the banner in the screenshot below instructs. Also wait for any Software Depot patch to finish so the upgrade binaries are available.&lt;/p&gt;
&lt;p&gt;Here are the versions from my lab:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;Before&lt;/th&gt;
					&lt;th&gt;After&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Services Runtime&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25555874&lt;/td&gt;
					&lt;td&gt;9.1.1.0.25714471&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Fleet Lifecycle was already on &lt;strong&gt;9.1.1.0.25713934&lt;/strong&gt;. Both 9.1.1 build numbers match the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vmware-cloud-foundation-9-1-1-0-bill-of-material.html"&gt;VCF 9.1.1 Bill of Materials&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="selecting-the-target-version"&gt;Selecting the Target Version&lt;/h2&gt;
&lt;p&gt;To get started, log in to VCF Operations with an Administrator account and go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We can see that Fleet Lifecycle is already upgraded, but the management components still have &lt;strong&gt;9.1.0.*&lt;/strong&gt; selected as the target. If the new release is not available, use &lt;strong&gt;Sync&lt;/strong&gt; to refresh the lifecycle metadata and wait for the task to complete.&lt;/p&gt;
&lt;p&gt;Under &lt;strong&gt;Management Components&lt;/strong&gt;, click on &lt;strong&gt;Select Version&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/001-capture-001.webp" alt="VCF Management Upgrade page showing Fleet Lifecycle at 9.1.1.0.25713934 and the management component target still set to 9.1.0.*." width="1186" height="508" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;Set Target Version&lt;/strong&gt; dialog, select &lt;strong&gt;9.1.1.*&lt;/strong&gt; from the &lt;strong&gt;VCF global version&lt;/strong&gt; drop-down and click on &lt;strong&gt;Set Version&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Please note that this target applies to management components across all VCF instances. Setting the target does not start the upgrades; we still need to select the component to upgrade.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/003-capture-003.webp" alt="Set Target Version dialog with VCF global version 9.1.1.* selected and the Set Version button enabled." width="1022" height="272" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="running-the-runtime-prechecks"&gt;Running the Runtime Prechecks&lt;/h2&gt;
&lt;p&gt;Clear any existing component selections, then filter the list for &lt;strong&gt;runtime&lt;/strong&gt; and select the &lt;strong&gt;VCF services runtime&lt;/strong&gt; row for the instance you want to upgrade. In my lab this is &lt;strong&gt;instance-a&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Make sure only the intended runtime is selected. The buttons should show &lt;strong&gt;Run Prechecks (1)&lt;/strong&gt; and &lt;strong&gt;Upgrade (1)&lt;/strong&gt;. Check that the upgrade path is &lt;strong&gt;9.1.0.0200.25555874 -&amp;gt; 9.1.1.0.25714471&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Expand &lt;strong&gt;Check Required Binaries&lt;/strong&gt; and confirm that the required binaries are available. Resolve any missing binaries before proceeding.&lt;/p&gt;
&lt;p&gt;Click on &lt;strong&gt;Run Prechecks (1)&lt;/strong&gt;. Once the task completes, review &lt;strong&gt;Precheck details&lt;/strong&gt; and resolve any errors before starting the upgrade, following the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/using-the-depot-configuration-tab/upgrade-a-vcf-management-component.html"&gt;individual component upgrade procedure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here we can see the runtime row showing &lt;strong&gt;Ready for upgrade&lt;/strong&gt;, with the &lt;strong&gt;Precheck details&lt;/strong&gt; link available.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/005-capture-005.webp" alt="VCF Services Runtime selected for instance-a, with the upgrade path to 9.1.1.0.25714471, Ready for upgrade status, and Precheck details link." width="1800" height="645" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="starting-the-upgrade"&gt;Starting the Upgrade&lt;/h2&gt;
&lt;p&gt;Once the prechecks have completed successfully, click on &lt;strong&gt;Upgrade&lt;/strong&gt; on the runtime row.&lt;/p&gt;
&lt;p&gt;The status changes to &lt;strong&gt;Upgrade in progress&lt;/strong&gt;. We can follow the progress by clicking on &lt;strong&gt;Upgrade details&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/006-capture-006.webp" alt="VCF Services Runtime row showing Upgrade in progress from 9.1.0.0200.25555874 to 9.1.1.0.25714471." width="955" height="58" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The workflow starts by setting the runtime upgrade context and staging the runtime plugin. In this capture we can see &lt;strong&gt;Staging binaries&lt;/strong&gt; followed by &lt;strong&gt;Running Component Stage Prechecks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/007-capture-007.webp" alt="VCF Services Runtime upgrade workflow in progress, with the plugin staging subtask displaying binary staging and component stage precheck messages." width="1376" height="656" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;We now have to wait for the workflow to finish. It continues through runtime prechecks, package staging, upgrade preparation, the upgrade itself, and the final inventory sync.&lt;/p&gt;
&lt;p&gt;If a task fails, open its details and resolve the reported issue before retrying. The &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;9.1.1 known issues&lt;/a&gt; also explain that a completed workflow can retain failed subtask attempts after successful retries. Review the final task status and component health when checking the result.&lt;/p&gt;
&lt;h2 id="verifying-the-upgrade"&gt;Verifying the Upgrade&lt;/h2&gt;
&lt;p&gt;Once the upgrade is complete, the workflow shows &lt;strong&gt;Completed&lt;/strong&gt;. The final &lt;strong&gt;Inventory sync post VCF services runtime upgrade&lt;/strong&gt; subtask also shows &lt;strong&gt;Completed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In my lab the workflow started at &lt;strong&gt;9:01 AM&lt;/strong&gt; and completed at &lt;strong&gt;2:46 PM&lt;/strong&gt; on September 7, about &lt;strong&gt;5 hours and 45 minutes&lt;/strong&gt;. This is the total workflow time shown in my task, not a measurement of service downtime. Allow for your environment to take a different amount of time.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/008-capture-008.webp" alt="Completed VCF Services Runtime upgrade workflow, with a 9:01 AM start, 2:46 PM completion, and completed final inventory sync." width="1358" height="554" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;We can verify the installed version by going to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Components&lt;/strong&gt; and opening &lt;strong&gt;VCF Services Runtime&lt;/strong&gt; for the instance.&lt;/p&gt;
&lt;p&gt;Under &lt;strong&gt;Summary&lt;/strong&gt;, check that the status is &lt;strong&gt;Running&lt;/strong&gt; and the version is &lt;strong&gt;9.1.1.0.25714471&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-services-runtime-9-1-1-upgrade/009-capture-009.webp" alt="VCF Services Runtime Summary showing Running status, version 9.1.1.0.25714471, and Small size after the upgrade." width="542" height="741" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Before moving on, open &lt;strong&gt;Services runtime health&lt;/strong&gt; and check the nodes and hosted services for outstanding health issues. Verify the services you use, such as sign-in, log collection, and lifecycle operations, and confirm that backups are still working.&lt;/p&gt;
&lt;p&gt;The runtime in my lab is now on &lt;strong&gt;9.1.1&lt;/strong&gt;. We can continue with the remaining management components, following the release-specific dependencies above. Upgrading the runtime does not by itself confirm that every hosted component is on 9.1.1; check each component&amp;rsquo;s version separately.&lt;/p&gt;
&lt;!-- Editorial review, 2026-09-07:
Sources verified directly in Broadcom TechDocs, including the September 4 release-note updates.
All nine supplied PNGs have unique SHA-256 hashes. Captures 002 (open version menu)
and 004 (cropped list with ten components selected) were omitted as redundant.
The seven included screenshots are losslessly encoded copies, without visual edits.
The lab screenshots establish the source/target builds, completed workflow, duration,
and final Running status. They do not establish backup success, detailed precheck
results, full post-upgrade health, or duration of service unavailability.
The Fleet Lifecycle predecessor is currently draft: true. Its opening link was
removed for publication; restore the link once that article is published.
The generic individual-component documentation prohibits parallel operations, while
the 9.1.1 release notes permit them subject to dependencies. This walkthrough uses
one runtime at a time and preserves the VCF Operations isolation warning shown in
the supplied UI, without claiming a universal mandatory order for all components.
--&gt;</content:encoded></item><item><title>Upgrading VCF Operations to 9.1.1 Using a .PAK File</title><link>https://cosmin.us/upgrading-vcf-operations-to-9-1-1-using-a-pak-file/</link><pubDate>Thu, 03 Sep 2026 06:50:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/upgrading-vcf-operations-to-9-1-1-using-a-pak-file/</guid><description>&lt;p&gt;With the release of VMware Cloud Foundation 9.1.1 on September 3, 2026, I wanted to get my VCF Operations lab upgraded. This is a maintenance release focused mostly on supportability improvements. The VCF 9.1.1 release notes can be found &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;, and the VCF Operations release notes are &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post I will go over upgrading VCF Operations from 9.1.0.0400 to 9.1.1 using the upgrade PAK file. If you are still on an older release, I also covered &lt;a href="https://cosmin.us/upgrading-vcf-operations-to-9-0-1-using-a-pak-file/"&gt;upgrading VCF Operations to 9.0.1 using a PAK file&lt;/a&gt;. That is a separate walkthrough, not a required intermediate upgrade.&lt;/p&gt;</description><content:encoded>&lt;p&gt;With the release of VMware Cloud Foundation 9.1.1 on September 3, 2026, I wanted to get my VCF Operations lab upgraded. This is a maintenance release focused mostly on supportability improvements. The VCF 9.1.1 release notes can be found &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;, and the VCF Operations release notes are &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-1-0-release-notes/vcfoperations-9-1-1-0-release-notes.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post I will go over upgrading VCF Operations from 9.1.0.0400 to 9.1.1 using the upgrade PAK file. If you are still on an older release, I also covered &lt;a href="https://cosmin.us/upgrading-vcf-operations-to-9-0-1-using-a-pak-file/"&gt;upgrading VCF Operations to 9.0.1 using a PAK file&lt;/a&gt;. That is a separate walkthrough, not a required intermediate upgrade.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Broadcom &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/upgrading-cloud-foundation/upgrade-backup-and-restore/install-a-software-update.html"&gt;does not recommend using the PAK method for maintenance upgrades&lt;/a&gt; in a fleet-managed VCF 9.1.0.x environment. In that case, upgrade Fleet Lifecycle to 9.1.1 first and use &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;. I used the manual PAK workflow in my lab, and this post only covers the VCF Operations appliance. The screenshots document that lab result; they are not a replacement for the official component order or evidence that Fleet Lifecycle can be skipped. The PAK method remains the documented path when upgrading from Aria Operations 8.x or VCF Operations 9.0.x to 9.1.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="what-is-new-in-vcf-operations-911"&gt;What Is New in VCF Operations 9.1.1&lt;/h2&gt;
&lt;p&gt;A few changes in this release stood out to me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SDDC Manager log collection can now be managed from VCF Operations.&lt;/li&gt;
&lt;li&gt;A network proxy can be configured when deploying a new cloud proxy from the OVA.&lt;/li&gt;
&lt;li&gt;The VMware Salt for VCF Components API is now available for managing configuration across VCF components.&lt;/li&gt;
&lt;li&gt;Active Directory lookup, password management, and certificate management now cover more users, accounts, and VCF components.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The release also fixes problems with mixed-case FQDNs during upgrade operations, the UI not loading when NTP is out of sync, services not recovering after a cluster power-on, and log buffers filling the logging disk. Broadcom also published a separate &lt;a href="https://techdocs.broadcom.com/content/dam/broadcom/techdocs/us/en/assets/vmware-cis/vcf-ops/VCF_Operations_9.1.1.0_Fixed%20_CVEs.xlsx"&gt;VCF Operations 9.1.1 fixed-CVE workbook&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="versions-used-in-this-upgrade"&gt;Versions Used in This Upgrade&lt;/h2&gt;
&lt;p&gt;The PAK file and the VCF Operations node use different build numbers. This is expected.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Item&lt;/th&gt;
					&lt;th&gt;Before&lt;/th&gt;
					&lt;th&gt;After&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Installed update package&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25541550&lt;/td&gt;
					&lt;td&gt;9.1.1.0.25679887&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Operations node&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25541561&lt;/td&gt;
					&lt;td&gt;9.1.1.0.25679751&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In my case the PAK file was &lt;code&gt;Operations-Upgrade-9.1.1.0.25679887.pak&lt;/code&gt;, and the download was 7.03 GB.&lt;/p&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;p&gt;Before starting the upgrade:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review the release notes and verify the supported upgrade path.&lt;/li&gt;
&lt;li&gt;Confirm that every VCF Operations node is online and healthy and that DNS and NTP are working correctly.&lt;/li&gt;
&lt;li&gt;Run the pre-upgrade assessment and review the results.&lt;/li&gt;
&lt;li&gt;Back up any customized content that you need to preserve.&lt;/li&gt;
&lt;li&gt;Take the VCF Operations cluster offline and snapshot every cluster node without virtual machine memory and without quiescing the guest file system. Broadcom documents the full process &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/upgrading-cloud-foundation/upgrade-backup-and-restore/create-a-snapshot.html"&gt;here&lt;/a&gt;. Bring the cluster online again before starting the upgrade.&lt;/li&gt;
&lt;li&gt;Plan for downtime. The VCF Operations cluster restarts and remains unavailable during the update.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There is a known 9.1.1 issue where the Management Pack compatibility precheck can show raw resource keys and JSON. If that happens, download the APUAT support-bundle HTML report from the same precheck run to see the readable results.&lt;/p&gt;
&lt;h2 id="downloading-the-upgrade-pak"&gt;Downloading the Upgrade PAK&lt;/h2&gt;
&lt;p&gt;To get started, log in to the &lt;a href="https://support.broadcom.com"&gt;Broadcom Support Portal&lt;/a&gt; and go to &lt;strong&gt;My Downloads -&amp;gt; VMware Cloud Foundation -&amp;gt; VMware Cloud Foundation 9 -&amp;gt; 9.1.1.0&lt;/strong&gt;. Under &lt;strong&gt;VCF Operations&lt;/strong&gt;, click &lt;strong&gt;View Group&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/001-capture-001.webp" alt="Broadcom download portal row showing VCF Operations 9.1.1.0 and packlist ID 545687." width="1800" height="61" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Read both agreements and accept the terms to enable the downloads.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/002-capture-002.webp" alt="Checked box accepting the Broadcom terms and compliance-reporting terms." width="1300" height="112" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Download &lt;code&gt;Operations-Upgrade-9.1.1.0.25679887.pak&lt;/code&gt;. The portal also provides the checksums that we can use to validate the file after the download.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/003-capture-003.webp" alt="VCF Operations 9.1.1 upgrade PAK details showing a 7.03 GB file, build 25679887, and checksums." width="1800" height="123" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="checking-the-cluster-before-the-upgrade"&gt;Checking the Cluster Before the Upgrade&lt;/h2&gt;
&lt;p&gt;Open the VCF Operations administration interface at &lt;code&gt;https://&amp;lt;primary-node-fqdn&amp;gt;/admin&lt;/code&gt; and log in with the local &lt;code&gt;admin&lt;/code&gt; account.&lt;/p&gt;
&lt;p&gt;Go to &lt;strong&gt;System Status&lt;/strong&gt; and make sure the cluster is Online and every node is Running. In my lab the starting node version was &lt;strong&gt;9.1.0.0400.25541561&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/006-capture-006.webp" alt="VCF Operations primary node running online on version 9.1.0.0400.25541561 before the upgrade." width="1800" height="75" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Go to &lt;strong&gt;Software Update&lt;/strong&gt;. The previously installed update in my lab was &lt;strong&gt;9.1.0.0400.25541550&lt;/strong&gt;. Click &lt;strong&gt;Install a Software Update&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/007-capture-007.webp" alt="VCF Operations Software Update page showing installed version 9.1.0.0400.25541550." width="1670" height="576" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="uploading-the-pak-file"&gt;Uploading the PAK File&lt;/h2&gt;
&lt;p&gt;Click &lt;strong&gt;Browse&lt;/strong&gt;, select &lt;code&gt;Operations-Upgrade-9.1.1.0.25679887.pak&lt;/code&gt;, and click &lt;strong&gt;Upload&lt;/strong&gt;. Leave &lt;strong&gt;Install the PAK file even if it is already installed&lt;/strong&gt; unchecked.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/008-capture-008.webp" alt="Add Software Update wizard with the VCF Operations 9.1.1 PAK selected and ready to upload." width="1696" height="618" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The upload can take some time because the PAK is just over 7 GB. Once it finishes, confirm that the signature is valid and that the version is &lt;strong&gt;9.1.1.0.25679887&lt;/strong&gt;, then click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/009-capture-009.webp" alt="VCF Operations wizard confirming the 9.1.1 PAK signature is valid and warning that the cluster will restart." width="1778" height="1544" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Review the End User License Agreement, select &lt;strong&gt;I accept the terms of this agreement&lt;/strong&gt;, and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/010-capture-010.webp" alt="VCF Operations update wizard with the Foundation Agreement accepted." width="1760" height="1532" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Review the update information and the software update best practices. This screen reminds us to have a backup or snapshots, run the pre-upgrade assessment, and remove the snapshots after the upgrade. Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/011-capture-011.webp" alt="VCF Operations 9.1.1 update information recommending snapshots, a pre-upgrade assessment, and snapshot removal after completion." width="1766" height="1538" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;On the last page, click &lt;strong&gt;Install&lt;/strong&gt;. The installer restarts the cluster before copying the files, and the administration interface will become unavailable for a while.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/012-capture-012.webp" alt="Final installation step warning that the VCF Operations cluster will restart before the files are copied." width="1774" height="1554" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="monitoring-the-upgrade"&gt;Monitoring the Upgrade&lt;/h2&gt;
&lt;p&gt;After the administration interface comes back, log in again and go to &lt;strong&gt;Software Update&lt;/strong&gt; to follow the progress. The workflow moves through 14 steps. In the capture below it is at &lt;strong&gt;7 of 14 - Preapply Validated&lt;/strong&gt; and is preparing for certificate renewal.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/013-capture-013.webp" alt="VCF Operations 9.1.1 installation at step 7 of 14, preparing for certificate renewal." width="1800" height="431" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Once all 14 steps complete, the status changes to &lt;strong&gt;Applied and Cleaned&lt;/strong&gt;. In my single-node lab the install took about 40 minutes after the PAK finished uploading.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/014-capture-014.webp" alt="Software Update page showing VCF Operations 9.1.1 installed with all 14 steps applied and cleaned." width="1800" height="643" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="verifying-the-upgrade"&gt;Verifying the Upgrade&lt;/h2&gt;
&lt;p&gt;Go back to &lt;strong&gt;System Status&lt;/strong&gt; and verify that the cluster is Online and every node is Running. The final node version in my lab is &lt;strong&gt;9.1.1.0.25679751&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/09/vcf-operations-9-1-1-upgrade/015-capture-015.webp" alt="VCF Operations System Status showing a successful upgrade, an online primary node, and version 9.1.1.0.25679751." width="1800" height="418" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;In the standard lifecycle workflow, cloud proxy and license server lifecycle is bundled with VCF Operations. Because this lab used the maintenance PAK route, verify both explicitly instead of assuming they were updated. The 9.1.1 release notes list cloud proxy build &lt;strong&gt;25679891&lt;/strong&gt; and license server build &lt;strong&gt;25679819&lt;/strong&gt;. I also recommend checking that collections have resumed, integrations are healthy, dashboards load, and fresh metrics are coming in.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t forget to remove the snapshots once everything has been validated. Since we are doing an upgrade, I also strongly recommend clearing the browser cache before using the new VCF Operations version.&lt;/p&gt;
&lt;p&gt;And with that we are finished upgrading the VCF Operations cluster to 9.1.1. If this is part of a full VCF 9.1.1 upgrade, don&amp;rsquo;t forget to continue with the remaining components in the order listed in the release notes.&lt;/p&gt;</content:encoded></item><item><title>Updating ESXi with the Authenticated Broadcom Depot or an Offline Bundle</title><link>https://cosmin.us/updating-esxi-with-the-authenticated-broadcom-depot-or-an-offline-bundle/</link><pubDate>Tue, 25 Aug 2026 23:05:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/updating-esxi-with-the-authenticated-broadcom-depot-or-an-offline-bundle/</guid><description>&lt;p&gt;This is the corrected follow-up to my earlier ESXi command-line upgrade articles. The shared public VMware host-update depot used in those examples is no longer valid. Broadcom now uses customer-specific authenticated download URLs, and its current standalone command-line procedure documents an offline depot ZIP with &lt;code&gt;esxcli software profile update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The procedure and release information below were reviewed on August 25, 2026. Reopen the linked Broadcom articles during every change: depot authentication, entitlements, available profiles, release builds and support status can change.&lt;/p&gt;</description><content:encoded>&lt;p&gt;This is the corrected follow-up to my earlier ESXi command-line upgrade articles. The shared public VMware host-update depot used in those examples is no longer valid. Broadcom now uses customer-specific authenticated download URLs, and its current standalone command-line procedure documents an offline depot ZIP with &lt;code&gt;esxcli software profile update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The procedure and release information below were reviewed on August 25, 2026. Reopen the linked Broadcom articles during every change: depot authentication, entitlements, available profiles, release builds and support status can change.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scope:&lt;/strong&gt; This article is for a standalone, profile-based ESXi update when &lt;code&gt;esxcli&lt;/code&gt; is an approved lifecycle method. For a VCF-managed host, use the supported VCF lifecycle workflow. For a cluster managed with a vSphere Lifecycle Manager desired image, remediate through vLCM so the host does not drift from that image. NSX-prepared hosts have additional sequencing and kernel-module requirements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="do-not-select-a-build-merely-because-it-is-called-latest"&gt;Do Not Select a Build Merely Because It Is Called Latest&lt;/h2&gt;
&lt;p&gt;An image-profile name is an exact change target, not a moving alias. Choose the release required by the approved bill of materials, upgrade path, hardware support and product interoperability. Then copy the exact profile name reported by the selected depot.&lt;/p&gt;
&lt;p&gt;The three old examples were pinned to releases that Broadcom&amp;rsquo;s &lt;a href="https://knowledge.broadcom.com/external/article/316595/build-numbers-and-versions-of-vmware-esx.html"&gt;build-number table&lt;/a&gt; now shows as superseded:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Historical article target&lt;/th&gt;
					&lt;th&gt;What the current table shows&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;ESXi 7.0 Update 3f, build 20036589&lt;/td&gt;
					&lt;td&gt;Later ESXi 7 entries exist, through Update 3w, build 24784741. ESXi 7 reached End of General Support on October 2, 2025.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ESXi 8.0 Update 3b, build 24280767&lt;/td&gt;
					&lt;td&gt;Later releases exist in the 8.0 Update 3 train, including Update 3k, build 25595708.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ESX 9.0 GA, build 24755229&lt;/td&gt;
					&lt;td&gt;Later 9.0 releases and a separate 9.1 train exist. The table lists 9.0.2.0100 build 25595025 and 9.1.0.0200 build 25557999.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Those values describe the table on the review date; they are not recommendations and must not be copied as an automatic target. In particular, a numerically higher build in another maintenance or major-version train is not proof that it is the correct upgrade for an environment.&lt;/p&gt;
&lt;h2 id="confirm-the-lifecycle-method-and-exact-target"&gt;Confirm the Lifecycle Method and Exact Target&lt;/h2&gt;
&lt;p&gt;Before downloading or applying an image:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Confirm the supported upgrade path in the &lt;a href="https://interopmatrix.broadcom.com/"&gt;Broadcom Product Interoperability Matrix&lt;/a&gt;, including vCenter Server, NSX, vSAN and every integrated VMware product.&lt;/li&gt;
&lt;li&gt;Verify the server model, CPU, boot device, NICs, storage controllers, drivers, firmware and BIOS in the &lt;a href="https://compatibilityguide.broadcom.com/"&gt;Broadcom Compatibility Guide&lt;/a&gt;. Use the current vendor-customized image when the hardware vendor requires it.&lt;/li&gt;
&lt;li&gt;Read the target release notes and identify whether the required artifact is under &lt;strong&gt;Products&lt;/strong&gt; or &lt;strong&gt;Solutions&lt;/strong&gt; in the Broadcom Support Portal. Broadcom explains that base releases and patch releases can appear in different areas.&lt;/li&gt;
&lt;li&gt;For an NSX-prepared host, follow &lt;a href="https://knowledge.broadcom.com/external/article/312013"&gt;Broadcom KB 312013&lt;/a&gt; for the matching NSX kernel-module bundle and upgrade sequence. Do not apply a generic image and assume the NSX packages will remain correct.&lt;/li&gt;
&lt;li&gt;If the host is VCF-managed or governed by a vLCM desired image, stop using this standalone procedure and use that product&amp;rsquo;s lifecycle workflow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ESXi 7 is now a legacy, end-of-general-support release. Do not treat a newer ESXi 7 patch as a substitute for an approved migration plan. Use post-EoGS content or a downgrade only under the applicable support policy and Broadcom Support guidance.&lt;/p&gt;
&lt;h2 id="prepare-the-host"&gt;Prepare the Host&lt;/h2&gt;
&lt;p&gt;Before changing the host:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take a current ESXi configuration backup and verify the recovery path.&lt;/li&gt;
&lt;li&gt;Migrate or shut down all user VMs. Do not manually move or power off vCLS VMs unless Broadcom Support directs you to do so.&lt;/li&gt;
&lt;li&gt;Confirm the remaining cluster can satisfy the intended vSphere HA failover policy while this host is unavailable.&lt;/li&gt;
&lt;li&gt;For vSAN, confirm cluster health and object compliance, wait for active resynchronizations to finish, and select the maintenance-mode data-migration option appropriate to the storage policies and available capacity.&lt;/li&gt;
&lt;li&gt;Keep out-of-band console access available and patch one host at a time unless the validated design explicitly permits parallel remediation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enter maintenance mode from the vSphere Client and confirm it from the ESXi shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vim-cmd hostsvc/hostsummary &lt;span class="p"&gt;|&lt;/span&gt; grep inMaintenanceMode
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Continue only when the result is &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="preferred-method-use-an-offline-depot-bundle"&gt;Preferred Method: Use an Offline Depot Bundle&lt;/h2&gt;
&lt;p&gt;Broadcom&amp;rsquo;s current standalone &lt;code&gt;esxcli&lt;/code&gt; procedure uses an offline depot ZIP. Download the artifact for the exact approved release from the Broadcom Support Portal or the hardware vendor, then upload it to a datastore accessible by the host. Confirm the upload completed and retain the portal filename and release information with the change record.&lt;/p&gt;
&lt;p&gt;Set the path to the uploaded file. Replace the uppercase example components with the actual datastore, directory and filename:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OFFLINE_BUNDLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/vmfs/volumes/DATASTORE/updates/ESXI_DEPOT_BUNDLE.zip&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;List every image profile in that bundle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software sources profile list -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OFFLINE_BUNDLE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Read the target release notes to distinguish &lt;code&gt;standard&lt;/code&gt;, &lt;code&gt;no-tools&lt;/code&gt;, security-only and vendor-customized profiles. Copy one exact profile name from the command output only after confirming it matches the approved target:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TARGET_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;COPY_EXACT_PROFILE_NAME_FROM_LIST_OUTPUT&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Inspect the current host profile and perform a dry run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software profile get
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software profile update --dry-run -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OFFLINE_BUNDLE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_PROFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Treat every dependency, acceptance-level, hardware, space or package-removal message as a failed precheck until it is understood. A clean dry run is still not proof that the host will boot or rejoin the cluster successfully. Do not add &lt;code&gt;--force&lt;/code&gt;, &lt;code&gt;--no-sig-check&lt;/code&gt;, &lt;code&gt;--ok-to-remove&lt;/code&gt; or compatibility-bypass flags to make the command pass.&lt;/p&gt;
&lt;p&gt;Broadcom &lt;a href="https://knowledge.broadcom.com/external/article/344817"&gt;documents a false dry-run failure&lt;/a&gt; on ESXi 7 releases earlier than 7.0 Update 3i when a target profile contains the newer ESXio content. Do not simply ignore that failure. Move to the fixed baseline through an approved path, use the supported lifecycle workflow, or obtain Broadcom Support guidance for the exact source and target.&lt;/p&gt;
&lt;p&gt;When the dry-run result and change target have been reviewed, apply the same profile without &lt;code&gt;--dry-run&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software profile update -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OFFLINE_BUNDLE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_PROFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;profile update&lt;/code&gt; normally preserves vendor/OEM components unless they are superseded. Do not replace it with &lt;code&gt;profile install&lt;/code&gt; unless the exact upgrade documentation or Broadcom Support requires installation semantics and the planned package removals have been reviewed. Starting with ESXi 8.0 Update 2, &lt;code&gt;esxcli software vib update&lt;/code&gt; and &lt;code&gt;esxcli software vib install&lt;/code&gt; are not supported for changing the ESXi version.&lt;/p&gt;
&lt;h2 id="alternative-use-the-authenticated-broadcom-online-depot"&gt;Alternative: Use the Authenticated Broadcom Online Depot&lt;/h2&gt;
&lt;p&gt;Use the online method only when direct host access to &lt;code&gt;dl.broadcom.com&lt;/code&gt; is permitted and the change workflow accepts a customer-specific token in the depot URL. Broadcom says only a Product Administrator can generate a download token for an entitled Site ID. A newly generated token can also take a short time to become valid.&lt;/p&gt;
&lt;p&gt;Treat the token like a credential: do not publish it, add it to source control, include it in screenshots, or paste it into tickets and chat transcripts. Prefer the offline-bundle method when shell history, process arguments or logs containing the authenticated URL would violate credential-handling policy.&lt;/p&gt;
&lt;p&gt;Temporarily enable the outbound HTTP client ruleset:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli network firewall ruleset &lt;span class="nb"&gt;set&lt;/span&gt; -e &lt;span class="nb"&gt;true&lt;/span&gt; -r httpClient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Set the authenticated main-depot URL, replacing &lt;code&gt;REPLACE_WITH_DOWNLOAD_TOKEN&lt;/code&gt; with the token for the entitled Site ID:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DEPOT_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://dl.broadcom.com/REPLACE_WITH_DOWNLOAD_TOKEN/PROD/COMP/ESX_HOST/main/vmw-depot-index.xml&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;List the depot profiles and copy the exact approved profile name from the output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software sources profile list -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DEPOT_URL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TARGET_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;COPY_EXACT_PROFILE_NAME_FROM_LIST_OUTPUT&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run only the precheck first:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software profile update --dry-run -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DEPOT_URL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_PROFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the dry run succeeds and its output has been reviewed, apply the update as a separate action:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software profile update -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DEPOT_URL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_PROFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Disable the temporary firewall exception and remove the shell variables when the depot is no longer needed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli network firewall ruleset &lt;span class="nb"&gt;set&lt;/span&gt; -e &lt;span class="nb"&gt;false&lt;/span&gt; -r httpClient
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; TARGET_PROFILE DEPOT_URL
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An HTTP 401 or 403 response can indicate a wrong Site ID, insufficient entitlement, a token that has not propagated yet or a token-access problem. Validate it with &lt;a href="https://knowledge.broadcom.com/external/article/395322"&gt;Broadcom&amp;rsquo;s authenticated-download troubleshooting guide&lt;/a&gt; instead of reverting to the retired public depot. Fix proxy and certificate trust problems; do not disable TLS certificate verification.&lt;/p&gt;
&lt;h2 id="reboot-and-validate-before-exiting-maintenance-mode"&gt;Reboot and Validate Before Exiting Maintenance Mode&lt;/h2&gt;
&lt;p&gt;If the profile update reports that a reboot is required, keep the host in maintenance mode and reboot it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli system shutdown reboot -r &lt;span class="s1"&gt;&amp;#39;apply ESXi profile update&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After the host finishes booting, verify the version and active profile:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmware -vl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software profile get
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before returning the host to service, also validate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Management networking, physical NICs, DNS and host connectivity to vCenter Server.&lt;/li&gt;
&lt;li&gt;Storage adapters, paths, datastores and expected multipathing policy.&lt;/li&gt;
&lt;li&gt;vSphere HA, DRS and cluster alarms.&lt;/li&gt;
&lt;li&gt;vSAN health, object compliance and any post-reboot resynchronization.&lt;/li&gt;
&lt;li&gt;NSX transport-node, tunnel, datapath and kernel-module status when applicable.&lt;/li&gt;
&lt;li&gt;Compliance with the intended vLCM image or VCF bill of materials.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Exit maintenance mode only after these checks succeed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vim-cmd /hostsvc/maintenance_mode_exit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Disable SSH or ESXi Shell again if it was enabled only for this change.&lt;/p&gt;
&lt;h2 id="official-references"&gt;Official References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/390985"&gt;Broadcom KB 390985: upgrading, updating or patching ESXi with esxcli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/390098/vcf-authenticated-downloads-configuratio.html"&gt;Broadcom KB 390098: authenticated downloads configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/379670/how-to-disable-the-hostupdatevmwarecom-d.html"&gt;Broadcom KB 379670: the old public host-update depots are no longer valid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/414704/esxi-upgrade-using-online-depot-fails-wi.html"&gt;Broadcom KB 414704: authenticated online-depot profile operations and the offline alternative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/316595/build-numbers-and-versions-of-vmware-esx.html"&gt;Broadcom KB 316595: ESXi and ESX build numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/372545/download-latest-isos-and-patches-for-vsp.html"&gt;Broadcom KB 372545: downloading ESXi ISOs and patches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/380215"&gt;Broadcom KB 380215: use profile-based updates on ESXi 8.0 Update 2 and later&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/344817"&gt;Broadcom KB 344817: legacy ESXi 7 dry-run failure with ESXio content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/415405/end-of-general-support-for-vsphere"&gt;Broadcom KB 415405: vSphere 7 End of General Support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/312013"&gt;Broadcom KB 312013: ESXi upgrades with NSX&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Safely Removing an SDDC Manager-Deployed NSX Edge Cluster from VCF</title><link>https://cosmin.us/safely-removing-an-sddc-manager-deployed-nsx-edge-cluster-from-vcf/</link><pubDate>Tue, 25 Aug 2026 12:05:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/safely-removing-an-sddc-manager-deployed-nsx-edge-cluster-from-vcf/</guid><description>&lt;p&gt;This is the corrected follow-up to my older article about &lt;a href="https://cosmin.us/simplifying-nsx-edge-removal-in-vmware-cloud-foundation-vcf-environment/"&gt;simplifying NSX Edge removal in VCF&lt;/a&gt;. The most important correction is that the Edge Cluster Deployment Removal Tool does &lt;strong&gt;not&lt;/strong&gt; preserve everything attached to an Edge cluster. Broadcom requires added dependencies to be removed or disconnected before the cleaner runs.&lt;/p&gt;
&lt;p&gt;The procedure below is based on &lt;a href="https://knowledge.broadcom.com/external/article/316110/vcf-nsxt-edge-cluster-deployment-removal.html"&gt;Broadcom KB 316110&lt;/a&gt;, reviewed on August 25, 2026. Always reopen the KB before a change because the attachment, checksum, prerequisites, and supported releases can change.&lt;/p&gt;</description><content:encoded>&lt;p&gt;This is the corrected follow-up to my older article about &lt;a href="https://cosmin.us/simplifying-nsx-edge-removal-in-vmware-cloud-foundation-vcf-environment/"&gt;simplifying NSX Edge removal in VCF&lt;/a&gt;. The most important correction is that the Edge Cluster Deployment Removal Tool does &lt;strong&gt;not&lt;/strong&gt; preserve everything attached to an Edge cluster. Broadcom requires added dependencies to be removed or disconnected before the cleaner runs.&lt;/p&gt;
&lt;p&gt;The procedure below is based on &lt;a href="https://knowledge.broadcom.com/external/article/316110/vcf-nsxt-edge-cluster-deployment-removal.html"&gt;Broadcom KB 316110&lt;/a&gt;, reviewed on August 25, 2026. Always reopen the KB before a change because the attachment, checksum, prerequisites, and supported releases can change.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Destructive operation:&lt;/strong&gt; The cleaner removes the selected deployment&amp;rsquo;s NSX gateways, Edge cluster and node VMs, network objects, associated vCenter objects, and SDDC Manager inventory records. A successful dry run is necessary, but it is not a rollback mechanism and does not replace dependency analysis or backups.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="confirm-that-the-deployment-is-supported"&gt;Confirm That the Deployment Is Supported&lt;/h2&gt;
&lt;p&gt;Use this cleaner only for an NSX Edge cluster deployment created through one of these SDDC Manager workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Application Virtual Network (AVN) bring-up workflow.&lt;/li&gt;
&lt;li&gt;The SDDC Manager Edge Cluster Creation workflow, including the corresponding UI workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;KB 316110 describes the cleaner as intended for freshly deployed Edge clusters. Stop and open a Broadcom Support case when the deployment&amp;rsquo;s origin or current inventory association is unclear.&lt;/p&gt;
&lt;p&gt;The current cleaner also exposes a separate &lt;code&gt;--db-removal-only&lt;/code&gt; mode for a specific VCF 9.x imported-Edge inventory scenario. That mode does not perform the deployment cleanup described here and is outside this article&amp;rsquo;s scope; use it only under the current KB instructions or Broadcom Support guidance.&lt;/p&gt;
&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; use this workflow when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Edge cluster is being used by Workload Control Plane (WCP), vSphere with Tanzu, or dependent Kubernetes services.&lt;/li&gt;
&lt;li&gt;The Edge cluster was created outside the supported SDDC Manager workflows.&lt;/li&gt;
&lt;li&gt;Edge VMs, gateways, or inventory records were already deleted manually and SDDC Manager no longer matches NSX or vCenter.&lt;/li&gt;
&lt;li&gt;Fabric or logical objects created by SDDC Manager were renamed and their original names are unknown.&lt;/li&gt;
&lt;li&gt;The requested action is to shrink, migrate, or repair an active Edge cluster rather than remove the deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Manual deletion can leave SDDC Manager inventory out of sync with NSX and vCenter. Broadcom directs administrators who reach that state to open a support case rather than continue deleting objects; see &lt;a href="https://knowledge.broadcom.com/external/article/437372/remove-nsxt-edge-cluster-from-sddc-manag.html"&gt;KB 437372&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="remove-dependencies-before-running-the-cleaner"&gt;Remove Dependencies Before Running the Cleaner&lt;/h2&gt;
&lt;p&gt;Inventory everything using the Edge cluster and migrate or remove it before continuing. This includes, as applicable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added Tier-0 or Tier-1 gateway configuration.&lt;/li&gt;
&lt;li&gt;Segments linked to a Tier-1 gateway.&lt;/li&gt;
&lt;li&gt;Interfaces, services, static routes, NAT, VPN, load-balancing, DHCP, or other configuration attached above the SDDC Manager-created deployment.&lt;/li&gt;
&lt;li&gt;External Connections and Transit Gateway dependencies in applicable VCF 9.x deployments.&lt;/li&gt;
&lt;li&gt;WCP and related components, which must be removed through the supported vCenter workflow before the Edge cluster can be reconsidered for cleanup.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Revert renamed fabric or logical entities to the names assigned by the SDDC Manager deployment workflow. The cleaner has only limited ability to disconnect linked segments; do not rely on the dry run to discover or safely migrate every application dependency.&lt;/p&gt;
&lt;p&gt;Obtain approval from the network and application owners after confirming that removing the identified gateways and Edge nodes will not interrupt a service that should remain available.&lt;/p&gt;
&lt;h2 id="prepare-backups-and-recovery-access"&gt;Prepare Backups and Recovery Access&lt;/h2&gt;
&lt;p&gt;Before running a destructive cleanup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Verify a current, successful NSX file-based backup and confirm access to its passphrase and remote backup files.&lt;/li&gt;
&lt;li&gt;Follow the current VCF backup guidance for SDDC Manager. Take an SDDC Manager VM snapshot only when the Broadcom procedure or Support guidance for the specific scenario instructs you to do so, and remove it promptly after successful validation.&lt;/li&gt;
&lt;li&gt;Do not snapshot NSX Manager, Global Manager, or Edge appliances. Broadcom documents that VM snapshots of NSX appliances are unsupported and can cause database corruption or cluster instability; use the supported NSX file-based backup instead. See &lt;a href="https://knowledge.broadcom.com/external/article/433822/virtual-machine-snapshots-are-not-suppor.html"&gt;KB 433822&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Schedule a maintenance window and keep console access to SDDC Manager, NSX, and vCenter available.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="download-and-verify-the-current-tool"&gt;Download and Verify the Current Tool&lt;/h2&gt;
&lt;p&gt;Open &lt;a href="https://knowledge.broadcom.com/external/article/316110/vcf-nsxt-edge-cluster-deployment-removal.html"&gt;KB 316110&lt;/a&gt; and download its current Edge cleaner attachment. Do not reuse an older tarball or a bookmarked attachment URL.&lt;/p&gt;
&lt;p&gt;The KB publishes the filename and hashes for its current attachment and warns that the hashes change when the file changes. Copy the tarball to &lt;code&gt;/home/vcf&lt;/code&gt; on the SDDC Manager appliance, not &lt;code&gt;/tmp&lt;/code&gt;, then calculate its SHA-256 hash:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /home/vcf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sha256sum &lt;span class="s1"&gt;&amp;#39;edge_cluster_cleaner_&amp;lt;version&amp;gt;.tar.gz&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Replace &lt;code&gt;&amp;lt;version&amp;gt;&lt;/code&gt; with the exact version in the downloaded filename. Compare the entire result with the current SHA-256 value shown in KB 316110. Stop if the filename or hash does not match.&lt;/p&gt;
&lt;p&gt;Extract the verified attachment and inspect the bundled help:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tar -xzvf &lt;span class="s1"&gt;&amp;#39;edge_cluster_cleaner_&amp;lt;version&amp;gt;.tar.gz&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; cleanup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./remove_edge_cluster.sh --help
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the flags reported by the downloaded tool. If its syntax differs from the KB or this article, stop and reconcile the version before continuing.&lt;/p&gt;
&lt;h2 id="run-a-dry-run-first"&gt;Run a Dry Run First&lt;/h2&gt;
&lt;p&gt;Use the exact Edge cluster name and, when supplied, the exact workload-domain name. Use a vCenter SSO administrator for the workload domain. Do not place its password on the command line; when neither a password flag nor password environment variable is supplied, the tool prompts for it without storing it in shell history.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./remove_edge_cluster.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --cluster &lt;span class="s1"&gt;&amp;#39;&amp;lt;EDGE_CLUSTER_NAME&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --workload &lt;span class="s1"&gt;&amp;#39;&amp;lt;WORKLOAD_DOMAIN_NAME&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --user &lt;span class="s1"&gt;&amp;#39;&amp;lt;SSO_ADMIN_USER&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --dryrun &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --verbose
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--workload&lt;/code&gt; argument is optional in the documented tool, but specifying the intended domain makes the target explicit. Review the dry-run output and generated log from beginning to end. Confirm that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The tool authenticated to the intended environment.&lt;/li&gt;
&lt;li&gt;The selected Edge cluster and workload domain are correct.&lt;/li&gt;
&lt;li&gt;Every object proposed for deletion belongs to the intended deployment.&lt;/li&gt;
&lt;li&gt;No unexpected dependency, renamed object, validation failure, or inventory mismatch appears.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any check fails, do not add force or warning-suppression flags. Correct the prerequisite or open a Broadcom Support case, then repeat the dry run.&lt;/p&gt;
&lt;h2 id="run-the-live-cleanup"&gt;Run the Live Cleanup&lt;/h2&gt;
&lt;p&gt;After the dry run succeeds and the change is approved, run the same command without &lt;code&gt;--dryrun&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./remove_edge_cluster.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --cluster &lt;span class="s1"&gt;&amp;#39;&amp;lt;EDGE_CLUSTER_NAME&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --workload &lt;span class="s1"&gt;&amp;#39;&amp;lt;WORKLOAD_DOMAIN_NAME&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --user &lt;span class="s1"&gt;&amp;#39;&amp;lt;SSO_ADMIN_USER&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --verbose
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Read the warning and confirm the target interactively. Do not use &lt;code&gt;--skip-warning&lt;/code&gt; merely to make the example noninteractive. Keep the terminal connected until the cleaner finishes and retain its log with the change record.&lt;/p&gt;
&lt;p&gt;KB 316110 notes that a transient timeout can occasionally stop cleanup partway through. In that documented timeout condition, inspect the log and rerun the same cleaner invocation. If the Edge cluster was dissolved but its Edge node VMs remain, follow the KB&amp;rsquo;s specific direction to remove those residual Edge Transport Node VMs through the NSX UI. Do not improvise manual deletion for other partial states.&lt;/p&gt;
&lt;h2 id="validate-all-three-inventories"&gt;Validate All Three Inventories&lt;/h2&gt;
&lt;p&gt;After the cleaner reports success, verify the result in:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SDDC Manager:&lt;/strong&gt; the Edge deployment and its workload-domain inventory association are removed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NSX Manager:&lt;/strong&gt; the intended gateways, Edge cluster, Edge nodes, uplink segments, and SDDC Manager-created transport-zone objects are gone, with no new alarms or stale dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vCenter Server:&lt;/strong&gt; the intended Edge node VMs, port groups, and deployment resource pool are gone, while unrelated infrastructure remains present.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also test the management and workload paths that were intentionally migrated away from the removed Edge cluster. If the three inventories disagree, stop. Do not manually delete more objects to make the screens match; collect the cleaner log and support bundles and open a Broadcom Support case.&lt;/p&gt;
&lt;h2 id="what-the-cleaner-normally-removes"&gt;What the Cleaner Normally Removes&lt;/h2&gt;
&lt;p&gt;Depending on whether the deployment came from AVN bring-up or direct SDDC Manager Edge creation, KB 316110 says the cleaner normally removes some or all of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The deployment&amp;rsquo;s Tier-0 and Tier-1 gateways.&lt;/li&gt;
&lt;li&gt;The Edge cluster and Edge node VMs.&lt;/li&gt;
&lt;li&gt;Edge uplink segments and deployment-created VLAN transport zones.&lt;/li&gt;
&lt;li&gt;Deployment-created vCenter port groups and resource pool.&lt;/li&gt;
&lt;li&gt;The corresponding SDDC Manager inventory records.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That list is the reason dependency removal and a reviewed dry run come first. The cleaner is a deployment-removal tool, not an application-migration or dependency-preservation tool.&lt;/p&gt;
&lt;h2 id="official-references"&gt;Official References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/316110/vcf-nsxt-edge-cluster-deployment-removal.html"&gt;Broadcom KB 316110: VCF NSX-T Edge Cluster Deployment Removal Tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/437372/remove-nsxt-edge-cluster-from-sddc-manag.html"&gt;Broadcom KB 437372: inventory mismatch after manual Edge removal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/407767/removing-an-edge-from-nsx-fails-after-th.html"&gt;Broadcom KB 407767: remove External Connection and gateway dependencies first&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/433822/virtual-machine-snapshots-are-not-suppor.html"&gt;Broadcom KB 433822: NSX appliance VM snapshots are unsupported&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>VMSA-2025-0004: Current Remediation and Fixed Versions</title><link>https://cosmin.us/vmsa-2025-0004-current-remediation-and-fixed-versions/</link><pubDate>Tue, 25 Aug 2026 12:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/vmsa-2025-0004-current-remediation-and-fixed-versions/</guid><description>&lt;p&gt;Broadcom published &lt;strong&gt;&lt;a href="https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/25390"&gt;VMSA-2025-0004&lt;/a&gt;&lt;/strong&gt; on March 4, 2025, for three vulnerabilities affecting VMware ESXi and related desktop and cloud products. Fixed versions are available, and the advisory lists &lt;strong&gt;no workarounds&lt;/strong&gt; for any of the three vulnerabilities.&lt;/p&gt;
&lt;p&gt;The practical response is therefore straightforward: identify every affected product, move it to a fixed or later supported build using its supported update method, and verify the resulting build. Access restrictions and monitoring remain useful defense-in-depth controls, but they do not replace the update.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Broadcom published &lt;strong&gt;&lt;a href="https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/25390"&gt;VMSA-2025-0004&lt;/a&gt;&lt;/strong&gt; on March 4, 2025, for three vulnerabilities affecting VMware ESXi and related desktop and cloud products. Fixed versions are available, and the advisory lists &lt;strong&gt;no workarounds&lt;/strong&gt; for any of the three vulnerabilities.&lt;/p&gt;
&lt;p&gt;The practical response is therefore straightforward: identify every affected product, move it to a fixed or later supported build using its supported update method, and verify the resulting build. Access restrictions and monitoring remain useful defense-in-depth controls, but they do not replace the update.&lt;/p&gt;
&lt;h2 id="fixed-versions"&gt;Fixed Versions&lt;/h2&gt;
&lt;p&gt;The following table reflects Broadcom&amp;rsquo;s VMSA response matrix. Where a newer supported update is available and compatible with your environment, use that newer update rather than treating the minimum fixed build as a preferred long-term target.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Product&lt;/th&gt;
					&lt;th&gt;Affected branch&lt;/th&gt;
					&lt;th&gt;Minimum remediation listed by Broadcom&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware ESXi&lt;/td&gt;
					&lt;td&gt;8.0&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ESXi80U3d-24585383&lt;/code&gt; or &lt;code&gt;ESXi80U2d-24585300&lt;/code&gt;, depending on the maintained branch&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware ESXi&lt;/td&gt;
					&lt;td&gt;7.0 (EOGS)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ESXi70U3s-24585291&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware Workstation&lt;/td&gt;
					&lt;td&gt;17.x&lt;/td&gt;
					&lt;td&gt;17.6.3&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware Fusion&lt;/td&gt;
					&lt;td&gt;13.x&lt;/td&gt;
					&lt;td&gt;13.6.3&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware Cloud Foundation&lt;/td&gt;
					&lt;td&gt;5.x&lt;/td&gt;
					&lt;td&gt;Async patch to &lt;code&gt;ESXi80U3d-24585383&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware Cloud Foundation&lt;/td&gt;
					&lt;td&gt;4.5.x (EOGS)&lt;/td&gt;
					&lt;td&gt;Async patch to &lt;code&gt;ESXi70U3s-24585291&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware Telco Cloud Platform&lt;/td&gt;
					&lt;td&gt;5.x, 4.x, 3.x, 2.x&lt;/td&gt;
					&lt;td&gt;Follow &lt;a href="https://knowledge.broadcom.com/external/article/389385"&gt;Broadcom KB 389385&lt;/a&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMware Telco Cloud Infrastructure&lt;/td&gt;
					&lt;td&gt;3.x, 2.x&lt;/td&gt;
					&lt;td&gt;Follow &lt;a href="https://knowledge.broadcom.com/external/article/389385"&gt;Broadcom KB 389385&lt;/a&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The ESXi 7.0 and VCF 4.5.x entries record the advisory&amp;rsquo;s March 2025 minimum fixes; they are not current supported target releases. vSphere 7.0 reached End of General Support on October 2, 2025, and Broadcom&amp;rsquo;s current VCF release matrix places VCF 4.x under End of General Support. Unless a specific Extended Support agreement or Broadcom Support direction applies, plan migration to a supported release rather than stopping at those legacy builds.&lt;/p&gt;
&lt;p&gt;Cloud Foundation administrators should use the VCF async-patching procedure linked from the advisory rather than independently applying an ESXi image that has not been accounted for in the VCF bill of materials. Also confirm hardware, firmware, driver, add-on, backup, replication, and management-product interoperability before beginning a production rollout.&lt;/p&gt;
&lt;p&gt;The advisory is the source of truth if its matrix changes after this article is published.&lt;/p&gt;
&lt;h2 id="understand-the-three-vulnerabilities-correctly"&gt;Understand the Three Vulnerabilities Correctly&lt;/h2&gt;
&lt;p&gt;These vulnerabilities are related, but they do not all provide the same capability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-22224 — VMCI heap overflow:&lt;/strong&gt; A malicious actor with local administrative privileges inside a VM may execute code as that VM&amp;rsquo;s &lt;strong&gt;VMX process&lt;/strong&gt; on the host. Broadcom rates it Critical with a maximum CVSSv3 score of 9.3.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-22225 — ESXi arbitrary write:&lt;/strong&gt; An actor who already has privileges within the VMX process may trigger an arbitrary kernel write and escape the &lt;strong&gt;VMX sandbox&lt;/strong&gt;. Broadcom rates it Important with a maximum CVSSv3 score of 8.2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-22226 — HGFS information disclosure:&lt;/strong&gt; An actor with administrative privileges inside a VM may exploit an out-of-bounds read to disclose memory from the VMX process. Broadcom rates it Important with a maximum CVSSv3 score of 7.1.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This distinction matters. CVE-2025-22224 provides code execution in the VMX process; it should not be described by itself as complete host takeover. CVE-2025-22225 is the sandbox-escape step described by the advisory. CVE-2025-22226 is an information-disclosure issue, not a code-execution issue.&lt;/p&gt;
&lt;p&gt;Broadcom&amp;rsquo;s current advisory states that it has information suggesting exploitation of all three CVEs has occurred in the wild.&lt;/p&gt;
&lt;h2 id="recommended-remediation-workflow"&gt;Recommended Remediation Workflow&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Inventory the affected products and exact builds.&lt;/strong&gt; Include standalone ESXi, VCF-managed hosts, Workstation, Fusion, and applicable Telco products.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compare each build with the current advisory.&lt;/strong&gt; Do not rely only on a scanner&amp;rsquo;s advisory title; confirm the installed build against the response matrix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plan the supported update path.&lt;/strong&gt; Check compatibility and product-specific prerequisites. For VCF, use the documented async-patching workflow referenced by Broadcom.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protect recoverability.&lt;/strong&gt; Confirm that current configuration backups and workload recovery plans are usable before changing production infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evacuate and maintain hosts correctly.&lt;/strong&gt; For clustered ESXi hosts, migrate or shut down workloads as appropriate and place each host into maintenance mode before applying its supported lifecycle operation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apply the fixed or a later supported build.&lt;/strong&gt; There is no Broadcom workaround that substitutes for this step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify the result.&lt;/strong&gt; Confirm the reported build, cluster health, management connectivity, storage and network health, and workload availability before returning the host to service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continue monitoring.&lt;/strong&gt; Review security telemetry and incident-response data for activity that predates remediation; applying the fixes blocks these vulnerable code paths but does not prove that earlier exploitation did not occur.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="no-workaround-means-no-equivalent-configuration-fix"&gt;No Workaround Means No Equivalent Configuration Fix&lt;/h2&gt;
&lt;p&gt;Broadcom lists &lt;strong&gt;None&lt;/strong&gt; in the Workarounds column for CVE-2025-22224, CVE-2025-22225, and CVE-2025-22226. Restricting administrative access inside VMs, segmenting management networks, and monitoring hosts are sensible controls, but they do not remove the vulnerable code and should not be presented as equivalent remediation.&lt;/p&gt;
&lt;h2 id="historical-context"&gt;Historical Context&lt;/h2&gt;
&lt;p&gt;My original March 2025 article described the initial urgency correctly but incorrectly stated that patches were not yet available. Broadcom&amp;rsquo;s initial advisory already included fixed versions. I have corrected the original article and retained it as historical context, while this page provides the current remediation-first guidance.&lt;/p&gt;
&lt;h2 id="official-references"&gt;Official References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://support.broadcom.com/web/ecx/support-content-notification/-/external/content/SecurityAdvisories/0/25390"&gt;VMSA-2025-0004 security advisory and response matrix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://brcm.tech/vmsa-2025-0004"&gt;VMSA-2025-0004 supplemental FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article?legacyId=88287"&gt;VCF asynchronous patching guidance referenced by the advisory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/389385"&gt;Telco Cloud remediation guidance, KB 389385&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/415405/end-of-general-support-for-vsphere.html"&gt;Broadcom KB 415405: vSphere 7.0 End of General Support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/314608/"&gt;Broadcom KB 314608: current and EOGS VCF releases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Safely Removing Stale NSX VIBs from an ESXi Host</title><link>https://cosmin.us/safely-removing-stale-nsx-vibs-from-an-esxi-host/</link><pubDate>Tue, 25 Aug 2026 09:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/safely-removing-stale-nsx-vibs-from-an-esxi-host/</guid><description>&lt;p&gt;This post replaces the unsafe package-removal command that appeared in my older article about &lt;a href="https://cosmin.us/removing-nsx-stale-packages-from-esxi-host/"&gt;removing stale NSX packages from an ESXi host&lt;/a&gt;. Broadcom now documents a clear distinction between removing NSX through its management workflow and cleaning up VIBs that remain afterward.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Do not manually remove individual NSX VIBs with &lt;code&gt;esxcli software vib remove&lt;/code&gt;. Broadcom identifies that method as unsupported. It can break distributed-switch state, disconnect host networking, and in some failure cases leave reimaging as the recovery path.&lt;/p&gt;</description><content:encoded>&lt;p&gt;This post replaces the unsafe package-removal command that appeared in my older article about &lt;a href="https://cosmin.us/removing-nsx-stale-packages-from-esxi-host/"&gt;removing stale NSX packages from an ESXi host&lt;/a&gt;. Broadcom now documents a clear distinction between removing NSX through its management workflow and cleaning up VIBs that remain afterward.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Do not manually remove individual NSX VIBs with &lt;code&gt;esxcli software vib remove&lt;/code&gt;. Broadcom identifies that method as unsupported. It can break distributed-switch state, disconnect host networking, and in some failure cases leave reimaging as the recovery path.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="when-this-procedure-applies"&gt;When This Procedure Applies&lt;/h2&gt;
&lt;p&gt;Use this workflow for the documented stale-package condition: NSX has already been removed from the host through NSX Manager, or the host has been removed from NSX Manager, but NSX VIBs remain on ESXi. One example is the dependency error covered by &lt;a href="https://knowledge.broadcom.com/external/article/409544"&gt;Broadcom KB 409544&lt;/a&gt;, where &lt;code&gt;vsipfwlib&lt;/code&gt; remains dependent on &lt;code&gt;nsx-proto2-libs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is not a shortcut for dismantling an active transport node. If NSX Manager still shows the host as configured, if workloads or VMkernel adapters still depend on NSX-backed networking, or if the supported removal command reports attached resources, resolve those dependencies before continuing. Do not bypass the command&amp;rsquo;s safety checks by deleting individual VIBs.&lt;/p&gt;
&lt;h2 id="step-1-evacuate-the-host-and-enter-maintenance-mode"&gt;Step 1: Evacuate the Host and Enter Maintenance Mode&lt;/h2&gt;
&lt;p&gt;Before attempting either the NSX Manager removal or the stale-VIB cleanup:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Evacuate powered-on workloads from the host.&lt;/li&gt;
&lt;li&gt;Put the host into maintenance mode.&lt;/li&gt;
&lt;li&gt;Confirm that the cluster and its storage can tolerate the host being unavailable.&lt;/li&gt;
&lt;li&gt;Keep console or out-of-band management access available in case normal host networking is interrupted.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do not perform this cleanup on an in-service host.&lt;/p&gt;
&lt;h2 id="step-2-remove-or-unprepare-the-host-in-nsx-manager"&gt;Step 2: Remove or Unprepare the Host in NSX Manager&lt;/h2&gt;
&lt;p&gt;Use NSX Manager as the first removal method. Select the applicable &lt;strong&gt;Remove NSX&lt;/strong&gt; or unprepare action for the host transport node. The exact navigation label varies by NSX release. Wait for NSX Manager to report the host as &lt;strong&gt;Not Configured&lt;/strong&gt; before treating the remaining packages as stale.&lt;/p&gt;
&lt;p&gt;For one currently documented reinstall scenario, Broadcom directs administrators to go to &lt;strong&gt;System&lt;/strong&gt; &amp;gt; &lt;strong&gt;Fabric&lt;/strong&gt; &amp;gt; &lt;strong&gt;Hosts&lt;/strong&gt;, move the host out of the prepared cluster, and use &lt;strong&gt;Remove NSX&lt;/strong&gt; if it does not transition to &lt;strong&gt;Not Configured&lt;/strong&gt;. See &lt;a href="https://knowledge.broadcom.com/external/article/401684"&gt;KB 401684&lt;/a&gt; and confirm the matching procedure for your installed NSX version.&lt;/p&gt;
&lt;h2 id="step-3-confirm-which-nsx-vibs-remain"&gt;Step 3: Confirm Which NSX VIBs Remain&lt;/h2&gt;
&lt;p&gt;Log in to the ESXi shell as an authorized administrator and list the relevant packages:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software vib list &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;nsx|vsipfwlib&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Record the output for troubleshooting. If the command returns no matching packages, there are no NSX VIBs for this procedure to remove. Reconcile the host&amp;rsquo;s state in NSX Manager instead of continuing blindly.&lt;/p&gt;
&lt;h2 id="step-4-use-the-supported-nsx-removal-command"&gt;Step 4: Use the Supported NSX Removal Command&lt;/h2&gt;
&lt;p&gt;For the stale-VIB condition documented in KB 409544, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nsxcli -c del nsx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Allow the command to complete. If it fails, stop and address the reported dependency or attached-resource condition. Do not replace it with individual &lt;code&gt;esxcli software vib remove&lt;/code&gt; commands. Broadcom&amp;rsquo;s &lt;a href="https://knowledge.broadcom.com/external/article/426464/esx-host-loses-network-connectivity-afte.html"&gt;KB 426464&lt;/a&gt; explicitly says to correct the condition causing &lt;code&gt;del nsx&lt;/code&gt; to fail rather than using the unsupported ESXCLI method.&lt;/p&gt;
&lt;h2 id="step-5-reboot-and-verify-the-host"&gt;Step 5: Reboot and Verify the Host&lt;/h2&gt;
&lt;p&gt;KB 409544 requires a reboot after the removal. Reboot the host while it remains in maintenance mode. After it has returned, log in and repeat the package check:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli software vib list &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;nsx|vsipfwlib&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the KB 409544 condition, the expected result is no matching NSX VIBs. Also verify that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The management interface is reachable.&lt;/li&gt;
&lt;li&gt;NSX Manager reports the host as &lt;strong&gt;Not Configured&lt;/strong&gt; if it is meant to remain unprepared.&lt;/li&gt;
&lt;li&gt;No stale NSX-backed distributed-switch resources remain associated with the host.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you intend to prepare the host again, initiate that operation from NSX Manager. Wait for the transport node to report a healthy state, then validate management connectivity, workload networking, and tunnel status before exiting maintenance mode.&lt;/p&gt;
&lt;h2 id="if-esxcli-removal-was-already-attempted"&gt;If ESXCLI Removal Was Already Attempted&lt;/h2&gt;
&lt;p&gt;If individual NSX VIBs were already removed and the host lost network connectivity, do not continue removing packages. Use console or out-of-band access and follow the recovery article that matches the symptom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/426464/esx-host-loses-network-connectivity-afte.html"&gt;KB 426464: ESX host loses network connectivity after running ESXCLI removal on NSX VIBs&lt;/a&gt; warns that affected hosts can require reimaging.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/394809/nsx-vibs-were-uninstalled-using-esxcli-c.html"&gt;KB 394809: NSX VIBs were uninstalled using ESXCLI, causing network outages&lt;/a&gt; documents a console-based recovery path and highly recommends reimaging afterward to avoid unexpected effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the host&amp;rsquo;s current state does not match either documented scenario, collect diagnostics and open a Broadcom Support case rather than combining cleanup commands from unrelated KB articles.&lt;/p&gt;
&lt;h2 id="official-references"&gt;Official References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/409544"&gt;Broadcom KB 409544: NSX VIB removal fails with a DependencyError&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/426464/esx-host-loses-network-connectivity-afte.html"&gt;Broadcom KB 426464: Network loss after unsupported NSX VIB removal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/394809/nsx-vibs-were-uninstalled-using-esxcli-c.html"&gt;Broadcom KB 394809: Recovery after ESXCLI removal causes a network outage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/401684"&gt;Broadcom KB 401684: UI-first NSX VIB removal and reinstall flow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Safely Canceling and Deleting Alerts with the VCF Operations API</title><link>https://cosmin.us/safely-canceling-and-deleting-alerts-with-the-vcf-operations-api/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/safely-canceling-and-deleting-alerts-with-the-vcf-operations-api/</guid><description>&lt;p&gt;The VCF Operations API uses different payloads for finding, canceling, and deleting alerts. Treating those operations as interchangeable can either fail validation or broaden a cleanup beyond the alerts you intended to remove.&lt;/p&gt;
&lt;p&gt;This follow-up corrects the API section in &lt;a href="https://cosmin.us/bulk-delete-alerts-in-vcf-operations-formerly-know-as-aria-operations/"&gt;Bulk Delete Alerts in VCF Operations&lt;/a&gt;. The safe sequence is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Query candidate alerts without changing them.&lt;/li&gt;
&lt;li&gt;Review every returned alert ID and account for pagination.&lt;/li&gt;
&lt;li&gt;Cancel only the approved IDs with a &lt;code&gt;uuid-values&lt;/code&gt; body.&lt;/li&gt;
&lt;li&gt;Verify those IDs are now &lt;code&gt;CANCELED&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Delete the same IDs with a direct &lt;code&gt;AlertQuery&lt;/code&gt; body.&lt;/li&gt;
&lt;li&gt;Query again to confirm that they are gone.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix or tune the alert definition first. Deleting alert history does not stop the condition from generating new alerts.&lt;/li&gt;
&lt;li&gt;Use a VCF Operations account whose application role and object scope permit the required alert operations.&lt;/li&gt;
&lt;li&gt;Take any database backup required by your change policy before a large cleanup.&lt;/li&gt;
&lt;li&gt;Start with one small batch. The API documents a default query page size of 1,000, so a single response is not proof that you found every match.&lt;/li&gt;
&lt;li&gt;Use a trusted certificate. The examples intentionally do not bypass TLS verification.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set the appliance name, create a private working directory, and read an existing session token without placing it in shell history. Store the authorization header in a mode-600 file so the token is not expanded into each &lt;code&gt;curl&lt;/code&gt; process argument, then remove it as soon as the cleanup is verified:&lt;/p&gt;</description><content:encoded>&lt;p&gt;The VCF Operations API uses different payloads for finding, canceling, and deleting alerts. Treating those operations as interchangeable can either fail validation or broaden a cleanup beyond the alerts you intended to remove.&lt;/p&gt;
&lt;p&gt;This follow-up corrects the API section in &lt;a href="https://cosmin.us/bulk-delete-alerts-in-vcf-operations-formerly-know-as-aria-operations/"&gt;Bulk Delete Alerts in VCF Operations&lt;/a&gt;. The safe sequence is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Query candidate alerts without changing them.&lt;/li&gt;
&lt;li&gt;Review every returned alert ID and account for pagination.&lt;/li&gt;
&lt;li&gt;Cancel only the approved IDs with a &lt;code&gt;uuid-values&lt;/code&gt; body.&lt;/li&gt;
&lt;li&gt;Verify those IDs are now &lt;code&gt;CANCELED&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Delete the same IDs with a direct &lt;code&gt;AlertQuery&lt;/code&gt; body.&lt;/li&gt;
&lt;li&gt;Query again to confirm that they are gone.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="before-you-begin"&gt;Before You Begin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix or tune the alert definition first. Deleting alert history does not stop the condition from generating new alerts.&lt;/li&gt;
&lt;li&gt;Use a VCF Operations account whose application role and object scope permit the required alert operations.&lt;/li&gt;
&lt;li&gt;Take any database backup required by your change policy before a large cleanup.&lt;/li&gt;
&lt;li&gt;Start with one small batch. The API documents a default query page size of 1,000, so a single response is not proof that you found every match.&lt;/li&gt;
&lt;li&gt;Use a trusted certificate. The examples intentionally do not bypass TLS verification.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set the appliance name, create a private working directory, and read an existing session token without placing it in shell history. Store the authorization header in a mode-600 file so the token is not expanded into each &lt;code&gt;curl&lt;/code&gt; process argument, then remove it as soon as the cleanup is verified:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;OPS_FQDN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ops.example.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;umask&lt;/span&gt; &lt;span class="m"&gt;077&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp -d /tmp/vcf-ops-alert-cleanup.XXXXXX&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r -s -p &lt;span class="s1"&gt;&amp;#39;VCF Operations token: &amp;#39;&lt;/span&gt; OPS_TOKEN
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Authorization: OpsToken %s\n&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;600&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; OPS_TOKEN
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Current VCF Operations API requests use this header:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Authorization: OpsToken TOKEN_VALUE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can obtain the session token from &lt;code&gt;POST /suite-api/api/auth/token/acquire&lt;/code&gt;. Do not save the token, account password, or response in a shared script or repository.&lt;/p&gt;
&lt;h2 id="step-1-query-a-narrow-candidate-set"&gt;Step 1: Query a Narrow Candidate Set&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;POST /suite-api/api/alerts/query&lt;/code&gt; with an &lt;code&gt;AlertQuery&lt;/code&gt;. Prefer an exact &lt;code&gt;alertDefinitionId&lt;/code&gt;, resource ID, or an already reviewed list of alert IDs. The &lt;code&gt;alertName&lt;/code&gt; field uses contains logic and is therefore less precise.&lt;/p&gt;
&lt;p&gt;Create a query for one exact alert definition:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;compositeOperator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AND&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;activeOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;alertDefinitionId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;11111111-2222-3333-4444-555555555555&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save that JSON as &lt;code&gt;${OPS_WORK_DIR}/alert-candidates.json&lt;/code&gt;, replace the example UUID, and query the first page:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --fail-with-body &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --request POST &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_FQDN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/alerts/query?page=0&amp;amp;pageSize=1000&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-binary @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-candidates.json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-page-0.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Review the count and identifying fields before doing anything destructive:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq &lt;span class="s1"&gt;&amp;#39;.pageInfo, [.alerts[] | {alertId, alertDefinitionId, alertDefinitionName, resourceId, status}]&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-page-0.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;pageInfo.totalCount&lt;/code&gt; exceeds the number returned, query every remaining page and review it. Keep batches small enough to audit. Never replace the query with &lt;code&gt;{}&lt;/code&gt; merely to avoid pagination.&lt;/p&gt;
&lt;h2 id="step-2-build-and-review-the-exact-cancel-list"&gt;Step 2: Build and Review the Exact Cancel List&lt;/h2&gt;
&lt;p&gt;The modify-alerts endpoint does &lt;strong&gt;not&lt;/strong&gt; accept an &lt;code&gt;AlertQuery&lt;/code&gt;. It requires a &lt;code&gt;uuid-values&lt;/code&gt; body whose only required field is the &lt;code&gt;uuids&lt;/code&gt; array.&lt;/p&gt;
&lt;p&gt;After reviewing the first batch, build the body from its returned IDs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq &lt;span class="s1"&gt;&amp;#39;{uuids: [.alerts[].alertId]}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-page-0.json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-cancel.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq . &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-cancel.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Record the approved count and retain the reviewed ID list with the change record.&lt;/p&gt;
&lt;h2 id="step-3-cancel-only-those-ids"&gt;Step 3: Cancel Only Those IDs&lt;/h2&gt;
&lt;p&gt;Cancel the exact list with &lt;code&gt;POST /suite-api/api/alerts?action=cancel&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --fail-with-body &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --request POST &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_FQDN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/alerts?action=cancel&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-binary @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-cancel.json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-cancel-response.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq &lt;span class="s1"&gt;&amp;#39;[.alerts[] | {alertId, status, cancelTimeUTC}]&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-cancel-response.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Canceling changes alert state; it does not delete the alert record.&lt;/p&gt;
&lt;h2 id="step-4-build-the-targeted-delete-query"&gt;Step 4: Build the Targeted Delete Query&lt;/h2&gt;
&lt;p&gt;The delete endpoint accepts a direct &lt;code&gt;AlertQuery&lt;/code&gt;, not an &lt;code&gt;alert-query&lt;/code&gt; wrapper. Reuse the reviewed IDs and require &lt;code&gt;CANCELED&lt;/code&gt; status:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq &lt;span class="s1"&gt;&amp;#39;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; compositeOperator: &amp;#34;AND&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; alertStatus: [&amp;#34;CANCELED&amp;#34;],
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; alertId: .uuids
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-cancel.json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-delete.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq . &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-delete.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the same body through the read-only query endpoint first:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --fail-with-body &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --request POST &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_FQDN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/alerts/query?page=0&amp;amp;pageSize=1000&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-binary @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-delete.json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-delete-preview.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq &lt;span class="s1"&gt;&amp;#39;.pageInfo, [.alerts[] | {alertId, alertDefinitionName, resourceId, status}]&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alert-delete-preview.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Stop if the preview contains an unexpected ID, definition, resource, or status. The preview count should match the reviewed cancel list for that batch.&lt;/p&gt;
&lt;h2 id="step-5-delete-and-verify"&gt;Step 5: Delete and Verify&lt;/h2&gt;
&lt;p&gt;Delete the targeted canceled alerts with &lt;code&gt;DELETE /suite-api/api/alerts/bulk&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --fail-with-body &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --request DELETE &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_FQDN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/alerts/bulk&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-binary @&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/alerts-to-delete.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The documented success response is HTTP 204 and indicates that the deletion was started. It does not return a deleted-object list. Query the exact IDs again until the API returns no matching alerts, and confirm the expected result in the UI and audit history before closing the change.&lt;/p&gt;
&lt;p&gt;Delete the temporary authorization header immediately. Retain or securely remove the reviewed JSON files according to the change-record policy, then remove the directory when it is empty:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -f -- &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPS_WORK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/authorization.header&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; OPS_TOKEN
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# After retaining or deleting the reviewed JSON files:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rmdir -- &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS_WORK_DIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; OPS_WORK_DIR
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="requests-to-avoid"&gt;Requests to Avoid&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Do not send an empty &lt;code&gt;{}&lt;/code&gt; query to the bulk-delete endpoint.&lt;/li&gt;
&lt;li&gt;Do not use only &lt;code&gt;alertStatus: [&amp;quot;CANCELED&amp;quot;]&lt;/code&gt; unless the approved scope is explicitly every canceled alert in the environment.&lt;/li&gt;
&lt;li&gt;Do not put an &lt;code&gt;AlertQuery&lt;/code&gt; inside an &lt;code&gt;alert-query&lt;/code&gt; wrapper; the endpoint expects the query fields at the JSON root.&lt;/li&gt;
&lt;li&gt;Do not send alert IDs directly to &lt;code&gt;DELETE /suite-api/api/alerts&lt;/code&gt;; the documented bulk deletion route is &lt;code&gt;/suite-api/api/alerts/bulk&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Do not assume the first 1,000 results are the complete set.&lt;/li&gt;
&lt;li&gt;Do not schedule destructive cleanup until the query, count limits, audit logging, and failure handling have been tested with a small batch.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/suite-api/api/alerts/query/post/"&gt;VCF Operations API: Query Alert&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/suite-api/api/alerts/post/"&gt;VCF Operations API: Modify Alerts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/suite-api/api/alerts/bulk/delete/"&gt;VCF Operations API: Delete Canceled Alerts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/data-structures/alert-query/"&gt;VCF Operations API: AlertQuery schema&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/api-security-schema/"&gt;VCF Operations API authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Using a 90-Day Planning Horizon Correctly in VCF Operations</title><link>https://cosmin.us/using-a-90-day-planning-horizon-correctly-in-vcf-operations/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/using-a-90-day-planning-horizon-correctly-in-vcf-operations/</guid><description>&lt;p&gt;A 90-day capacity goal can describe three different things in VCF Operations: past demand used by the projection, future warning lead time, or the future period considered by VM rightsizing. They are controlled separately.&lt;/p&gt;
&lt;p&gt;This article replaces &lt;a href="https://cosmin.us/configuring-vcf-operations-9-capacity-calculations-to-consider-90-days-of-usage/"&gt;the earlier 90-day capacity procedure&lt;/a&gt;, which incorrectly treated Time Remaining thresholds as a historical lookback setting.&lt;/p&gt;
&lt;h2 id="the-three-meanings-of-90-days"&gt;The Three Meanings of 90 Days&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Planning question&lt;/th&gt;
					&lt;th&gt;Relevant control&lt;/th&gt;
					&lt;th&gt;What it does not control&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Should the forecast consider up to 90 days of past demand?&lt;/td&gt;
					&lt;td&gt;Historical Data window, if that value is available in the installed build&lt;/td&gt;
					&lt;td&gt;Alert severity or procurement lead time&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Should an alert become critical when exhaustion is projected within 90 days?&lt;/td&gt;
					&lt;td&gt;Time Remaining criticality thresholds&lt;/td&gt;
					&lt;td&gt;Historical lookback&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Should Recommended Size cover demand projected across a 90-day future horizon?&lt;/td&gt;
					&lt;td&gt;The applicable Time Remaining warning/green threshold plus the documented 30-day extension&lt;/td&gt;
					&lt;td&gt;Past-data retention&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Changing one row does not configure the other two.&lt;/p&gt;</description><content:encoded>&lt;p&gt;A 90-day capacity goal can describe three different things in VCF Operations: past demand used by the projection, future warning lead time, or the future period considered by VM rightsizing. They are controlled separately.&lt;/p&gt;
&lt;p&gt;This article replaces &lt;a href="https://cosmin.us/configuring-vcf-operations-9-capacity-calculations-to-consider-90-days-of-usage/"&gt;the earlier 90-day capacity procedure&lt;/a&gt;, which incorrectly treated Time Remaining thresholds as a historical lookback setting.&lt;/p&gt;
&lt;h2 id="the-three-meanings-of-90-days"&gt;The Three Meanings of 90 Days&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Planning question&lt;/th&gt;
					&lt;th&gt;Relevant control&lt;/th&gt;
					&lt;th&gt;What it does not control&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Should the forecast consider up to 90 days of past demand?&lt;/td&gt;
					&lt;td&gt;Historical Data window, if that value is available in the installed build&lt;/td&gt;
					&lt;td&gt;Alert severity or procurement lead time&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Should an alert become critical when exhaustion is projected within 90 days?&lt;/td&gt;
					&lt;td&gt;Time Remaining criticality thresholds&lt;/td&gt;
					&lt;td&gt;Historical lookback&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Should Recommended Size cover demand projected across a 90-day future horizon?&lt;/td&gt;
					&lt;td&gt;The applicable Time Remaining warning/green threshold plus the documented 30-day extension&lt;/td&gt;
					&lt;td&gt;Past-data retention&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Changing one row does not configure the other two.&lt;/p&gt;
&lt;h2 id="what-the-capacity-engine-actually-does"&gt;What the Capacity Engine Actually Does&lt;/h2&gt;
&lt;p&gt;VCF Operations forecasts demand rather than simply averaging a fixed block of historical utilization. Current Broadcom guidance describes these behaviors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recent samples receive more weight through exponential decay.&lt;/li&gt;
&lt;li&gt;Conservative risk uses the upper bound of the projection range.&lt;/li&gt;
&lt;li&gt;Aggressive risk uses the mean of the upper and lower projection bounds.&lt;/li&gt;
&lt;li&gt;Peak-focused mode incorporates peaks detected in historical demand and can be combined with either risk posture.&lt;/li&gt;
&lt;li&gt;Business Hours limits the demand samples used for projection to the configured hours; it does not merely give those hours extra weight.&lt;/li&gt;
&lt;li&gt;Capacity Remaining is based on a short forward projection, while Time Remaining estimates when demand will intersect usable capacity.&lt;/li&gt;
&lt;li&gt;vSphere HA admission-control reservations reduce usable cluster capacity and can therefore change the result even when current utilization appears low.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These settings change the model&amp;rsquo;s behavior. None of them, by itself, means “use exactly 90 days of history.”&lt;/p&gt;
&lt;h2 id="before-changing-a-policy"&gt;Before Changing a Policy&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Identify the active policy on the exact cluster, VM group, or object you are evaluating.&lt;/li&gt;
&lt;li&gt;Record the existing Capacity settings and take screenshots for the change record.&lt;/li&gt;
&lt;li&gt;Confirm whether the object is using the Demand model, the optional Allocation model, or both. Do not add arbitrary allocation ratios to hide a Demand-based alert.&lt;/li&gt;
&lt;li&gt;Check vSphere HA admission control before interpreting usable capacity as missing physical capacity.&lt;/li&gt;
&lt;li&gt;Decide which 90-day outcome you actually need: historical evidence, alert lead time, VM sizing horizon, or a documented combination.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Clone an inherited policy when you need a separate production, non-production, cluster, or VM posture. Broadcom recommends separate VM policies when rightsizing settings should differ from higher-level capacity policies.&lt;/p&gt;
&lt;h2 id="goal-1-use-a-90-day-future-alert-lead-time"&gt;Goal 1: Use a 90-Day Future Alert Lead Time&lt;/h2&gt;
&lt;p&gt;If procurement must begin when capacity is projected to run out within a quarter, configure Time Remaining severity thresholds for that operational lead time.&lt;/p&gt;
&lt;p&gt;For example, an organization might choose warning at 120 days and critical at 90 days so the earlier warning leaves a 30-day intake buffer. Those numbers are governance choices, not Broadcom defaults. Keep the thresholds in a logical order, document who owns each severity, and verify how the installed version labels warning, immediate, and critical.&lt;/p&gt;
&lt;p&gt;This configuration means “alert us based on a future exhaustion date.” It does &lt;strong&gt;not&lt;/strong&gt; mean the forecast reads only the last 90 days.&lt;/p&gt;
&lt;h2 id="goal-2-use-a-90-day-vm-recommended-size-horizon"&gt;Goal 2: Use a 90-Day VM Recommended Size Horizon&lt;/h2&gt;
&lt;p&gt;Broadcom&amp;rsquo;s current rightsizing explanation states that Recommended Size considers the peak projected demand from now through 30 days beyond the Time Remaining threshold used by the policy. Its example uses a 30-day warning threshold and therefore produces a 60-day sizing horizon.&lt;/p&gt;
&lt;p&gt;Under that documented rule, a 90-day Recommended Size horizon corresponds to a 60-day applicable threshold plus the 30-day extension:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;60-day policy threshold + 30-day extension = 90-day sizing horizon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Do not set the threshold to 90 days and call the sizing horizon 90 days; that would extend the evaluated period to 120 days under the same rule. Because UI wording can differ by release, verify the resulting projection on a VM&amp;rsquo;s Capacity tab before applying the policy broadly.&lt;/p&gt;
&lt;p&gt;Use a VM-specific policy if clusters need different Time Remaining severities. Select Conservative, Aggressive, and Peak Focused according to workload risk and peak behavior, not merely to force a preferred recommendation.&lt;/p&gt;
&lt;h2 id="goal-3-consider-90-days-of-historical-demand"&gt;Goal 3: Consider 90 Days of Historical Demand&lt;/h2&gt;
&lt;p&gt;The Historical Data setting is the control associated with the model&amp;rsquo;s past-data window. Broadcom KB 437777 explicitly treats it separately from Time Remaining risk and gives an example of temporarily reducing a 30-day window to one day when an obsolete spike is distorting a forecast.&lt;/p&gt;
&lt;p&gt;To request a 90-day historical window:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Infrastructure Operations &amp;gt; Configurations &amp;gt; Policy Definition&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Edit or clone the policy that is active on the intended objects.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Capacity&lt;/strong&gt; and unlock the inherited Historical Data setting if necessary.&lt;/li&gt;
&lt;li&gt;Select 90 days only if the installed VCF Operations build exposes 90 days as a supported value.&lt;/li&gt;
&lt;li&gt;Save the policy, confirm its object assignment and precedence, and record the effective value.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the installed build does not offer a 90-day value, do not substitute a 90-day Time Remaining threshold and describe it as a lookback. Use 90-day historical charts or reports as supporting evidence, and confirm the supported forecasting-window choices for that release with Broadcom Support.&lt;/p&gt;
&lt;p&gt;Historical-data retention is also separate. Retaining a metric for reporting does not guarantee that every retained sample is used by the current projection.&lt;/p&gt;
&lt;h2 id="correcting-anomalous-history"&gt;Correcting Anomalous History&lt;/h2&gt;
&lt;p&gt;Use the Capacity view&amp;rsquo;s &lt;strong&gt;Reset&lt;/strong&gt; control when a known change or anomaly makes the current projection unrepresentative. Broadcom documents two relevant behaviors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Selecting a new projection start date causes forecasting to use data from that point forward.&lt;/li&gt;
&lt;li&gt;Selecting a start and end time for exclusion omits that interval from capacity planning and forecasting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A reset does not delete the underlying historical metric data. Charts, reports, and retained time-series data remain available.&lt;/p&gt;
&lt;p&gt;Do not assume an object maintenance schedule is a substitute for this exclusion workflow. Maintenance behavior is designed around monitoring and alert handling; use the capacity engine&amp;rsquo;s own reset or exclusion controls when the goal is to change forecasting input.&lt;/p&gt;
&lt;h2 id="recalculate-and-validate"&gt;Recalculate and Validate&lt;/h2&gt;
&lt;p&gt;Capacity forecasting runs periodically, so a policy change may not appear after one five-minute collection cycle. Broadcom KB 437777 describes two supported validation paths:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For a global recalculation, go to &lt;strong&gt;Administration &amp;gt; Control Panel &amp;gt; Dynamic Thresholds&lt;/strong&gt; and start recalculation during an approved window.&lt;/li&gt;
&lt;li&gt;For a specific cluster, open its &lt;strong&gt;Capacity&lt;/strong&gt; tab and use &lt;strong&gt;Reset&lt;/strong&gt; only when changing the projection baseline is intended.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then validate all of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The expected policy is active on the target object.&lt;/li&gt;
&lt;li&gt;The effective Historical Data value matches the approved setting.&lt;/li&gt;
&lt;li&gt;Time Remaining severity changes at the intended future thresholds.&lt;/li&gt;
&lt;li&gt;The Capacity chart shows the expected projection start point and any excluded interval.&lt;/li&gt;
&lt;li&gt;VM Recommended Size uses the intended future horizon.&lt;/li&gt;
&lt;li&gt;HA reservation and capacity buffers match the actual resilience design.&lt;/li&gt;
&lt;li&gt;Demand and Allocation models are interpreted separately, with the more constrained model understood.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Test on a small object group before broad assignment. Keep the before-and-after values with the change record so a surprising forecast can be traced to a specific policy decision.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/437777/critical-cpu-capacity-alerts-despite-low.html"&gt;Broadcom KB 437777: Critical CPU capacity alerts despite low utilization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.vmware.com/cloud-foundation/2025/08/12/vmware-cloud-foundation-helps-you-optimally-size-vms-and-keep-your-infrastructure-and-workloads-running-smoothly/"&gt;Broadcom VCF Blog: Rightsizing VMs with VMware Cloud Foundation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Deploying a VCF 9.1 Fleet with the VCF Installer</title><link>https://cosmin.us/deploying-a-vcf-9-1-fleet-with-the-vmware-cloud-foundation-installer-step-by-step-instructions/</link><pubDate>Fri, 07 Aug 2026 09:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/deploying-a-vcf-9-1-fleet-with-the-vmware-cloud-foundation-installer-step-by-step-instructions/</guid><description>&lt;p&gt;Last year, when VCF 9.0 shipped, I covered the VCF Installer in three posts: &lt;a href="https://cosmin.us/deploying-the-vmware-cloud-foundation-installer-appliance-step-by-step-instructions/"&gt;deploying the appliance&lt;/a&gt;, &lt;a href="https://cosmin.us/configuring-the-vmware-cloud-foundation-installer-appliance-step-by-step-instructions/"&gt;configuring it&lt;/a&gt;, and &lt;a href="https://cosmin.us/deploy-a-vcf-9-instance-in-an-existing-vcf-fleet/"&gt;deploying a VCF 9 instance&lt;/a&gt;. With VCF 9.1 &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes.html"&gt;generally available since May 12, 2026&lt;/a&gt;, it was time to run the whole flow again in the lab, and enough has changed that it earns a fresh walkthrough. This post covers the complete path in one go: downloading and deploying the 9.1 installer appliance, connecting the depot, downloading binaries, and deploying a new VCF fleet on top of an existing vCenter. I used the 9.1.0.0400 installer from the July 2026 refresh.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Last year, when VCF 9.0 shipped, I covered the VCF Installer in three posts: &lt;a href="https://cosmin.us/deploying-the-vmware-cloud-foundation-installer-appliance-step-by-step-instructions/"&gt;deploying the appliance&lt;/a&gt;, &lt;a href="https://cosmin.us/configuring-the-vmware-cloud-foundation-installer-appliance-step-by-step-instructions/"&gt;configuring it&lt;/a&gt;, and &lt;a href="https://cosmin.us/deploy-a-vcf-9-instance-in-an-existing-vcf-fleet/"&gt;deploying a VCF 9 instance&lt;/a&gt;. With VCF 9.1 &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes.html"&gt;generally available since May 12, 2026&lt;/a&gt;, it was time to run the whole flow again in the lab, and enough has changed that it earns a fresh walkthrough. This post covers the complete path in one go: downloading and deploying the 9.1 installer appliance, connecting the depot, downloading binaries, and deploying a new VCF fleet on top of an existing vCenter. I used the 9.1.0.0400 installer from the July 2026 refresh.&lt;/p&gt;
&lt;h2 id="what-changed-since-the-90-posts"&gt;What changed since the 9.0 posts&lt;/h2&gt;
&lt;p&gt;The overall shape is the same (deploy the OVA, connect a depot, download binaries, run the deployment wizard) but 9.1 moves a few important pieces, per the official &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/what-s-new/whats-new-installer.html"&gt;What&amp;rsquo;s New for the VCF Installer&lt;/a&gt; and the depot KBs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The download token is gone.&lt;/strong&gt; Depot authentication now uses a &lt;strong&gt;Download Service ID + Activation Code&lt;/strong&gt; obtained from the VCF Business Services console. The token flow from my 9.0 configuration post no longer applies. See &lt;a href="https://knowledge.broadcom.com/external/article/443647/download-token-has-been-replaced-by-acti.html"&gt;KB 443647&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VCF Management Services are deployed by default.&lt;/strong&gt; The installer now provisions the VCF services runtime, fleet lifecycle, identity broker, software depot, Salt RaaS, telemetry, and the centralized &lt;strong&gt;License Server&lt;/strong&gt; as part of a new deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrated planning workflow.&lt;/strong&gt; The wizard generates CPU, memory, storage, VLAN, and FQDN requirements up front and validates your infrastructure against them, including a &lt;strong&gt;Pre-fill generated FQDNs&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto-generated passwords.&lt;/strong&gt; The installer can generate the component passwords for you, retrievable after deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dual-stack support.&lt;/strong&gt; The appliance OVA now asks for an IP Address Version (IPv4 only, or IPv4 and IPv6), and existing dual-stack environments are supported, though wizard-driven deployments on an existing vCenter remain IPv4-only; dual-stack goes through a JSON spec.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lowercase FQDNs are now formalized.&lt;/strong&gt; The 9.1 planning docs state &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/planning-and-preparation/vcf-components-fqdns-and-ip-addresses/first-vcf-instance-fqdns-and-ip-addresses.html"&gt;do not use capital letters in the FQDN&lt;/a&gt;, and uppercase component FQDNs are a documented deployment-failure &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/known-issues/vcf-installer-91-known-issues.html"&gt;known issue&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="download-the-vcf-installer"&gt;Download the VCF Installer&lt;/h2&gt;
&lt;p&gt;The appliance OVA comes from the Broadcom Support Portal at &lt;a href="https://support.broadcom.com/web/ecx"&gt;support.broadcom.com&lt;/a&gt;: select the &lt;strong&gt;VMware Cloud Foundations&lt;/strong&gt; division, go to &lt;strong&gt;My Downloads&lt;/strong&gt;, and pick &lt;strong&gt;VMware Cloud Foundation 9&lt;/strong&gt; with your target release. If the portal navigation fights you, &lt;a href="https://knowledge.broadcom.com/external/article/401497/vmware-vcf-90-or-vvf-90-downloads-in-the.html"&gt;KB 401497&lt;/a&gt; walks through it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select the release. I grabbed &lt;strong&gt;9.1.0.0400&lt;/strong&gt; from the July 2026 patch wave&lt;/li&gt;
&lt;li&gt;Agree to the Terms and Conditions&lt;/li&gt;
&lt;li&gt;Download &lt;strong&gt;VCF-SDDC-Manager-Appliance-9.1.0.0400.25570100.ova&lt;/strong&gt; (2.28 GB) and verify the checksum&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/001-capture-001.webp" alt="Broadcom support portal showing the VCF Installer 9.1.0.0400 download page with the VCF-SDDC-Manager-Appliance OVA file, build number 25570100, and its SHA2 and MD5 checksums." width="1649" height="588" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="deploy-the-vcf-installer-appliance"&gt;Deploy the VCF Installer appliance&lt;/h2&gt;
&lt;p&gt;Sizing is unchanged from 9.0: 4 vCPUs, 16 GB RAM, and 914 GB storage (thin provisioning keeps that honest), per the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/preparing-your-environment/deploy-the-vmware-cloud-foundation-installer-appliance.html"&gt;official deployment page&lt;/a&gt;. The docs describe two placement options: on one of the ESX hosts that will form the management domain (the appliance is converted into SDDC Manager during deployment), or outside the management infrastructure entirely, where one appliance can deploy multiple platforms. As in the 9.0 post, I am deploying the OVA through an existing vCenter.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log in to vCenter with a user that can deploy an OVF&lt;/li&gt;
&lt;li&gt;Right click the cluster and click &lt;strong&gt;Deploy OVF Template&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/002-capture-002.webp" alt="vSphere Client actions menu on cluster mgmt-cluster-01 showing the Deploy OVF Template option." width="488" height="256" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Local file&lt;/strong&gt; and upload the installer OVA&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/003-capture-003.webp" alt="Deploy OVF Template wizard step 1 with the local file VCF-SDDC-Manager-Appliance-9.1.0.0400.25570100.ova selected." width="1148" height="610" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Give the appliance a name&lt;/li&gt;
&lt;li&gt;Select a deployment location&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/004-capture-004.webp" alt="Deploy OVF Template wizard step 2 with the VM name set and mgmt-datacenter-01 selected as the target location under vcenter-mgmt.vcf.sddc.lab." width="1143" height="607" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select a compute resource and wait for the compatibility checks&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/005-capture-005.webp" alt="Deploy OVF Template wizard step 3 with mgmt-cluster-01 selected and compatibility checks succeeded." width="1143" height="601" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review the deployment details, note the 914 GB thick footprint vs 4.2 GB thin&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/006-capture-006.webp" alt="Review details step of the Deploy OVF Template wizard showing VMware VCF SDDC Manager Appliance version 9.1.0.0400." width="1141" height="609" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read and accept the license agreements&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/007-capture-007.webp" alt="License agreements step of the Deploy OVF Template wizard with the Broadcom Foundation Agreement accepted." width="1144" height="600" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select a datastore for the deployment&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/008-capture-008.webp" alt="Select storage step of the Deploy OVF Template wizard with the vcf-vsan datastore selected and compatibility checks succeeded." width="1149" height="608" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select the destination network: the appliance needs to reach the ESX hosts, the VM management network, DNS, and NTP&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/009-capture-009.webp" alt="Select networks step of the Deploy OVF Template wizard mapping Network 1 to the sddc-vds01-mgmt port group with static IPv4 allocation." width="1143" height="605" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fill in the template customization: root and local user passwords (minimum 15 characters with the usual complexity rules; the local password is what you will use for &lt;strong&gt;admin@local&lt;/strong&gt; in the UI and &lt;strong&gt;vcf&lt;/strong&gt; over SSH), hostname, networking, DNS, and NTP&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is also where 9.1 differs from 9.0: the networking section now starts with an &lt;strong&gt;IP Address Version&lt;/strong&gt; selector, with IPv6 address, prefix length, and gateway fields if you go dual-stack.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/010-capture-010.webp" alt="Customize template step of the Deploy OVF Template wizard with masked root and local user password fields for the VCF Installer appliance." width="1142" height="610" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review the summary&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Finish&lt;/strong&gt; and wait for the deployment to complete&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/011-capture-011.webp" alt="Ready to complete summary of the Deploy OVF Template wizard for the VCF-SDDC-Manager-Appliance-9.1.0.0400.25570100 OVA." width="1146" height="608" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="log-in-and-connect-the-depot"&gt;Log in and connect the depot&lt;/h2&gt;
&lt;p&gt;Once the appliance is up, navigate to https://ip_address/ui or https://hostname/ui. Same as 9.0, the services take a few minutes to start after first boot.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For username use &lt;strong&gt;admin@local&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Enter the local user password from the OVA deployment&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Log in&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/012-capture-012.webp" alt="VMware Cloud Foundation Installer login page with admin@local entered as the username." width="577" height="668" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Get Started page opens with the Download Binaries card flagging &lt;strong&gt;No Depot Connection&lt;/strong&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Depot Settings and Binary Management&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/013-capture-013.webp" alt="The VCF Installer Get Started page with the Download Binaries card showing a No Depot Connection warning." width="586" height="327" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Both depot types are available: online (direct or via proxy) and offline, fed by the VCF Download Tool, only one can be connected at a time. For air-gapped environments the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/preparing-your-environment/downloading-binaries-to-the-vcf-installer-appliance/download-install-binaries-to-an-offline-depot.html"&gt;official offline depot procedure&lt;/a&gt; covers the Download Tool flow; William Lam also documented the new &lt;a href="https://williamlam.com/2026/05/vcf-9-1-new-http-offline-depot-support-for-vcf-installer-fleet-depot-service.html"&gt;HTTP offline depot support in 9.1&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Configure&lt;/strong&gt; under the &lt;strong&gt;Online Depot&lt;/strong&gt; tile&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/014-capture-014.webp" alt="Depot settings and binary management page with unconfigured Online Depot and Offline Depot tiles." width="1465" height="650" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Here is the big change from 9.0: instead of pasting a download token, the dialog shows the appliance&amp;rsquo;s &lt;strong&gt;Download Service ID&lt;/strong&gt; (the docs and KB call it the Software Depot ID). Take that ID to the BSC portal at &lt;a href="https://vcf.broadcom.com"&gt;vcf.broadcom.com&lt;/a&gt;, register it, and you get an &lt;strong&gt;Activation Code&lt;/strong&gt; back; the full flow is in the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/preparing-your-environment/downloading-binaries-to-the-vcf-installer-appliance/connect-to-an-online-depot-to-download-binaries.html"&gt;official depot procedure&lt;/a&gt; and &lt;a href="https://knowledge.broadcom.com/external/article/443647/download-token-has-been-replaced-by-acti.html"&gt;KB 443647&lt;/a&gt;. The download token from &lt;a href="https://knowledge.broadcom.com/external/article/390098"&gt;KB 390098&lt;/a&gt; that we used in the 9.0 post is not used here anymore.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy the &lt;strong&gt;Download Service ID&lt;/strong&gt; and register it in the BSC portal to obtain the Activation Code&lt;/li&gt;
&lt;li&gt;Enter the &lt;strong&gt;Activation Code&lt;/strong&gt; (enable the proxy toggle if you need one)&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Authenticate&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/015-capture-015.webp" alt="The Online Depot dialog showing the Download Service ID with the Activation Code field to be filled from the BSC portal." width="853" height="402" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="download-the-binaries"&gt;Download the binaries&lt;/h2&gt;
&lt;p&gt;With the depot connected, the Binary Management section lists everything available for the release.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Confirm the Online Depot tile shows &lt;strong&gt;Depot connection active&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Binary Management&lt;/strong&gt;, select the product and version, &lt;strong&gt;VMware Cloud Foundation 9.1.0.0&lt;/strong&gt; in my case&lt;/li&gt;
&lt;li&gt;Select the binaries and click &lt;strong&gt;Download&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/016-capture-016.webp" alt="Depot settings page with the online depot connection active and the VMware Cloud Foundation 9.1.0.0 binaries listed as not downloaded." width="1434" height="614" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The component list is a good illustration of how 9.1 patch waves work: the installer pulls the latest patch of each component rather than a single uniform build: SDDC Manager 9.1.0.0400, NSX 9.1.0.0200, VCF Automation 9.1.0.0200, VCF Operations 9.1.0.0400, and so on. William Lam has a good write-up of &lt;a href="https://williamlam.com/2026/06/vcf-9-1-quick-tip-understanding-vcf-installer-default-behavior-for-vcf-patch-releases.html"&gt;this default behavior&lt;/a&gt; if you need to pin earlier versions. Also note the sizes, VCF services runtime alone is 17.42 GB and VCF Automation 14.95 GB, so give the downloads some time.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/017-capture-017.webp" alt="Binary Management table with all VMware Cloud Foundation 9.1 components showing download status Success." width="1406" height="582" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="start-the-deployment-wizard"&gt;Start the Deployment Wizard&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Return Home&lt;/strong&gt;: the Deploy card sits next to Download Binaries. Progress in the wizard is saved locally in the browser after each step, so you can safely step away&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/018-capture-018.webp" alt="The VCF Installer home page with the Download Binaries and Deploy cards side by side." width="864" height="252" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Deployment Wizard&lt;/strong&gt; and select &lt;strong&gt;VMware Cloud Foundation&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The dropdown also offers &lt;strong&gt;VMware vSphere Foundation&lt;/strong&gt;: the 9.1 installer deploys VVF through the same wizard framework, with a reduced flow (no NSX Manager or SDDC Manager steps). That is a post for another day; everything below follows the VCF path.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/019-capture-019.webp" alt="The Deploy card with the Deployment Wizard dropdown expanded showing VMware Cloud Foundation and VMware vSphere Foundation options." width="425" height="296" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="deploy-vmware-cloud-foundation"&gt;Deploy VMware Cloud Foundation&lt;/h2&gt;
&lt;p&gt;The wizard runs through four phases: Introduction, Plan, Prepare, Deploy; the official procedure is &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/deploy-a-new-vcf-fleet-or-a-new-vcf-instance.html"&gt;Start a New VCF Fleet or a New VCF Instance Deployment&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="introduction"&gt;Introduction&lt;/h3&gt;
&lt;p&gt;The About page is worth an actual read: it diagrams the VCF fleet concept and calls out that &lt;strong&gt;VCF 9.1 introduces VCF management services&lt;/strong&gt; inside the management domain, next to vCenter, NSX Manager, and SDDC Manager. The installer deploys the management domain; workload domains come later from VCF Operations.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/032-capture-032.webp" alt="The VCF Installer deployment wizard introduction page showing the VCF fleet diagram with VCF Operations, VCF Automation, and the first VCF instance’s management domain." width="1496" height="658" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Three deployment paths are offered: a new VCF fleet, a new VCF instance joining an existing fleet&amp;rsquo;s VCF Operations, or deploying deferred components. Same as in my 9.0 fleet post, this lab is a fresh start.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Deploy a new VCF fleet&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/033-capture-033.webp" alt="The Deployment Paths step with Deploy a new VCF fleet selected over the new VCF Instance and deferred components options." width="1478" height="386" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h3 id="plan"&gt;Plan&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Check &lt;strong&gt;I have an existing vCenter instance&lt;/strong&gt;: the wizard will collect and validate the details later&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also flag an existing VCF Operations 9.1 instance or an NSX-registered vCenter here. VCF Automation is no longer a hard requirement at deployment time; it can be connected or deployed later as a day-N operation.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/034-capture-034.webp" alt="The Plan phase Existing Component step with the existing vCenter checkbox selected." width="1494" height="701" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;Deployment model&lt;/strong&gt;. I went with &lt;strong&gt;Simple&lt;/strong&gt;, which locks the size to &lt;strong&gt;Small&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Review the component sizing table and click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The sizing table is part of the new integrated planning workflow, and it is worth pausing on: VCF management services alone ask for 40 vCPUs, 82 GB RAM, and 3 TB of disk in this smallest configuration.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/035-capture-035.webp" alt="The Size Options step with the Simple deployment model and Small size selected, showing per-component vCPU, RAM, and disk requirements." width="1492" height="659" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Review the &lt;strong&gt;Network Options&lt;/strong&gt;: by default VCF Operations, VCF Automation, and the management services land on the VM management network, and a distributed Transit Gateway is configured to make the domain VPC-ready&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt; (or &lt;strong&gt;Customize&lt;/strong&gt; if you need separate networks)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One caveat straight from the wizard: with an existing vCenter the wizard supports IPv4-only; dual-stack deployments have to go through a JSON spec.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/036-capture-036.webp" alt="The Network Options step showing the default network configuration with the Customize button." width="1488" height="661" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Review Prerequisites step is the payoff of the planning workflow: capacity totals (2 hosts, 84 vCPUs, 254 GB RAM, 5,244 GB disk for my configuration), VLAN requirements (none for this path), and the exact FQDN and IP requirements: 12 IPs for the management services pool, 5 for VCF Automation, plus FQDNs for Cloud proxy, NSX Manager, VCF Operations, and the License Server. The &lt;strong&gt;Pre-fill generated FQDNs in wizard&lt;/strong&gt; button carries these into the later steps. Remember: lowercase only, forward and reverse resolvable.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create the DNS records and reserve the IP ranges&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/037-capture-037.webp" alt="The Review Prerequisites step listing capacity totals, VLAN requirements, and the FQDNs and IP address pools needed for the deployment." width="1487" height="656" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h3 id="prepare"&gt;Prepare&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;Version&lt;/strong&gt;: 9.1.0.0, with the latest downloaded patch of each component applied automatically&lt;/li&gt;
&lt;li&gt;Name the VCF instance and the management domain&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/038-capture-038.webp" alt="The Prepare phase General Information step with version 9.1.0.0, instance name instance-01, and management domain name mgmt." width="1493" height="660" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The VCF Management step collects the FQDNs for VCF Operations, the License Server, and the fleet, instance, and services-runtime components; this is where the pre-filled FQDNs from the Plan phase save the typing.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter the details of the existing vCenter: FQDN, administrator, and root credentials&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Connect&lt;/strong&gt;: the cluster running the vCenter appliance is selected as the deployment destination&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/039-capture-039.webp" alt="The Existing vCenter step with fields for the vCenter FQDN, administrator credentials, and root password and the Connect button." width="1492" height="656" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Provide the IP pools, a single IPv4 range works for both: minimum 12 addresses for the VCF Management Services pool and 5 for the VCF Automation pool&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/040-capture-040.webp" alt="The Networks step with the VCF Management Services and VCF Automation IP pool ranges to be filled in." width="1492" height="650" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter the NSX Manager cluster and appliance FQDNs&lt;/li&gt;
&lt;li&gt;Decide on the overlay networking mode&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;strong&gt;Configure overlay using ESX Management VMkernel Networking&lt;/strong&gt; toggle is one of my favorite quality-of-life items in 9.x: NSX 9 can run overlay over the ESX management VMkernel network without a VLAN-backed transport configuration. Unchecked, NSX is configured in VLAN transport zone mode instead.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/041-capture-041.webp" alt="The NSX Manager step with cluster and appliance FQDN fields and the overlay via ESX Management VMkernel Networking toggle enabled." width="1496" height="663" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter the SDDC Manager FQDN and the installer appliance password&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The info banner explains why the appliance password is requested: when the installer appliance runs on one of the management domain hosts, it is converted into the SDDC Manager appliance during deployment: the same appliance transition the official docs describe, and the reason the prerequisites page noted the SDDC Manager FQDN is optional in that placement.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/042-capture-042.webp" alt="The SDDC Manager step with the FQDN filled in and the info banner explaining the installer appliance is converted into SDDC Manager during deployment." width="1498" height="658" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h3 id="deploy"&gt;Deploy&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Review the summary, every section from the wizard is expandable here&lt;/li&gt;
&lt;li&gt;Optionally click &lt;strong&gt;Download JSON Spec&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The JSON preview tab and the downloadable spec make the whole deployment repeatable: the same file drives API-based deployments, and it is the vehicle for the options the wizard does not expose, like dual-stack networking or an alternative internal cluster CIDR.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/043-capture-043.webp" alt="The Review step of the Deploy phase showing the deployment summary with the Download JSON Spec option." width="1495" height="659" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Wait for the 11 validation checks to complete: deployment specification, security configuration, DNS resolution, versions and bundles, existing SDDC Manager configuration, password policies, network configuration, existing components, and the capacity calculations&lt;/li&gt;
&lt;li&gt;Resolve any errors, acknowledge warnings if appropriate, and click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-91-installer/044-capture-044.webp" alt="The Validate and Deploy step with validation in progress showing 0 of 11 checks completed and the Deploy button still disabled." width="1493" height="654" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;From here the installer takes over: management services, VCF Operations, NSX, SDDC Manager conversion, and the rest of the management domain roll out in sequence. Depending on hardware, expect this to run for a few hours.&lt;/p&gt;
&lt;h2 id="if-validation-or-deployment-fails"&gt;If validation or deployment fails&lt;/h2&gt;
&lt;p&gt;A few 9.1-specific failure modes worth knowing before you hit Deploy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Deploy and configure VCF Management Platform&amp;rdquo; fails&lt;/strong&gt;: the management services use an internal cluster CIDR of 198.18.0.0/15 by default; if that overlaps your network, &lt;a href="https://knowledge.broadcom.com/external/article/440541/deploying-vcf-91-fails-at-deploy-and-con.html"&gt;KB 440541&lt;/a&gt; covers switching it to 240.0.0.0/15 or 250.0.0.0/15 via the JSON spec.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;VCF Management Services Deployment Task&amp;rdquo; fails on NTP&lt;/strong&gt;: the NTP server must be reachable over UDP 123 from the deployed appliances, not just from the installer: &lt;a href="https://knowledge.broadcom.com/external/article/439240/vcf-91-installer-deployment-is-failing-i.html"&gt;KB 439240&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;vMotion / vSAN network connectivity validations fail&lt;/strong&gt;: the installer does not recognize standby uplinks; set the vmnics active/active or disable the check per &lt;a href="https://knowledge.broadcom.com/external/article/437248/91-vcf-installer-fails-on-vmotion-networ.html"&gt;KB 437248&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uppercase FQDNs&lt;/strong&gt;: deployment fails for fleet components, identity broker, services runtime, and VCF Automation; lowercase everything (&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/known-issues/vcf-installer-91-known-issues.html"&gt;known issues&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For nested labs, William Lam maintains a &lt;a href="https://williamlam.com/2026/05/vcf-9-1-comprehensive-vcf-installer-sddc-manager-configuration-workarounds-for-lab-deployments.html"&gt;comprehensive set of installer workarounds for 9.1&lt;/a&gt; (pNIC speed, vSAN HCL, and MTU prechecks included. And a neat trick from the same source: the installer doubles as a &lt;a href="https://williamlam.com/2026/05/vcf-9-1-quick-tip-using-the-vcf-installer-as-a-standalone-pre-check-tool.html"&gt;standalone pre-check tool&lt;/a&gt;) you can run the full validation suite against your infrastructure without deploying anything.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Official documentation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-.html"&gt;Deploying a New VCF or vSphere Foundation Platform (9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/preparing-your-environment/deploy-the-vmware-cloud-foundation-installer-appliance.html"&gt;Deploy VCF Installer (9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/preparing-your-environment/downloading-binaries-to-the-vcf-installer-appliance.html"&gt;Downloading Binaries to VCF Installer (9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/preparing-your-environment/downloading-binaries-to-the-vcf-installer-appliance/connect-to-an-online-depot-to-download-binaries.html"&gt;Connect VCF Installer to Broadcom or an Offline Depot (9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/deployment/deploying-a-new-vmware-cloud-foundation-or-vmware-vsphere-foundation-private-cloud-/deploy-a-new-vcf-fleet-or-a-new-vcf-instance.html"&gt;Start a New VCF Fleet or a New VCF Instance Deployment (9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/planning-and-preparation/vcf-components-fqdns-and-ip-addresses/first-vcf-instance-fqdns-and-ip-addresses.html"&gt;First VCF Instance FQDNs and IP Addresses (9.1 planning)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes.html"&gt;VCF 9.1 Release Notes&lt;/a&gt; · &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/vmware-cloud-foundation-bill-of-materials.html"&gt;Bill of Materials&lt;/a&gt; · &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/what-s-new/whats-new-installer.html"&gt;What&amp;rsquo;s New - VCF Installer&lt;/a&gt; · &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/known-issues/vcf-installer-91-known-issues.html"&gt;VCF Installer Known Issues&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Broadcom KBs&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/443647/download-token-has-been-replaced-by-acti.html"&gt;KB 443647 - Download token replaced by Activation Code in VCF Installer 9.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/401497/vmware-vcf-90-or-vvf-90-downloads-in-the.html"&gt;KB 401497 - VCF/VVF downloads in the Broadcom Support Portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/440541/deploying-vcf-91-fails-at-deploy-and-con.html"&gt;KB 440541 - VCF 9.1 fails at Deploy and configure VCF Management Platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/439240/vcf-91-installer-deployment-is-failing-i.html"&gt;KB 439240 - VCF 9.1 installer fails at VCF Management Services Deployment Task&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/437248/91-vcf-installer-fails-on-vmotion-networ.html"&gt;KB 437248 - VCF 9.1 installer fails on vMotion/vSAN network connectivity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;My VCF 9.0 installer series&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cosmin.us/deploying-the-vmware-cloud-foundation-installer-appliance-step-by-step-instructions/"&gt;Deploying the VMware Cloud Foundation Installer Appliance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cosmin.us/configuring-the-vmware-cloud-foundation-installer-appliance-step-by-step-instructions/"&gt;Configuring the VMware Cloud Foundation Installer Appliance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cosmin.us/deploy-a-vcf-9-instance-in-an-existing-vcf-fleet/"&gt;Deploy a VCF 9 Instance in a New VCF Fleet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Upgrading VCF 9.1 Management Services to 9.1.0.0400 Step by Step</title><link>https://cosmin.us/upgrading-vcf-9-1-management-services-to-9-1-0-0400-step-by-step/</link><pubDate>Mon, 03 Aug 2026 10:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/upgrading-vcf-9-1-management-services-to-9-1-0-0400-step-by-step/</guid><description>&lt;p&gt;On July 13, 2026 Broadcom shipped the next VCF 9.1 patch wave, and this post walks through the part of it that lives under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;: the VCF Management services. The headline releases on this surface are &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-operations/9-1-0-0400/vcfoperations-9-1-0-0400-release-notes.html"&gt;VCF Operations 9.1.0.0400&lt;/a&gt; and &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-automation/vcfautomation-9-1-0-0200-release-notes.html"&gt;VCF Automation 9.1.0.0200&lt;/a&gt;, mostly security enhancements plus a batch of fixes. This post is the follow-up to my &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;9.1.0.0300 walkthrough&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To be clear on scope: this post covers only the management services. SDDC Manager 9.1.0.0400 and the core components (vCenter, NSX, ESX, vSAN) go through the VCF Instances flow and are not covered here; see the short section at the end.&lt;/p&gt;</description><content:encoded>&lt;p&gt;On July 13, 2026 Broadcom shipped the next VCF 9.1 patch wave, and this post walks through the part of it that lives under &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;: the VCF Management services. The headline releases on this surface are &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-operations/9-1-0-0400/vcfoperations-9-1-0-0400-release-notes.html"&gt;VCF Operations 9.1.0.0400&lt;/a&gt; and &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-automation/vcfautomation-9-1-0-0200-release-notes.html"&gt;VCF Automation 9.1.0.0200&lt;/a&gt;, mostly security enhancements plus a batch of fixes. This post is the follow-up to my &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;9.1.0.0300 walkthrough&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To be clear on scope: this post covers only the management services. SDDC Manager 9.1.0.0400 and the core components (vCenter, NSX, ESX, vSAN) go through the VCF Instances flow and are not covered here; see the short section at the end.&lt;/p&gt;
&lt;p&gt;One thing to understand up front: &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x.html"&gt;patch releases are not synchronized among all VCF components&lt;/a&gt;, and you can pick and choose which components to apply. That is why my target list below is a mix of 0400, 0200, and 0100 builds. It looks odd the first time. It is expected.&lt;/p&gt;
&lt;h2 id="versions-in-this-update"&gt;Versions in This Update&lt;/h2&gt;
&lt;p&gt;Here is the full From/To picture from my lab, exactly as the VCF Operations UI reports it.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;Current Version&lt;/th&gt;
					&lt;th&gt;Target Version&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Fleet Lifecycle&lt;/td&gt;
					&lt;td&gt;9.1.0.0300.25536195&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25570104&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Operations&lt;/td&gt;
					&lt;td&gt;9.1.0.0300.25531073&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25541561&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Operations for Networks&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25427421&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25517220&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Identity Broker&lt;/td&gt;
					&lt;td&gt;9.1.0.0.25368698&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25522734&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Automation&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25429499&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25556825&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Log Management&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25435121&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25544947&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SDDC Lifecycle&lt;/td&gt;
					&lt;td&gt;9.1.0.0300.25536194&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25570103&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Real-Time Metrics&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25435036&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25544944&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Real-Time Metrics Store&lt;/td&gt;
					&lt;td&gt;9.1.0.0.25370367&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25555874&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Salt Master&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25434834&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25544946&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Salt RaaS&lt;/td&gt;
					&lt;td&gt;9.1.0.0100.25434834&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25544946&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Software Depot&lt;/td&gt;
					&lt;td&gt;9.1.0.0.25371105&lt;/td&gt;
					&lt;td&gt;9.1.0.0400.25570105&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Migration Service Engine&lt;/td&gt;
					&lt;td&gt;9.1.0.0.25370929&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25556825&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Services Runtime&lt;/td&gt;
					&lt;td&gt;9.1.0.0.25370367&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25555874&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;SDDC Manager &lt;strong&gt;9.1.0.0400&lt;/strong&gt; (build &lt;strong&gt;25570100&lt;/strong&gt;) ships in the same wave but lives outside this component list. See the scope section at the end of the post.&lt;/p&gt;
&lt;h2 id="before-you-start"&gt;Before You Start&lt;/h2&gt;
&lt;p&gt;A few rules before clicking anything. &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/lifecycle-management/using-the-depot-configuration-tab/upgrade-a-vcf-management-component.html"&gt;Back up your components before patching, and remember only one upgrade or patch operation can run at a time&lt;/a&gt;. That single-operation rule matters more than it sounds with fourteen components in the queue, plan for a long session or spread it over a maintenance window. If your depot is online, the binaries pull directly. If you run offline, update the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vmware-download-tool/vcf-download-tool-9-1-0-0400-release-notes.html"&gt;VCF Download Tool to &lt;strong&gt;9.1.0.0400&lt;/strong&gt;&lt;/a&gt; (build &lt;strong&gt;25550178&lt;/strong&gt;) first and download the binaries with it.&lt;/p&gt;
&lt;p&gt;Two known issues shape how I ran this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-operations/9-1-0-0400/sddc-lifecycle-9-1-0-0400-release-notes.html"&gt;SDDC Lifecycle 9.1.0.0400&lt;/a&gt;: the batch precheck can fail with &lt;strong&gt;VCF_LCM_FLEET_UPGRADE_400_COMPONENT_NOT_NEEDED_USER_INPUT_SPEC_PROVIDED&lt;/strong&gt;. Do not use Run Prechecks (ALL). Precheck each component individually.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-operations/9-1-0-0400/software-depot-9-1-0-0400-release-notes.html"&gt;Software Depot 9.1.0.0400&lt;/a&gt;: patching the depot takes it temporarily offline. Do not run any other component patch at the same time, and retry anything that failed afterwards.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="upgrade-fleet-lifecycle"&gt;Upgrade Fleet Lifecycle&lt;/h2&gt;
&lt;p&gt;Broadcom&amp;rsquo;s ordering guidance for maintenance releases starts with Fleet Lifecycle. For patch releases the order is flexible, but I still go Fleet Lifecycle first; it drives patch deployment for the rest of the fleet components.&lt;/p&gt;
&lt;p&gt;In VCF Operations, go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;. Open the &amp;ldquo;&amp;hellip;&amp;rdquo; menu on the Fleet Lifecycle card and click Select version.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/001-capture-001.webp" alt="The VCF Management Upgrade page with the Fleet Lifecycle three-dot menu expanded and the Select version option visible." width="1282" height="356" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Fleet Lifecycle Component Target Version dialog opens. Set the target to &lt;strong&gt;9.1.0.0400.25570104&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/002-capture-002.webp" alt="The Fleet Lifecycle Component Target Version dialog with 9.1.0.0400.25570104 selected." width="858" height="255" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Back on the card, the upgrade path now reads &lt;strong&gt;9.1.0.0300.25536195&lt;/strong&gt; to &lt;strong&gt;9.1.0.0400.25570104&lt;/strong&gt;. Click Upgrade.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/003-capture-003.webp" alt="The Fleet Lifecycle card showing the upgrade path to 9.1.0.0400.25570104 with the Upgrade button." width="915" height="127" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Kick off the upgrade. The card flips to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/004-capture-004.webp" alt="The Fleet Lifecycle card showing Upgrade in progress with a link to Upgrade details." width="963" height="124" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Open Upgrade details. The first two subtasks are &amp;ldquo;Set Fleet lifecycle upgrade context&amp;rdquo; and &amp;ldquo;Stage Fleet lifecycle plugin in VCF services runtime&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/005-capture-005.webp" alt="The Fleet Lifecycle upgrade workflow with its first two subtasks, Set Fleet lifecycle upgrade context and Stage Fleet lifecycle plugin in VCF services runtime." width="1308" height="511" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The status messages move through Staging binaries and Running Component Stage Prechecks. Nothing to do here but watch.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/006-capture-006.webp" alt="The Fleet Lifecycle upgrade workflow showing the Staging binaries and Running Component Stage Prechecks messages." width="1303" height="729" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;All 7 subtasks land on Completed. In this run the whole thing took about 45 minutes, 11:08 to 11:54 AM.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/007-capture-007.webp" alt="The Fleet Lifecycle upgrade workflow with all 7 subtasks showing Completed after roughly 45 minutes." width="1315" height="680" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="set-the-vcf-management-target-version"&gt;Set the VCF Management Target Version&lt;/h2&gt;
&lt;p&gt;With Fleet Lifecycle done, click CHANGE TARGET VERSION.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/008-capture-008.webp" alt="The VCF Management page with the CHANGE TARGET VERSION button highlighted after the Fleet Lifecycle upgrade." width="470" height="61" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Set Target Version dialog offers the VCF global version 9.1.0.*.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/009-capture-009.webp" alt="The Set Target Version dialog showing the VCF global version 9.1.0.* selection." width="850" height="279" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The component list now shows everything Ready for upgrade, with the mixed 0400/0200/0100 targets from the table above. This is the per-component patch numbering at work, not a depot problem.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/010-capture-010.webp" alt="The VCF Management component list showing every component Ready for upgrade with mixed 9.1.0.0400, 9.1.0.0200, and 9.1.0.0100 target versions." width="1265" height="641" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Because of the SDDC Lifecycle known issue, I did not touch RUN PRECHECKS (ALL). I ran prechecks per component instead, right before each upgrade. It costs a few extra clicks per component, but it avoids the &lt;strong&gt;VCF_LCM_FLEET_UPGRADE_400_COMPONENT_NOT_NEEDED_USER_INPUT_SPEC_PROVIDED&lt;/strong&gt; failure entirely.&lt;/p&gt;
&lt;h2 id="upgrade-vcf-operations"&gt;Upgrade VCF Operations&lt;/h2&gt;
&lt;p&gt;First up, VCF Operations itself to &lt;strong&gt;9.1.0.0400.25541561&lt;/strong&gt;. Note that the cloud proxy and the license server are patched automatically as part of this one, no separate steps needed for either.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/011-capture-011.webp" alt="The VCF Operations row Ready for upgrade with target version 9.1.0.0400.25541561." width="1254" height="312" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The workflow runs through its subtasks; I moved on once it was In Progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/012-capture-012.webp" alt="The VCF Operations upgrade workflow with its subtasks In Progress." width="1305" height="723" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-identity-broker"&gt;Upgrade Identity Broker&lt;/h2&gt;
&lt;p&gt;Next, Identity Broker to &lt;strong&gt;9.1.0.0100.25522734&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/013-capture-013.webp" alt="The Identity Broker row Ready for upgrade with target version 9.1.0.0100.25522734." width="1159" height="87" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;This one is a 6-subtask workflow.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/014-capture-014.webp" alt="The Identity Broker upgrade workflow showing its 6 subtasks In Progress." width="1315" height="614" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-vcf-automation"&gt;Upgrade VCF Automation&lt;/h2&gt;
&lt;p&gt;VCF Automation goes to &lt;strong&gt;9.1.0.0200.25556825&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/015-capture-015.webp" alt="The VCF Automation row Ready for upgrade with target version 9.1.0.0200.25556825." width="1209" height="168" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The precheck workflow runs first, then the upgrade takes over.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/016-capture-016.webp" alt="The VCF Automation precheck workflow running before the upgrade proceeds." width="1313" height="704" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-vcf-operations-for-networks"&gt;Upgrade VCF Operations for Networks&lt;/h2&gt;
&lt;p&gt;VCF Operations for Networks moves to &lt;strong&gt;9.1.0.0200.25517220&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/017-capture-017.webp" alt="The VCF Operations for Networks row Ready for upgrade with target version 9.1.0.0200.25517220." width="1246" height="172" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-log-management"&gt;Upgrade Log Management&lt;/h2&gt;
&lt;p&gt;Log Management targets &lt;strong&gt;9.1.0.0400.25544947&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/019-capture-019.webp" alt="The Log Management row Ready for upgrade with target version 9.1.0.0400.25544947." width="1056" height="100" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Same pattern: precheck, then the upgrade workflow.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/020-capture-020.webp" alt="The Log Management upgrade workflow with its subtasks In Progress." width="1068" height="710" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-sddc-lifecycle"&gt;Upgrade SDDC Lifecycle&lt;/h2&gt;
&lt;p&gt;SDDC Lifecycle goes to &lt;strong&gt;9.1.0.0400.25570103&lt;/strong&gt;: the component behind the batch precheck known issue, upgraded here with its own individual precheck.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/021-capture-021.webp" alt="The SDDC Lifecycle row Ready for upgrade with target version 9.1.0.0400.25570103." width="1054" height="92" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-real-time-metrics-and-metrics-store"&gt;Upgrade Real-Time Metrics and Metrics Store&lt;/h2&gt;
&lt;p&gt;Real-Time Metrics targets &lt;strong&gt;9.1.0.0400.25544944&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/022-capture-022.webp" alt="The Real-Time Metrics row Ready for upgrade with target version 9.1.0.0400.25544944." width="1054" height="90" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Real-Time Metrics row switches to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/023-capture-023.webp" alt="The Real-Time Metrics row showing Upgrade in progress with the Upgrade details link." width="855" height="66" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Then the upgrade workflow itself.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/024-capture-024.webp" alt="The Real-Time Metrics upgrade workflow with its subtasks In Progress." width="1065" height="224" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Real-Time Metrics Store is a separate component; it targets &lt;strong&gt;9.1.0.0200.25555874&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/025-capture-025.webp" alt="The Real-Time Metrics Store row Ready for upgrade with target version 9.1.0.0200.25555874." width="1051" height="92" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Real-Time Metrics Store row switches to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/026-capture-026.webp" alt="The Real-Time Metrics Store row showing Upgrade in progress with the Upgrade details link." width="857" height="56" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;And the upgrade workflow follows.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/027-capture-027.webp" alt="The Real-Time Metrics Store upgrade workflow with its subtasks In Progress." width="1064" height="412" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-salt-master"&gt;Upgrade Salt Master&lt;/h2&gt;
&lt;p&gt;Salt Master targets &lt;strong&gt;9.1.0.0400.25544946&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/029-capture-029.webp" alt="The Salt Master row Ready for upgrade with target version 9.1.0.0400.25544946." width="1051" height="95" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Salt Master row switches to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/030-capture-030.webp" alt="The Salt Master row showing Upgrade in progress with the Upgrade details link." width="847" height="58" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The upgrade workflow takes over and works through its subtasks.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/031-capture-031.webp" alt="The Salt Master upgrade workflow with its subtasks In Progress." width="1067" height="584" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-software-depot"&gt;Upgrade Software Depot&lt;/h2&gt;
&lt;p&gt;Software Depot goes to &lt;strong&gt;9.1.0.0400.25570105&lt;/strong&gt;. Per the known issue in the release notes, the depot goes briefly offline during its own patch, so avoid launching other component patches at the same time and retry anything that failed afterwards.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/033-capture-033.webp" alt="The Software Depot row Ready for upgrade with target version 9.1.0.0400.25570105." width="1056" height="95" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Software Depot row switches to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/034-capture-034.webp" alt="The Software Depot row showing Upgrade in progress with the Upgrade details link." width="854" height="59" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Then the upgrade workflow, while the depot is briefly unavailable.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/035-capture-035.webp" alt="The Software Depot upgrade workflow with its subtasks In Progress while the depot is temporarily offline." width="1064" height="662" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-migration-service-engine"&gt;Upgrade Migration Service Engine&lt;/h2&gt;
&lt;p&gt;Migration Service Engine targets &lt;strong&gt;9.1.0.0200.25556825&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/036-capture-036.webp" alt="The Migration Service Engine row Ready for upgrade with target version 9.1.0.0200.25556825." width="1053" height="93" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The Migration Service Engine row switches to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/037-capture-037.webp" alt="The Migration Service Engine row showing Upgrade in progress with the Upgrade details link." width="849" height="56" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Fun detail in the workflow panel: the staging task exposes the internal component name &lt;strong&gt;VCD_MIGRATOR&lt;/strong&gt;: &amp;ldquo;Stage VCD_MIGRATOR plugin in VCF services runtime&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/038-capture-038.webp" alt="The Migration Service Engine upgrade workflow with the Stage VCD_MIGRATOR plugin in VCF services runtime subtask." width="1069" height="386" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-vcf-services-runtime"&gt;Upgrade VCF Services Runtime&lt;/h2&gt;
&lt;p&gt;VCF Services Runtime goes to &lt;strong&gt;9.1.0.0200.25555874&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/039-capture-039.webp" alt="The VCF Services Runtime row Ready for upgrade with target version 9.1.0.0200.25555874." width="1051" height="95" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The VCF Services Runtime row switches to Upgrade in progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/040-capture-040.webp" alt="The VCF Services Runtime row showing Upgrade in progress with the Upgrade details link." width="851" height="56" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Then the upgrade workflow with its subtasks.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/041-capture-041.webp" alt="The VCF Services Runtime upgrade workflow with its subtasks In Progress." width="1057" height="404" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-salt-raas"&gt;Upgrade Salt RaaS&lt;/h2&gt;
&lt;p&gt;Salt RaaS ran last in my lab, targeting &lt;strong&gt;9.1.0.0400.25544946&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/028-capture-028.webp" alt="The Salt RaaS row Ready for upgrade with target version 9.1.0.0400.25544946." width="1053" height="95" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;At the time of this capture the precheck workflow was still running, &amp;ldquo;Run Salt RaaS upgrade prechecks&amp;rdquo; shows In Progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/08/vcf-9-1-0400-upgrade/044-capture-044.webp" alt="The Salt RaaS precheck workflow with the Run Salt RaaS upgrade prechecks subtask still In Progress." width="1060" height="520" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="what-about-sddc-manager-and-the-core-components"&gt;What About SDDC Manager and the Core Components?&lt;/h2&gt;
&lt;p&gt;They are out of scope for this post. &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-installer/sddc-manager-9-1-0-0400-release-notes.html"&gt;SDDC Manager 9.1.0.0400&lt;/a&gt; (build &lt;strong&gt;25570100&lt;/strong&gt;) and the core components from this wave (ESX 9.1.0.0200, vSAN 9.1.0.0200, NSX 9.1.0.0200, and vCenter 9.1.0.0200, later bumped to 9.1.0.0300 on July 29, 2026) are applied through &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Instances&lt;/strong&gt;. That is the same flow I documented in &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;Upgrading VCF 9.1 to 9.1.0.0300 Step by Step&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="validate-the-update"&gt;Validate the Update&lt;/h2&gt;
&lt;p&gt;Before calling it done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the Component Versions page, every patched management component should show On Target.&lt;/li&gt;
&lt;li&gt;Check the task list, no failed workflows left behind.&lt;/li&gt;
&lt;li&gt;Confirm the VCF Operations UI is reachable and healthy.&lt;/li&gt;
&lt;li&gt;Retry anything that failed while the Software Depot was being patched; the depot was offline during that window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For SDDC Manager and the core components, see the previous section, the flow in &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;Upgrading VCF 9.1 to 9.1.0.0300 Step by Step&lt;/a&gt; still applies one-to-one.&lt;/p&gt;</content:encoded></item><item><title>Fixing Swagger’s localhost:8600 URL in VCF Automation 9.1</title><link>https://cosmin.us/fixing-swagger-localhost-8600-server-url-vcf-automation-9-1/</link><pubDate>Fri, 31 Jul 2026 00:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/fixing-swagger-localhost-8600-server-url-vcf-automation-9-1/</guid><description>&lt;p&gt;While putting together the &lt;a href="https://cosmin.us/vcf-automation-9-1-api-getting-started/"&gt;VCF Automation 9.1 API getting started&lt;/a&gt; post, I spent some time in the in-product API Help Center. Log into the VM Apps tenant, click your username, &lt;strong&gt;API Help Center &amp;gt; Explore Automation APIs&lt;/strong&gt;. The Swagger pages render fine, but the moment you try an actual call, it fails. The &lt;strong&gt;Servers&lt;/strong&gt; box for the VCF Automation (Blueprint) API shows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://localhost:8600
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Swagger UI builds Try It Out requests from &lt;code&gt;servers[0].url&lt;/code&gt;, so the browser dutifully sends every request to port 8600 on &lt;em&gt;your own workstation&lt;/em&gt;. Connection refused, every time. The documentation is correct; the advertised host is not.&lt;/p&gt;</description><content:encoded>&lt;p&gt;While putting together the &lt;a href="https://cosmin.us/vcf-automation-9-1-api-getting-started/"&gt;VCF Automation 9.1 API getting started&lt;/a&gt; post, I spent some time in the in-product API Help Center. Log into the VM Apps tenant, click your username, &lt;strong&gt;API Help Center &amp;gt; Explore Automation APIs&lt;/strong&gt;. The Swagger pages render fine, but the moment you try an actual call, it fails. The &lt;strong&gt;Servers&lt;/strong&gt; box for the VCF Automation (Blueprint) API shows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://localhost:8600
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Swagger UI builds Try It Out requests from &lt;code&gt;servers[0].url&lt;/code&gt;, so the browser dutifully sends every request to port 8600 on &lt;em&gt;your own workstation&lt;/em&gt;. Connection refused, every time. The documentation is correct; the advertised host is not.&lt;/p&gt;
&lt;p&gt;This post is about finding where that value actually comes from (which took three wrong turns through the appliance&amp;rsquo;s Kubernetes internals) and the override that finally fixed it without touching a container image. The short version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;localhost:8600&lt;/code&gt; value is &lt;strong&gt;not in any configuration on the appliance&lt;/strong&gt;. A grep across a full support-bundle cluster dump finds no ConfigMap, Helm value, gateway route, or forwarded-headers setting that produces it.&lt;/li&gt;
&lt;li&gt;The spec is a &lt;strong&gt;static JSON file generated by springdoc at build time&lt;/strong&gt; (the giveaway is its &lt;code&gt;&amp;quot;description&amp;quot;: &amp;quot;Generated server url&amp;quot;&lt;/code&gt;) and it ships &lt;strong&gt;as a classpath resource inside the Spring Boot application&lt;/strong&gt; in the &lt;code&gt;tango-blueprint-service-app&lt;/code&gt; pod. Whoever built it had the service listening on port 8600, and the URL froze there.&lt;/li&gt;
&lt;li&gt;The api-docs page itself is served by a &lt;em&gt;different&lt;/em&gt; pod than the spec, which is why the obvious nginx-level fixes go nowhere.&lt;/li&gt;
&lt;li&gt;The fix: mount a corrected copy of the spec from a ConfigMap and prepend &lt;code&gt;file:/override/&lt;/code&gt; to &lt;code&gt;spring.web.resources.static-locations&lt;/code&gt; via &lt;code&gt;JAVA_OPTS&lt;/code&gt;, so Spring serves the fixed file and never falls through to the copy shipped in the image. Survives pod restarts with nothing to reconcile it away; a product upgrade will wipe it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything below was done on a lab appliance running build &lt;code&gt;9.1.0.0100.25429499&lt;/code&gt;. This is an unsupported modification. More on that at the end.&lt;/p&gt;
&lt;h2 id="the-symptom"&gt;The Symptom&lt;/h2&gt;
&lt;p&gt;In the tenant API Help Center, open the VCF Automation API (the Blueprint one, version 2019-09-12). The spec renders, the paths are all correct, but the servers dropdown offers exactly one entry: &lt;code&gt;http://localhost:8600&lt;/code&gt;. There is no way to type a different URL: the dropdown only lists what the spec declares, and this spec declares one hardcoded server with no variables.&lt;/p&gt;
&lt;p&gt;Browser DevTools (Network tab) shows what the page actually loads. First an index of every API the Help Center knows about:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/tenant/&amp;lt;your-tenant&amp;gt;/api-docs/assets/content/soft/automation-apis.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That index maps each tile to a spec URL: about sixteen specs across a dozen backend services. The Blueprint entry points at:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/blueprint/api-docs/classic-apis/api-doc-public-classic-vra-2019-09-12.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that document contains the problem, verbatim:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;servers&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;http://localhost:8600&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Generated server url&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Two details in that response are worth pausing on, because they shaped the whole investigation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;Generated server url&amp;quot;&lt;/code&gt; is the literal default description springdoc attaches when it auto-computes the server URL from the incoming request. So springdoc generated this, but if it were computed per request, it would show the appliance FQDN, not localhost.&lt;/li&gt;
&lt;li&gt;The response carries a &lt;code&gt;last-modified&lt;/code&gt; date from months before I ever opened the page, plus &lt;code&gt;accept-ranges: bytes&lt;/code&gt;. That is a static file being read off disk (or classpath), not a document rendered per request.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Put together: someone ran the Blueprint service on a build machine, where it listened on &lt;code&gt;localhost:8600&lt;/code&gt;, exported the generated spec to a file, and shipped that file in the product. The URL froze at build time.&lt;/p&gt;
&lt;h2 id="ruling-out-configuration"&gt;Ruling Out Configuration&lt;/h2&gt;
&lt;p&gt;Before touching anything, I wanted to know whether some appliance setting produces or rewrites that value, because if it did, that would be the supported place to fix it.&lt;/p&gt;
&lt;p&gt;It does not. I had a full support bundle from this appliance handy (that is a story for another post), and the extracted cluster object dump is conclusive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The string &lt;code&gt;8600&lt;/code&gt; appears nowhere in the cluster as a port, URL, or config value. No Service exposes it, no container declares it, no ConfigMap mentions it. The only matches are UID substrings.&lt;/li&gt;
&lt;li&gt;There is no &lt;code&gt;springdoc&lt;/code&gt;, &lt;code&gt;server.forward-headers-strategy&lt;/code&gt;, or server-URL configuration in any ConfigMap in the &lt;code&gt;prelude&lt;/code&gt; or &lt;code&gt;vmsp-platform&lt;/code&gt; namespaces.&lt;/li&gt;
&lt;li&gt;The Envoy gateway routes (Gateway API &lt;code&gt;HTTPRoute&lt;/code&gt; objects) that publish the api-docs paths perform &lt;strong&gt;path rewrites only&lt;/strong&gt;: nothing rewrites hosts or response bodies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So there is no knob. The value lives in content, not configuration, and only Broadcom can fix it properly. Everything from here on is about making the appliance serve a corrected copy.&lt;/p&gt;
&lt;h2 id="wrong-turn-1-the-pod-that-serves-the-page-doesnt-serve-the-spec"&gt;Wrong Turn #1: The Pod That Serves the Page Doesn&amp;rsquo;t Serve the Spec&lt;/h2&gt;
&lt;p&gt;The api-docs page shell (the Angular app with the tiles) is served by the &lt;code&gt;cloud-automation-ui-app&lt;/code&gt; pod in the &lt;code&gt;prelude&lt;/code&gt; namespace. Its nginx config (ConfigMap &lt;code&gt;cloud-automation-ui&lt;/code&gt;) rewrites &lt;code&gt;/tenant/&amp;lt;org&amp;gt;/api-docs&lt;/code&gt; and &lt;code&gt;/provider/api-docs&lt;/code&gt; into static content under &lt;code&gt;/usr/share/nginx/html/dist&lt;/code&gt;. My first instinct was an nginx &lt;code&gt;sub_filter&lt;/code&gt; there, rewriting &lt;code&gt;localhost:8600&lt;/code&gt; in responses.&lt;/p&gt;
&lt;p&gt;Dead end, for a structural reason: the spec never passes through that pod. The gateway routes the two URLs to different backends entirely:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Path&lt;/th&gt;
					&lt;th&gt;HTTPRoute&lt;/th&gt;
					&lt;th&gt;Backend&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/tenant/&amp;lt;org&amp;gt;/api-docs/...&lt;/code&gt; (the page, the index JSON)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;tenant-in-path-automation-ui&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;cloud-automation-ui&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/blueprint/api-docs/...&lt;/code&gt; (the spec)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;blueprintapi-docs&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;tango-blueprint:8080&lt;/code&gt;, prefix rewritten to &lt;code&gt;/api-docs/&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A &lt;code&gt;sub_filter&lt;/code&gt; in the UI pod would rewrite a response it never sees. The actual owner of the spec is the Blueprint service itself: &lt;code&gt;Deployment/tango-blueprint-service-app&lt;/code&gt;, image &lt;code&gt;blueprint-webapp:9.1.0.0100.25429499&lt;/code&gt;: a Spring Boot app, which also explains the Spring Security headers on the spec response.&lt;/p&gt;
&lt;h2 id="wrong-turn-2-there-is-no-file-to-edit"&gt;Wrong Turn #2: There Is No File to Edit&lt;/h2&gt;
&lt;p&gt;Fine, exec into the right pod and &lt;code&gt;sed&lt;/code&gt; the file in place:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude &lt;span class="nb"&gt;exec&lt;/span&gt; deploy/tango-blueprint-service-app -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sh -c &lt;span class="s1"&gt;&amp;#39;find / -name &amp;#34;api-doc-public-classic-vra-*.json&amp;#34; -not -path &amp;#34;/proc/*&amp;#34; 2&amp;gt;/dev/null&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nothing. And looking for the application itself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude &lt;span class="nb"&gt;exec&lt;/span&gt; deploy/tango-blueprint-service-app -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sh -c &lt;span class="s1"&gt;&amp;#39;find / -maxdepth 3 -name &amp;#34;*.jar&amp;#34; -not -path &amp;#34;/proc/*&amp;#34; 2&amp;gt;/dev/null | head&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/opt/bc-fips/bcutil-fips-2.1.5.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/opt/bc-fips/bctls-fips-2.1.22.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/opt/bc-fips/bcpkix-fips-2.1.10.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/opt/bc-fips/bc-fips-2.1.2.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/opt/bc-fips/bcmail-fips-2.1.6.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/jdk/lib/jrt-fs.jar
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Only the Bouncy Castle FIPS libraries and the JDK, the shallow search doesn&amp;rsquo;t even turn up the application archive itself. Wherever the application lives, the spec is packaged inside it as a classpath resource: &lt;code&gt;find&lt;/code&gt; sees nothing, and &lt;code&gt;sed&lt;/code&gt; has nothing to reach. Even if you dug out the archive, patched it, and re-packed it in the running container, the fix would be pointless: the JVM holds it open, so a restart is needed to pick up the change, and the restart is exactly what rebuilds the container filesystem from the pristine image. The fix would erase itself at the moment of application.&lt;/p&gt;
&lt;h2 id="wrong-turn-3-kubectl-edit-ate-my-java_opts"&gt;Wrong Turn #3: kubectl edit Ate My JAVA_OPTS&lt;/h2&gt;
&lt;p&gt;The mechanism that does work is Spring&amp;rsquo;s static resource resolution. Spring Boot serves static content from an ordered list of locations, and the first location that contains a matching file wins:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spring.web.resources.static-locations =
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Setting that property &lt;em&gt;replaces&lt;/em&gt; the default list. So if I prepend a filesystem directory and re-append the defaults, a file I control shadows the identically-pathed resource on the application classpath, and everything else keeps being served from the classpath exactly as before.&lt;/p&gt;
&lt;p&gt;The path arithmetic works out neatly. After the gateway&amp;rsquo;s prefix rewrite, the backend sees the request as &lt;code&gt;/api-docs/classic-apis/api-doc-public-classic-vra-2019-09-12.json&lt;/code&gt;. With &lt;code&gt;file:/override/&lt;/code&gt; first in the list, Spring checks &lt;code&gt;/override/api-docs/classic-apis/api-doc-public-classic-vra-2019-09-12.json&lt;/code&gt; before falling through to the classpath. That is exactly where a ConfigMap mount can put a corrected copy.&lt;/p&gt;
&lt;p&gt;The wrong-turn part: my first attempt applied all of this with &lt;code&gt;kubectl edit deploy&lt;/code&gt;. The volume and volumeMount saved; the &lt;code&gt;JAVA_OPTS&lt;/code&gt; append &lt;strong&gt;silently did not&lt;/strong&gt;. That env value is one enormous line that already contains &lt;code&gt;$(SERVICE_ACCOUNT_SECRET)&lt;/code&gt; (literal Kubernetes variable-expansion syntax) and somewhere in the editor round-trip the appended text was lost; I never pinned down exactly where. (The same string is also a shell command-substitution landmine if you ever round-trip the value through a shell, which is why the fix below patches programmatically.) The pod rolled, the override directory appeared, and the spec still said &lt;code&gt;localhost:8600&lt;/code&gt; because the JVM never got the property. Verify the property reached the Deployment before concluding the approach failed.&lt;/p&gt;
&lt;h2 id="the-fix"&gt;The Fix&lt;/h2&gt;
&lt;p&gt;All commands run as root on the appliance, where &lt;code&gt;kubectl&lt;/code&gt; is already configured. Replace &lt;code&gt;vcfa.domain.com&lt;/code&gt; with your appliance FQDN.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Produce the corrected spec.&lt;/strong&gt; No spelunking inside the image needed, pull it through the gateway and fix the one string:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk https://vcfa.domain.com/blueprint/api-docs/classic-apis/api-doc-public-classic-vra-2019-09-12.json &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s|http://localhost:8600|https://vcfa.domain.com|g&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; /root/api-doc-public-classic-vra-2019-09-12.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sanity-check it: zero remaining hits, and still valid JSON:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -c localhost:8600 /root/api-doc-public-classic-vra-2019-09-12.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 -m json.tool /root/api-doc-public-classic-vra-2019-09-12.json &amp;gt; /dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;valid json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;2. Create the ConfigMap and back up the Deployment:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude create configmap blueprint-apidocs-override &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --from-file&lt;span class="o"&gt;=&lt;/span&gt;/root/api-doc-public-classic-vra-2019-09-12.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude get deploy tango-blueprint-service-app -o yaml &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; /root/tango-blueprint-deploy.backup.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;3. Add the volume and mount.&lt;/strong&gt; A strategic merge patch merges named list entries, so this adds without disturbing the existing volumes and mounts:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude patch deploy tango-blueprint-service-app --type&lt;span class="o"&gt;=&lt;/span&gt;strategic -p &lt;span class="s1"&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; template:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; volumes:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; - name: apidocs-override
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; configMap:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; name: blueprint-apidocs-override
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; containers:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; - name: tango-blueprint-service-app
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; volumeMounts:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; - name: apidocs-override
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; mountPath: /override/api-docs/classic-apis
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;4. Append the properties to JAVA_OPTS (programmatically.&lt;/strong&gt; This reads the current value, appends both the current (&lt;code&gt;spring.web.resources.static-locations&lt;/code&gt;) and the pre-2.4 (&lt;code&gt;spring.resources.static-locations&lt;/code&gt;) property names) whichever one this Spring Boot generation ignores does no harm, and writes a JSON patch. It refuses to double-apply:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude get deploy tango-blueprint-service-app -o json &amp;gt; /root/d.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 - &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;import json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;d = json.load(open(&amp;#34;/root/d.json&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;env = d[&amp;#34;spec&amp;#34;][&amp;#34;template&amp;#34;][&amp;#34;spec&amp;#34;][&amp;#34;containers&amp;#34;][0][&amp;#34;env&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;i = [n for n, e in enumerate(env) if e[&amp;#34;name&amp;#34;] == &amp;#34;JAVA_OPTS&amp;#34;][0]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;loc = &amp;#34;file:/override/,classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;add = &amp;#34; -Dspring.web.resources.static-locations=&amp;#34; + loc + &amp;#34; -Dspring.resources.static-locations=&amp;#34; + loc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;if &amp;#34;static-locations&amp;#34; in env[i][&amp;#34;value&amp;#34;]:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; json.dump([], open(&amp;#34;/root/patch.json&amp;#34;, &amp;#34;w&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; print(&amp;#34;already present - nothing to do&amp;#34;); raise SystemExit
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;json.dump([{&amp;#34;op&amp;#34;: &amp;#34;replace&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;path&amp;#34;: &amp;#34;/spec/template/spec/containers/0/env/%d/value&amp;#34; % i,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; &amp;#34;value&amp;#34;: env[i][&amp;#34;value&amp;#34;] + add}],
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; open(&amp;#34;/root/patch.json&amp;#34;, &amp;#34;w&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;print(&amp;#34;patch written for env index&amp;#34;, i)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude patch deploy tango-blueprint-service-app --type&lt;span class="o"&gt;=&lt;/span&gt;json --patch-file&lt;span class="o"&gt;=&lt;/span&gt;/root/patch.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;5. Wait for the rollout.&lt;/strong&gt; The Deployment uses the &lt;code&gt;Recreate&lt;/code&gt; strategy with a single replica, so the Blueprint service is briefly down while the pod is replaced:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude rollout status deploy/tango-blueprint-service-app --timeout&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;Learned from wrong turn #3: verify each layer, not just the end result.&lt;/p&gt;
&lt;p&gt;The property is on the Deployment:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude get deploy tango-blueprint-service-app &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.spec.template.spec.containers[0].env[?(@.name==&amp;#34;JAVA_OPTS&amp;#34;)].value}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; tr &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -i static
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-Dspring.web.resources.static-locations=file:/override/,classpath:/META-INF/resources/,...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-Dspring.resources.static-locations=file:/override/,classpath:/META-INF/resources/,...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The override file is mounted in the new pod:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude &lt;span class="nb"&gt;exec&lt;/span&gt; deploy/tango-blueprint-service-app -c tango-blueprint-service-app -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ls -la /override/api-docs/classic-apis/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the actual test, the spec as served through the gateway:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk https://vcfa.domain.com/blueprint/api-docs/classic-apis/api-doc-public-classic-vra-2019-09-12.json &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -A2 &lt;span class="s1"&gt;&amp;#39;&amp;#34;servers&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;servers&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://vcfa.domain.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hard-reload the API Help Center page (the SPA caches aggressively) and the Servers box shows the appliance FQDN. Try It Out now sends requests where they belong.&lt;/p&gt;
&lt;h2 id="what-this-does-and-does-not-fix"&gt;What This Does and Does Not Fix&lt;/h2&gt;
&lt;p&gt;Worth being precise here, because the Help Center is bigger than one spec:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fixed:&lt;/strong&gt; the 2019-09-12 Blueprint spec shown above. Its 2019-01-15 sibling from the same &lt;code&gt;/blueprint/api-docs/classic-apis/&lt;/code&gt; directory - if it shows the same URL - is the same fix: repeat step 1 for it, then rebuild the ConfigMap with both files: &lt;code&gt;kubectl -n prelude create configmap blueprint-apidocs-override --from-file=/root/api-doc-public-classic-vra-2019-09-12.json --from-file=/root/api-doc-public-classic-vra-2019-01-15.json --dry-run=client -o yaml | kubectl -n prelude replace -f -&lt;/code&gt;. The mounted volume picks up the change on its own within a minute or so; no restart needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Same pattern, different pod:&lt;/strong&gt; the catalog, deployment, and policies tiles point at &lt;code&gt;api-doc-public-classic-vra-*.yaml&lt;/code&gt; files under &lt;code&gt;/catalog/api-docs/classic-apis/&lt;/code&gt; - the same baked-file shape, owned by the catalog service. If those show the same URL, it is the same fix against that Deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Possibly not broken at all:&lt;/strong&gt; several tiles point at live springdoc endpoints (&lt;code&gt;/identity/doc/v3/api-docs&lt;/code&gt;, &lt;code&gt;/iaas-api/swagger/v3/api-docs/...&lt;/code&gt;, &lt;code&gt;/project-service/api/swagger/v3/api-docs/...&lt;/code&gt;). Those generate their spec per request, so check before assuming. A quick &lt;code&gt;curl ... | jq .servers&lt;/code&gt; against each URL from the index tells you which ones need attention.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="caveats"&gt;Caveats&lt;/h2&gt;
&lt;p&gt;This is an unsupported modification to a Broadcom appliance, and it behaves accordingly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It survives pod restarts, and nothing reconciles it away.&lt;/strong&gt; The fix lives in the Deployment spec, so every pod the Deployment creates from now on gets the mount and the property - the verified state above is itself a freshly recreated pod. The &lt;code&gt;tango-blueprint-service&lt;/code&gt; Helm release is deployed once at install/upgrade time with nothing reconciling it continuously, so it should come back intact after an appliance reboot as well; re-check the spec once after your next reboot to confirm. (Do not assume this generalizes: several other components in the same namespace &lt;em&gt;are&lt;/em&gt; Flux-managed and would revert an edit within minutes.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A product upgrade will wipe it.&lt;/strong&gt; The LCM re-renders the Deployment from the new chart. Expect to re-apply, and re-check after any lifecycle operation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Roll back at any time&lt;/strong&gt; with the backup from step 2. Not with &lt;code&gt;kubectl apply&lt;/code&gt;, though - the backup carries the pre-patch &lt;code&gt;resourceVersion&lt;/code&gt; (so the apply is rejected as a conflict), and client-side apply against a Helm-created object has no &lt;code&gt;last-applied-configuration&lt;/code&gt; to prune from, so the added volume would survive the merge and the next pod would wedge on the then-deleted ConfigMap. &lt;code&gt;kubectl replace&lt;/code&gt; does a full PUT and removes the volume, mount, and &lt;code&gt;JAVA_OPTS&lt;/code&gt; additions in one shot; strip the &lt;code&gt;resourceVersion&lt;/code&gt; so the PUT is unconditional, and delete the ConfigMap only after the Deployment no longer references it:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed &lt;span class="s1"&gt;&amp;#39;/^ resourceVersion:/d&amp;#39;&lt;/span&gt; /root/tango-blueprint-deploy.backup.yaml &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; kubectl -n prelude replace -f -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude rollout status deploy/tango-blueprint-service-app --timeout&lt;span class="o"&gt;=&lt;/span&gt;180s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n prelude delete configmap blueprint-apidocs-override
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;File an SR anyway.&lt;/strong&gt; As of this writing there is no KB and nothing in the 9.1 release notes for this - the proper fix has to ship in the product, and that only happens if it gets reported. Reference the build number and the &lt;code&gt;&amp;quot;Generated server url&amp;quot;&lt;/code&gt; value in the spec.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you only need a working Try It Out for yourself and would rather not touch the appliance at all, there is a zero-footprint alternative: download the spec, fix &lt;code&gt;servers[0].url&lt;/code&gt; in the copy, and import it into Postman; it seeds the collection&amp;rsquo;s &lt;code&gt;baseUrl&lt;/code&gt; from the spec, and auth works as described in the &lt;a href="https://cosmin.us/vcf-automation-9-1-api-getting-started/"&gt;getting started post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="final-notes"&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;The frustrating part of this bug is how little is actually wrong: every path in the spec is correct, authentication is correct, the API itself works. One string, frozen at build time on some build machine where the Blueprint service happened to listen on port 8600, breaks the one feature the page exists to provide.&lt;/p&gt;
&lt;p&gt;The investigation pattern is the reusable part. When a value appears in a rendered page and nothing in the configuration produces it, stop grepping ConfigMaps and follow the bytes instead: DevTools tells you the exact URL, the response headers tell you whether it is static or generated, and the gateway routes tell you which pod actually owns it. In this case each of those three steps invalidated an otherwise-reasonable fix (the nginx rewrite targeted the wrong pod, the in-pod &lt;code&gt;sed&lt;/code&gt; targeted a file that does not exist, and the editor-based patch failed silently) before the resource-shadowing approach landed on the one layer where the platform genuinely offers an override.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cosmin.us/vcf-automation-9-1-api-getting-started/"&gt;VCF Automation 9.1 API Getting Started&lt;/a&gt;: authentication against the same appliance, and where the API docs moved in 9.1&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/administration-sdks-cli-and-tools/what-are-the-automation-apis-and-how-do-i-use-them_1.html"&gt;Broadcom TechDocs - What Are the Automation APIs and How Do I Use Them (VCF 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/org-management-vm-apps-org/latest/"&gt;VM Apps Org APIs on the Broadcom Developer Portal&lt;/a&gt;, the hosted alternative to the in-product Help Center&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/reference/web/servlet.html#web.servlet.spring-mvc.static-content"&gt;Spring Boot Reference - Serving Static Content&lt;/a&gt;, the &lt;code&gt;static-locations&lt;/code&gt; resolution order this fix relies on&lt;/li&gt;
&lt;li&gt;&lt;a href="https://springdoc.org/faq.html"&gt;springdoc-openapi FAQ&lt;/a&gt;; how the &amp;ldquo;Generated server url&amp;rdquo; value is computed, and why it goes stale behind a proxy&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>VCF Automation 9.1 API Getting Started</title><link>https://cosmin.us/vcf-automation-9-1-api-getting-started/</link><pubDate>Thu, 30 Jul 2026 07:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/vcf-automation-9-1-api-getting-started/</guid><description>&lt;p&gt;Back in 2022 I wrote &lt;a href="https://cosmin.us/vra-8-api-getting-started/"&gt;vRA 8 API getting started&lt;/a&gt;, two curl calls and you had a bearer token. Since then the product has been renamed twice (vRealize Automation → VMware Aria Automation → VCF Automation) and, more importantly for anyone with scripts in production, the authentication flow changed in VCF 9.x. Neither of the two calls from that post works against a 9.1 appliance.&lt;/p&gt;
&lt;p&gt;This is the 9.1 version of the same post: the minimum you need to do before you can actually query the API, with curl.&lt;/p&gt;</description><content:encoded>&lt;p&gt;Back in 2022 I wrote &lt;a href="https://cosmin.us/vra-8-api-getting-started/"&gt;vRA 8 API getting started&lt;/a&gt;, two curl calls and you had a bearer token. Since then the product has been renamed twice (vRealize Automation → VMware Aria Automation → VCF Automation) and, more importantly for anyone with scripts in production, the authentication flow changed in VCF 9.x. Neither of the two calls from that post works against a 9.1 appliance.&lt;/p&gt;
&lt;p&gt;This is the 9.1 version of the same post: the minimum you need to do before you can actually query the API, with curl.&lt;/p&gt;
&lt;h2 id="what-changed-since-vra-8"&gt;What Changed Since vRA 8&lt;/h2&gt;
&lt;p&gt;The short version, before the steps:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;vRA 8.x&lt;/th&gt;
					&lt;th&gt;VCF Automation 9.1 (VM Apps org)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Refresh token&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /csp/gateway/am/api/login?access_token&lt;/code&gt; with username/password&lt;/td&gt;
					&lt;td&gt;Generated in the UI (&lt;strong&gt;My Account &amp;gt; API Tokens&lt;/strong&gt;), no programmatic call&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Bearer token&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /iaas/api/login&lt;/code&gt; with the refresh token&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;POST /tm/oauth/tenant/{tenant}/token&lt;/code&gt;, standard OAuth &lt;code&gt;grant_type=refresh_token&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Bearer lifetime&lt;/td&gt;
					&lt;td&gt;~8 hours&lt;/td&gt;
					&lt;td&gt;1 hour&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Refresh token lifetime&lt;/td&gt;
					&lt;td&gt;90 days&lt;/td&gt;
					&lt;td&gt;90 days by default (configurable, at creation time only)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;API docs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;https://vra_url/automation-ui/api-docs/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;In-product &lt;strong&gt;API Help Center&lt;/strong&gt;, plus developer.broadcom.com&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The two things that break existing scripts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;You cannot get a refresh token with username and password anymore.&lt;/strong&gt; The docs are explicit: &amp;ldquo;As of VCF 9.0, the Identity Service API functionality has changed and is no longer used to obtain a refresh token programmatically.&amp;rdquo; The refresh token is now an &lt;strong&gt;API token&lt;/strong&gt; you generate once in the UI and treat like a credential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There is a tenant in the URL now.&lt;/strong&gt; VCF Automation 9 has a provider/tenant model. Everything that used to be vRA lives inside a &lt;strong&gt;VM Apps organization&lt;/strong&gt;, and the token endpoint is scoped to that org name, so step zero is finding out what yours is called.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="step-0-find-your-vm-apps-tenant-name"&gt;Step 0: Find Your VM Apps Tenant Name&lt;/h2&gt;
&lt;p&gt;Log into the Provider Management Portal (&lt;code&gt;https://vcfa.domain.com&lt;/code&gt;, the &lt;code&gt;admin&lt;/code&gt; account) and go to &lt;strong&gt;Organizations&lt;/strong&gt;. Note two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The name of your VM Apps organization, if you upgraded from Aria Automation 8.x, this is the classic tenant that was created during migration (the docs use &lt;code&gt;vcf-e2e-vidm&lt;/code&gt; as an example).&lt;/li&gt;
&lt;li&gt;The FQDN of the appliance itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need both for every call that follows.&lt;/p&gt;
&lt;h2 id="step-1-generate-an-api-token-the-new-refresh-token"&gt;Step 1: Generate an API Token (the New Refresh Token)&lt;/h2&gt;
&lt;p&gt;This is the part that moved from curl to the UI:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the VCF Automation UI at &lt;code&gt;https://vcfa.domain.com&lt;/code&gt; and switch the organization to your VM Apps tenant.&lt;/li&gt;
&lt;li&gt;Log in with a tenant account (it needs to be an org member with at least the &lt;code&gt;user&lt;/code&gt; service role, an &lt;code&gt;org_owner&lt;/code&gt; works fine).&lt;/li&gt;
&lt;li&gt;Click your name in the top-right corner and select &lt;strong&gt;My Account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;API Tokens&lt;/strong&gt; tab, click &lt;strong&gt;New&lt;/strong&gt;, give the token a name, and click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Copy the token; it is shown once.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By default the token lives for 129,600 minutes (90 days). If you want a different lifespan, set it &lt;strong&gt;before&lt;/strong&gt; creating the token under &lt;strong&gt;General Settings &amp;gt; Timeouts&lt;/strong&gt; in the Provider Management Portal (&lt;code&gt;0&lt;/code&gt; means unlimited); the lifetime is baked in at creation and cannot be changed retroactively. To kill a token early, revoke it from the same UI or via &lt;code&gt;DELETE /cloudapi/1.0.0/tokens/urn:vcloud:token:&amp;lt;token_id&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-2-exchange-the-api-token-for-an-access-token"&gt;Step 2: Exchange the API Token for an Access Token&lt;/h2&gt;
&lt;p&gt;This replaces the old &lt;code&gt;POST /iaas/api/login&lt;/code&gt;. The endpoint is a standard OAuth token endpoint, scoped to your tenant:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k --location --request POST &lt;span class="s1"&gt;&amp;#39;https://vcfa.domain.com/tm/oauth/tenant/your-vm-apps-tenant/token&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;Content-Type: application/x-www-form-urlencoded&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;Accept: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-urlencode &lt;span class="s1"&gt;&amp;#39;grant_type=refresh_token&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-urlencode &lt;span class="s1"&gt;&amp;#39;refresh_token=YOUR_API_TOKEN&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The response contains the bearer token:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;access_token&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;eyJhbGciOi...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;token_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Bearer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;expires_in&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;refresh_token&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;YOUR_API_TOKEN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The access token expires after one hour, noticeably shorter than the ~8 hours you got from &lt;code&gt;/iaas/api/login&lt;/code&gt; in 8.x, so long-running scripts should be prepared to re-run the exchange.&lt;/p&gt;
&lt;p&gt;For scripting, the whole thing collapses into one line with &lt;code&gt;jq&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -sk --request POST &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_HOST&lt;/span&gt;&lt;span class="s2"&gt;/tm/oauth/tenant/&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_TENANT&lt;/span&gt;&lt;span class="s2"&gt;/token&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/x-www-form-urlencoded&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Accept: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-urlencode &lt;span class="s1"&gt;&amp;#39;grant_type=refresh_token&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --data-urlencode &lt;span class="s2"&gt;&amp;#34;refresh_token=&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_API_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r .access_token&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-3-use-it"&gt;Step 3: Use It&lt;/h2&gt;
&lt;p&gt;The good news: once you have the access token, the API surface you know from vRA 8 is still there. The 9.1 programming guide tutorials use the same service endpoints (&lt;code&gt;/iaas/api&lt;/code&gt;, &lt;code&gt;/catalog/api&lt;/code&gt;, &lt;code&gt;/deployment/api&lt;/code&gt;, &lt;code&gt;/blueprint/api&lt;/code&gt;, &lt;code&gt;/abx&lt;/code&gt;, the Orchestrator gateway) with a plain bearer header:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_HOST&lt;/span&gt;&lt;span class="s2"&gt;/iaas/api/projects&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If a call comes back &lt;code&gt;403&lt;/code&gt;, verify what the account actually is inside the org. The docs still expose the CSP gateway for this (note the &lt;code&gt;csp-auth-token&lt;/code&gt; header instead of &lt;code&gt;Authorization&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# your org id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_HOST&lt;/span&gt;&lt;span class="s2"&gt;/csp/gateway/am/api/loggedin/user/orgs&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;csp-auth-token: &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# org role: must be org_owner or org_member&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_HOST&lt;/span&gt;&lt;span class="s2"&gt;/csp/gateway/am/api/loggedin/user/orgs/&lt;/span&gt;&lt;span class="nv"&gt;$ORG_ID&lt;/span&gt;&lt;span class="s2"&gt;/roles&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;csp-auth-token: &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# service roles: must include at least &amp;#34;user&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="nv"&gt;$VCFA_HOST&lt;/span&gt;&lt;span class="s2"&gt;/csp/gateway/am/api/loggedin/user/orgs/&lt;/span&gt;&lt;span class="nv"&gt;$ORG_ID&lt;/span&gt;&lt;span class="s2"&gt;/service-roles&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;csp-auth-token: &lt;/span&gt;&lt;span class="nv"&gt;$ACCESS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One caveat from Broadcom: scripts that authenticate against &lt;strong&gt;new&lt;/strong&gt; VM Apps organizations (created in 9.x, not upgraded from 8.x) should use the VCF Automation Provider Management Access Control APIs rather than the CSP APIs, treat the CSP gateway as a compatibility surface, not a foundation for new tooling.&lt;/p&gt;
&lt;h2 id="where-the-api-docs-moved"&gt;Where the API Docs Moved&lt;/h2&gt;
&lt;p&gt;The old in-product Swagger at &lt;code&gt;https://vra_url/automation-ui/api-docs/&lt;/code&gt; and the developer.vmware.com portal are both gone. In 9.1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In-product:&lt;/strong&gt; log into the VM Apps tenant, click your username in the top-right corner, and open &lt;strong&gt;API Help Center &amp;gt; Explore Automation APIs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Online:&lt;/strong&gt; the &lt;a href="https://developer.broadcom.com/xapis/org-management-vm-apps-org/latest/"&gt;VM Apps Org APIs on the Broadcom Developer Portal&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also worth knowing before you port scripts from 8.x: the Pipelines/Code Stream APIs (&lt;code&gt;/codestream/api/*&lt;/code&gt;), the CMX Kubernetes APIs, and the Migration Assessment APIs are removed in 9.1.&lt;/p&gt;
&lt;h2 id="a-note-on-all-apps-organizations"&gt;A Note on All Apps Organizations&lt;/h2&gt;
&lt;p&gt;Everything above covers the VM Apps organization, the classic vRA-shaped experience. The new &lt;strong&gt;All Apps&lt;/strong&gt; side of VCF Automation 9 (the Cloud Director-heritage Tenant Manager) authenticates differently again: provider tokens come from &lt;code&gt;POST /oauth/provider/token&lt;/code&gt;, and there is a session endpoint at &lt;code&gt;/cloudapi/1.0.0/sessions/provider&lt;/code&gt; that does accept basic auth and returns the bearer in the &lt;code&gt;x-vmware-vcloud-access-token&lt;/code&gt; response header. That API family deserves its own post; Christian Ferber has a good writeup linked below in the meantime.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/administration-sdks-cli-and-tools/what-are-the-automation-apis-and-how-do-i-use-them_1.html"&gt;Broadcom TechDocs - What Are the Automation APIs and How Do I Use Them (VCF 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/administration-sdks-cli-and-tools/what-are-the-automation-apis-and-how-do-i-use-them_1/getting-your-authentication-token/getting-a-refresh-token-for-the-vm-apps-tenant.html"&gt;Broadcom TechDocs - Getting a Refresh Token for the VM Apps Tenant (VCF 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/administration-sdks-cli-and-tools/what-are-the-automation-apis-and-how-do-i-use-them_1/getting-your-authentication-token/get-your-access-token-for-vra-8-x.html"&gt;Broadcom TechDocs - Get Your Access Token for the VCF Automation VM Apps API (VCF 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/administration-sdks-cli-and-tools/what-are-the-automation-apis-and-how-do-i-use-them_1/getting-your-authentication-token/verify-user-roles.html"&gt;Broadcom TechDocs - Verify User Roles (VCF 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/administration-sdks-cli-and-tools/what-are-the-automation-apis-and-how-do-i-use-them_1/getting-your-authentication-token/changing-the-lifetime-setting-of-an-api-token.html"&gt;Broadcom TechDocs - Changing the Lifetime Setting of an API Token (VCF 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vrealize.it/2025/11/06/vcf-automation-9-api-access/"&gt;vrealize.it - VCF Automation 9 API Access (All Apps / provider-side authentication)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>VCF Operations 9.1 Patch Stuck at “Installing PAK File”</title><link>https://cosmin.us/fixing-vcf-operations-9-1-express-patch-stuck-installing-pak-file/</link><pubDate>Wed, 29 Jul 2026 17:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/fixing-vcf-operations-9-1-express-patch-stuck-installing-pak-file/</guid><description>&lt;p&gt;The &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;9.1.0.0300 patch went through this lab without drama&lt;/a&gt; at the beginning of July. Three weeks later, the 9.1.0.0400 express patch for VCF Operations hit the same single-node appliance and stopped dead at &lt;strong&gt;Installing PAK file&lt;/strong&gt;: no progress, no error, and a reboot later, still nothing. What followed was a proper archaeology dig through every layer of state the upgrade machinery keeps, and almost every layer turned out to be holding a different version of the truth.&lt;/p&gt;</description><content:encoded>&lt;p&gt;The &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;9.1.0.0300 patch went through this lab without drama&lt;/a&gt; at the beginning of July. Three weeks later, the 9.1.0.0400 express patch for VCF Operations hit the same single-node appliance and stopped dead at &lt;strong&gt;Installing PAK file&lt;/strong&gt;: no progress, no error, and a reboot later, still nothing. What followed was a proper archaeology dig through every layer of state the upgrade machinery keeps, and almost every layer turned out to be holding a different version of the truth.&lt;/p&gt;
&lt;p&gt;The short version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The upgrade died &lt;strong&gt;two seconds&lt;/strong&gt; into the OS update phase because the glob over &lt;code&gt;/etc/yum.repos.d/*&lt;/code&gt; matched &lt;strong&gt;nothing&lt;/strong&gt; (the directory had been emptied (or removed; the error is identical either way)) and &lt;code&gt;sed&lt;/code&gt; exiting 2 on it is fatal to &lt;code&gt;updateCoordinator.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The failure was recorded in pakManager&amp;rsquo;s results file, and from then on a &lt;strong&gt;retry guard&lt;/strong&gt; rejected every new attempt in milliseconds, while CaSA kept retrying roughly &lt;strong&gt;every 11–12 seconds&lt;/strong&gt;, over 1,100 times in the retained logs alone.&lt;/li&gt;
&lt;li&gt;The UI said &lt;em&gt;Installing&lt;/em&gt; the whole time because CaSA&amp;rsquo;s own pak history had the &lt;code&gt;APPLY_OS_UPDATE&lt;/code&gt; operation with a &lt;strong&gt;null &lt;code&gt;completed_time&lt;/code&gt;&lt;/strong&gt;: stale state, not activity.&lt;/li&gt;
&lt;li&gt;Rebooting did not retry anything; it just rebuilt the same wedge, with the cluster still offline because &lt;em&gt;offline&lt;/em&gt; is persisted state.&lt;/li&gt;
&lt;li&gt;The recovery attempts then failed in two brand-new ways: a &lt;strong&gt;409 &lt;code&gt;pak_installation_active&lt;/code&gt;&lt;/strong&gt; raised when the precheck&amp;rsquo;s state check collided with the assessment install the precheck itself had just launched, and a &lt;strong&gt;NullPointerException&lt;/strong&gt; when LCM asked CaSA for an upgrade task that no longer existed anywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Versions in play: VCF Operations &lt;strong&gt;9.1.0.0300.25531073&lt;/strong&gt; upgrading to &lt;strong&gt;9.1.0.0400.25541550&lt;/strong&gt;, on a single-node deployment, driven by the express patch workflow in fleet management. All timestamps below are UTC, straight from the logs.&lt;/p&gt;
&lt;h2 id="the-symptom-installing-pak-file-forever"&gt;The Symptom: Installing PAK File, Forever&lt;/h2&gt;
&lt;p&gt;The express patch staged cleanly and started applying, then sat at &lt;em&gt;Installing PAK file&lt;/em&gt; for hours. A reboot later it still showed the same thing. Time to stop watching the progress bar and go look at what the appliance was actually doing.&lt;/p&gt;
&lt;p&gt;The places that matter for any PAK-based upgrade on a VCF Operations node:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;What&lt;/th&gt;
					&lt;th&gt;Where&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;pakManager action logs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/log/vcops/log/pakManager/vcopsPakManager.root.&amp;lt;action&amp;gt;.log&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Per-PAK script stdout/stderr&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/log/vcops/log/pakManager/&amp;lt;pak-id&amp;gt;/&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;PAK working state + results&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/db/pakRepoLocal/&amp;lt;pak-id&amp;gt;/&amp;lt;pak-id&amp;gt;.results&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;pakManager action history&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/db/pakRepoLocal/vcopsPakManagerCommonHistory.json&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CaSA logs + per-PAK history&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/log/vcops/log/casa/&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Staged PAK binaries&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/db/casa/pak/dist_pak_files/VA_LINUX/&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The PAK for this patch is &lt;code&gt;vRealizeOperationsManagerEnterprise-910040025541550&lt;/code&gt;: the ID is the version string with the dots removed, &lt;code&gt;9.1.0.0400.25541550&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="finding-the-loop"&gt;Finding the Loop&lt;/h2&gt;
&lt;p&gt;The first thing that stood out was not an error message but a rotation pattern. &lt;code&gt;vcopsPakManager.root.apply_os_update.log&lt;/code&gt; keeps twenty rotated files of 1 MB each, and every one of them was less than four hours old; the log was burning a full rotation roughly every 11 minutes. Something was running &lt;code&gt;apply_os_update&lt;/code&gt; constantly.&lt;/p&gt;
&lt;p&gt;Each attempt ended the same way, in milliseconds (log prefixes trimmed for width here and throughout):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[VerifyActionNotRunningOrRun] - apply_os_update result: &amp;#34;Failed&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[VerifyActionNotRunningOrRun] - apply_os_update exit code: &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[HandleError] - Exiting with exit code: 1, message: The action: apply_os_update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;on the pak file: &amp;#34;vRealizeOperationsManagerEnterprise-910040025541550&amp;#34; previously
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;failed, cleanup the system and remove_history before attempting again--exiting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is pakManager&amp;rsquo;s retry guard: once an action has &lt;code&gt;Failed&lt;/code&gt; in the PAK&amp;rsquo;s &lt;code&gt;.results&lt;/code&gt; file, every subsequent invocation is rejected before any script runs. And CaSA (the admin/cluster service that orchestrates PAK operations) was invoking it again roughly every 11–12 seconds, each time via:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/bin/sudo -n /usr/lib/vmware-python-3/bin/python
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /usr/lib/vmware-vcopssuite/utilities/pakManager/bin/vcopsPakManager.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --action apply_os_update --pak vRealizeOperationsManagerEnterprise-910040025541550
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --json --force_content_update true --roles ADMIN,DATA,UI
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The retained logs held &lt;strong&gt;1,125&lt;/strong&gt; rejections spanning just under four hours, and CaSA&amp;rsquo;s logs show the loop reaching back to the previous evening. An install loop where every iteration is refused on arrival: the upgrade could not move forward and would never stop trying. So the interesting question became: what failed the &lt;em&gt;first&lt;/em&gt; time?&lt;/p&gt;
&lt;h2 id="the-root-cause-one-sed-against-an-empty-directory"&gt;The Root Cause: One sed Against an Empty Directory&lt;/h2&gt;
&lt;p&gt;CaSA&amp;rsquo;s operation history gives the setup, and the per-PAK stderr log (&lt;code&gt;/storage/log/vcops/log/pakManager/vRealizeOperationsManagerEnterprise-910040025541550/apply_os_update_stderr.log&lt;/code&gt;) gives the kill. The timeline on July 28:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;17:42:27 → 17:42:33&lt;/code&gt;: validation runs and passes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;17:42:45 → 17:44:29&lt;/code&gt;: &lt;code&gt;BRING_CLUSTER_OFFLINE&lt;/code&gt; completes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;17:44:37&lt;/code&gt;: &lt;code&gt;APPLY_OS_UPDATE&lt;/code&gt; starts&lt;/li&gt;
&lt;li&gt;&lt;code&gt;17:44:39&lt;/code&gt;: the very first command of the VA upgrade phase runs, and dies:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[b2b - updateCoordinator - os_upgrade] - Entering VA upgrade phase
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[b2b - updateCoordinator - os_upgrade] - Disable existing repositories
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[b2b - updateCoordinator - runScript] - Script command:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;/usr/bin/sed -i &amp;#34;s/enabled=1/enabled=0/g&amp;#34; /etc/yum.repos.d/*&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[b2b - updateCoordinator - runScript] - stderr:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;/usr/bin/sed: can&amp;#39;t read /etc/yum.repos.d/*: No such file or directory&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[b2b - updateCoordinator - runScript] - exit code: 2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[b2b - updateCoordinator - programExit] - Unable to disable existing repositories for updates.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The glob over &lt;code&gt;/etc/yum.repos.d/*&lt;/code&gt; matched nothing: the shell passed the literal string through, &lt;code&gt;sed&lt;/code&gt; could not open it, and exited 2. That error is byte-identical whether the directory is empty or missing outright; by the time anyone could look, the files were back, so all the log proves is that there was nothing there to match. &lt;code&gt;updateCoordinator.py&lt;/code&gt; treats a non-zero exit here as fatal, reasonably, since it is about to drive &lt;code&gt;tdnf&lt;/code&gt; package operations and wants external repositories disabled first.&lt;/p&gt;
&lt;p&gt;Two details make this sting:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The upgrade does not need working external repos at all.&lt;/strong&gt; The very next steps in a healthy run copy the PAK&amp;rsquo;s own &lt;code&gt;local-pak-iso.repo&lt;/code&gt; into that directory and install everything from the ISO embedded in the PAK. The &lt;code&gt;sed&lt;/code&gt; only needs the glob to match &lt;em&gt;at least one file&lt;/em&gt;. A directory with nothing in it is the one state it cannot survive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This exact command succeeded three weeks earlier.&lt;/strong&gt; The 0300 patch on July 5 logged the identical &lt;code&gt;sed&lt;/code&gt; with an empty stderr and exit 0, then dropped &lt;code&gt;local-pak-iso.repo&lt;/code&gt; in place and carried on. So the directory was populated on July 5 and held nothing the glob could match by July 28, something removed those files in between. More on the suspects at the end.&lt;/p&gt;
&lt;p&gt;One more log-reading trap: the failure &lt;em&gt;looks&lt;/em&gt; like it took ten minutes, because after the fatal error &lt;code&gt;updateCoordinator.py&lt;/code&gt; spends from &lt;code&gt;17:44:39&lt;/code&gt; to &lt;code&gt;17:54:47&lt;/code&gt; generating a support bundle before it exits. The &lt;code&gt;Failed&lt;/code&gt; result lands in the state files at &lt;code&gt;17:54:47&lt;/code&gt;, ten minutes after the two-second failure. If you correlate timestamps across logs, that gap is the tool being helpful, not the upgrade doing work.&lt;/p&gt;
&lt;h2 id="why-it-looked-stuck-instead-of-failed"&gt;Why It Looked Stuck Instead of Failed&lt;/h2&gt;
&lt;p&gt;Here is the part that turned a two-second failure into a day of confusion. The upgrade machinery keeps (at least) &lt;strong&gt;four separate stores of state&lt;/strong&gt;, and they disagreed:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Store&lt;/th&gt;
					&lt;th&gt;Path&lt;/th&gt;
					&lt;th&gt;Owner&lt;/th&gt;
					&lt;th&gt;What it said&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;PAK results file&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/db/pakRepoLocal/&amp;lt;pak-id&amp;gt;/&amp;lt;pak-id&amp;gt;.results&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;pakManager&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;apply_os_update_result: Failed&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Action history&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/db/pakRepoLocal/vcopsPakManagerCommonHistory.json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;pakManager&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;apply_os_update: Failed&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Per-PAK operation history&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/storage/log/vcops/log/casa/casa_pak_history_&amp;lt;pak-id&amp;gt;.json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;CaSA&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;APPLY_OS_UPDATE&lt;/code&gt; started, &lt;strong&gt;never completed&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Upgrade orchestrator documents&lt;/td&gt;
					&lt;td&gt;CaSA runtime&lt;/td&gt;
					&lt;td&gt;CaSA&lt;/td&gt;
					&lt;td&gt;operation active, keep retrying&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The UI renders from CaSA&amp;rsquo;s view. Its per-PAK history file ended like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;operation&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;APPLY_OS_UPDATE&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;start_time&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1785260677162&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;completed_time&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An operation with a start time and a null completion is, as far as the UI is concerned, &lt;em&gt;still installing&lt;/em&gt;. pakManager knew the upgrade had failed; CaSA never wrote a terminal result for the operation. Both were internally consistent. Neither was lying. They just were not the same state machine.&lt;/p&gt;
&lt;h2 id="why-rebooting-did-not-help"&gt;Why Rebooting Did Not Help&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;BRING_CLUSTER_OFFLINE&lt;/code&gt; had completed &lt;em&gt;before&lt;/em&gt; the failure, and offline is persisted admin state. After the reboot, the platform came up and refused to start its services on purpose, from the support bundle&amp;rsquo;s &lt;code&gt;sysenv/status.txt&lt;/code&gt;, captured while it was down:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmware-vcops.service - LSB: vRealize Operations Platform
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Active: failed (Result: exit-code)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; vpostgres Cannot be started as the slice is offline
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; analytics Cannot be started as the slice is offline
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; collector Cannot be started as the slice is offline
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; api Cannot be started as the slice is offline
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So the reboot traded a stuck upgrade on a running cluster for a stuck upgrade on a &lt;strong&gt;down&lt;/strong&gt; cluster. One genuinely useful side effect: the retry loop did not survive the restart. CaSA&amp;rsquo;s orchestrator documents came back empty (&lt;code&gt;current_pak_activity&lt;/code&gt; all nulls from the first post-reboot poll onward) so the hammering stopped; the last &lt;code&gt;apply_os_update&lt;/code&gt; attempt in the logs is from just before the reboot. But nothing resumed, either. The upgrade was now fully inert: no process running, no retries, UI still saying &lt;em&gt;Installing&lt;/em&gt;, and monitoring down with it.&lt;/p&gt;
&lt;p&gt;Bringing the cluster back online restored the data-collection side of the house (services active, slice &lt;code&gt;ONLINE&lt;/code&gt;, still on 9.1.0.0300) while the upgrade state stayed exactly as wedged as before. Stale state does not age out. Waiting was never going to fix this.&lt;/p&gt;
&lt;h2 id="clearing-the-pak-state-cli-archaeology"&gt;Clearing the PAK State: CLI Archaeology&lt;/h2&gt;
&lt;p&gt;The guard message says what it wants: &lt;em&gt;&amp;ldquo;cleanup the system and remove_history before attempting again.&amp;rdquo;&lt;/em&gt; Turning that sentence into working commands took several tries, and the failed attempts are worth documenting because the CLI&amp;rsquo;s own error messages actively mislead.&lt;/p&gt;
&lt;p&gt;First lesson: run it with &lt;code&gt;python3&lt;/code&gt;. The script does not behave as a direct executable: invoked by path, the shell tries to interpret Python as shell (abridged, full path shortened):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vcopsPakManager.py: line 6: from: command not found
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vcopsPakManager.py: line 10: import: command not found
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vcopsPakManager.py: line 31: syntax error near unexpected token `(&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 /usr/lib/vmware-vcopssuite/utilities/pakManager/bin/vcopsPakManager.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run bare like that, it prints its full usage, which is where the trap sits. The guard message names &lt;code&gt;remove_history&lt;/code&gt; as if it were an action. It is not. It is a &lt;strong&gt;parameter of the &lt;code&gt;cleanup&lt;/code&gt; action&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cleanup - remove temp and working files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; params:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --remove_history (ACTION|all) - remove the history for the action. The parameter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; is the action, or &amp;#34;all&amp;#34; to remove all history
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --remove_pak - removes the pak file and all history
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --skip_history_update - removes the pak without updating history
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The tour of error messages on the way there:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--action remove_history ... → Action: &amp;#34;remove_history&amp;#34; is not valid
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--action cleanup --remove_history --pak &amp;lt;pak&amp;gt; → Action: --pak is not supported for remove_history
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--action cleanup --remove_history → option --remove_history requires argument
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--action cleanup --remove_pak &amp;lt;pak&amp;gt; → No PAK file specified
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second one is the nasty one: &lt;code&gt;--remove_history&lt;/code&gt; requires an argument, so it silently consumed &lt;code&gt;--pak&lt;/code&gt; as its value and then complained that &lt;code&gt;--pak&lt;/code&gt; is not a valid action name. And the fourth shows &lt;code&gt;--remove_pak&lt;/code&gt; is a bare flag, not an option that takes the PAK name, the PAK always goes in &lt;code&gt;--pak&lt;/code&gt;. The forms that worked:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 /usr/lib/vmware-vcopssuite/utilities/pakManager/bin/vcopsPakManager.py &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --action cleanup --pak vRealizeOperationsManagerEnterprise-910040025541550
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 /usr/lib/vmware-vcopssuite/utilities/pakManager/bin/vcopsPakManager.py &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --action cleanup --remove_history all --pak vRealizeOperationsManagerEnterprise-910040025541550
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And one final surprise from the results file afterwards: &lt;code&gt;--remove_history all&lt;/code&gt; flipped a dozen keys to &lt;code&gt;&amp;quot;history removed&amp;quot;&lt;/code&gt;, but not the ones that mattered:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apply_adapter_result: history removed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apply_system_update_result: history removed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;new_validate_result: history removed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;validate_result: Failed ← survived
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apply_os_update_result: Failed ← survived
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apply_os_update_exit_code: 1 ← survived
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Several statuses outlived the removal, including, of all things, the &lt;code&gt;apply_os_update&lt;/code&gt; Failed/exit-1 pair that is exactly what the retry guard checks. Keep that in mind for the endgame below.&lt;/p&gt;
&lt;p&gt;While in there, this is also the moment to fix the actual root cause, put repo definitions back in &lt;code&gt;/etc/yum.repos.d/&lt;/code&gt;. A snapshot, a sibling appliance, or the Photon base image all work as a source; strictly speaking the upgrade only needs the glob to match one file, but restoring the stock set is the right fix. Healthy looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;local-pak-iso.repo photon-extras.repo photon-release.repo photon-srpms.repo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;photon-debuginfo.repo photon-iso.repo photon.repo photon-updates.repo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-precheck-409-colliding-with-your-own-assessment"&gt;The Precheck 409: Colliding With Your Own Assessment&lt;/h2&gt;
&lt;p&gt;With pakManager&amp;rsquo;s state cleared and the repo directory restored, the next upgrade precheck failed after about a minute with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;An unexpected error occurred in step ops_precheck. Reference Code: EEF54002.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;409: upgrade.verification.pak_installation_active
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PreConditionFailedCasaException: key=upgrade.verification.pak_installation_active
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My first theory was the obvious one, that null-&lt;code&gt;completed_time&lt;/code&gt; entry still sitting in CaSA&amp;rsquo;s history. The CaSA log killed that theory and replaced it with something stranger. The precheck works by staging and installing an assessment PAK (&lt;code&gt;APUAT-for-814x&lt;/code&gt;) on the appliance, and the sequence around the failure reads:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;19:03:20 verifyConsistentState PAK_INSTALL → Cluster is in consistent state
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;19:03:21 APUAT-for-814x staged; validation, then apply_system_update begins
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;19:04:01 OrchestratorStatusDocument: current_pak_activity =
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&amp;#34;pak_id&amp;#34;:&amp;#34;APUAT-for-814x-910025541563&amp;#34;,&amp;#34;operation_name&amp;#34;:&amp;#34;APPLY_SYSTEM_UPDATE&amp;#34;,&amp;#34;step&amp;#34;:12,...}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;19:04:01 verifyConsistentState PAK_INSTALL, again
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;19:04:02 Cluster state check failed: PreConditionFailedCasaException:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; key=upgrade.verification.pak_installation_active
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same consistency check passed at &lt;code&gt;19:03:20&lt;/code&gt; with no PAK active, and failed 41 seconds later because a PAK installation &lt;em&gt;was&lt;/em&gt; genuinely active, &lt;strong&gt;the assessment install the precheck itself had just launched&lt;/strong&gt;. The stale enterprise-PAK entry was nowhere in it; CaSA was telling the truth about a collision between two halves of the same workflow. Meanwhile the assessment PAK, indifferent to the LCM step failing above it, ran to a clean finish in under twelve minutes, one more case of the layers not sharing a reality.&lt;/p&gt;
&lt;p&gt;Two useful tools on the CaSA side regardless. Its deployment state is queryable directly, and note it reported &lt;code&gt;&amp;quot;DONE&amp;quot;&lt;/code&gt; &lt;em&gt;while the 409 was still reproducible&lt;/em&gt;, so treat it as one more opinion, not an oracle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin https://localhost/casa/deployment/cluster/installationstate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the non-destructive reset is restarting the service:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl restart vmware-casa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I restarted CaSA and re-ran the precheck; this run went clean end to end: the assessment PAK staged, validated, installed, and cleaned up in thirteen minutes, and the step reported success. Whether the restart mattered or the retry simply avoided the earlier collision, I cannot prove from the logs; what the evidence does show is that the null-completion history entry was still in place, untouched, during the passing run. It was never the thing the 409 keyed on.&lt;/p&gt;
&lt;h2 id="the-nullpointerexception-asking-an-empty-orchestrator-for-a-task"&gt;The NullPointerException: Asking an Empty Orchestrator for a Task&lt;/h2&gt;
&lt;p&gt;Precheck green, one more attempt at the actual upgrade, and a new reference code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;An unexpected error occurred in step ops_apply_upgrade. Reference Code: 90AD4093.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Detail: Cannot invoke &amp;#34;com.broadcom.vcf.lcm.sddc.upgrade.sdk.client.appliance.model.Task.getId()&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;because &amp;#34;task&amp;#34; is null
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An NPE in the LCM client is a product bug in the sense that it hides the real condition, but the underlying state is easy to read. CaSA&amp;rsquo;s orchestrator, logged on every status poll, was completely empty:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;UpdateOrchestratorDocument={&amp;#34;casa_webapp_pak_id&amp;#34;:null,&amp;#34;casa_webapp_force_content_update&amp;#34;:false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;casa_pak_status&amp;#34;:{}}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OrchestratorStatusDocument: {&amp;#34;current_pak_activity&amp;#34;:{&amp;#34;pak_id&amp;#34;:null,&amp;#34;operation_name&amp;#34;:null,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;step&amp;#34;:0,&amp;#34;total_steps&amp;#34;:0,...},...,&amp;#34;queued_pak_ids&amp;#34;:[],&amp;#34;is_upgrade_orchestrator_active&amp;#34;:false,...}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the PAK&amp;rsquo;s working directory was down to two files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/storage/db/pakRepoLocal/vRealizeOperationsManagerEnterprise-910040025541550/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── manifest.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── vRealizeOperationsManagerEnterprise-910040025541550.results ← still says Failed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Two separate subtractions added up to this. The reboot had emptied CaSA&amp;rsquo;s runtime documents and queue, that happened back at 12:43, and it is what stopped the retry loop. The &lt;code&gt;cleanup&lt;/code&gt; action had then removed the extracted PAK content from &lt;code&gt;pakRepoLocal&lt;/code&gt;: which is its job. Between the two, nothing on the appliance still described an in-flight upgrade, so when LCM told CaSA to proceed with the apply step, there was no registered PAK, no queued operation, and nothing to build a task from. CaSA returned no task; the LCM client dereferenced it; NPE. The pendulum had swung all the way from &lt;em&gt;state says failed, refuse to run&lt;/em&gt; to &lt;em&gt;no state at all, nothing to run&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The original binary survives, though, cleanup did not touch the staged PAK repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;locate .pak &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="m"&gt;0400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/storage/db/casa/pak/dist_pak_files/VA_LINUX/vRealizeOperationsManagerEnterprise-910040025541550.pak
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;plus the &lt;span class="m"&gt;0400&lt;/span&gt; license-server and cloud-proxy PAKs, trimmed&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-clean-path-out"&gt;The Clean Path Out&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ What follows is the planned remediation from this point, not a procedure I have verified end to end, which is exactly why step 1 exists. It is a lab; on a production deployment, this is the moment to take the reference codes (&lt;code&gt;EEF54002&lt;/code&gt;, &lt;code&gt;90AD4093&lt;/code&gt;) and the support bundle to an SR instead of editing state by hand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At this point the environment is: cluster online and collecting, on 9.1.0.0300; repo directory restored; precheck passing; PAK binary staged; and two pieces of stale state left, the &lt;code&gt;Failed&lt;/code&gt; survivor keys in the results file and the null-completion entry in CaSA&amp;rsquo;s per-PAK history. The way out is to stop half-clearing and reset the PAK completely, then let the workflow rebuild everything from the binary:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Snapshot the appliance.&lt;/strong&gt; The cluster is healthy right now; protect that before another attempt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remove the PAK and all of its history.&lt;/strong&gt; Per the usage text, &lt;code&gt;--remove_pak&lt;/code&gt; &amp;ldquo;removes the pak file and all history.&amp;rdquo; Note this is the one cleanup variant I have not exercised, and given that &lt;code&gt;--remove_history all&lt;/code&gt; left the &lt;code&gt;Failed&lt;/code&gt; keys standing, do not take the usage text on faith:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 /usr/lib/vmware-vcopssuite/utilities/pakManager/bin/vcopsPakManager.py &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --action cleanup --remove_pak --pak vRealizeOperationsManagerEnterprise-910040025541550
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Afterwards, verify the &lt;code&gt;pakRepoLocal&lt;/code&gt; directory (with its &lt;code&gt;.results&lt;/code&gt; file) is actually gone, and that the staged binary in &lt;code&gt;/storage/db/casa/pak/dist_pak_files/VA_LINUX/&lt;/code&gt; is still there, if &lt;code&gt;--remove_pak&lt;/code&gt; reaches into the staged repository too, the workflow will need to re-download the PAK, which is inconvenient rather than fatal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clear CaSA&amp;rsquo;s per-PAK history&lt;/strong&gt; so the UI stops rendering the ghost &lt;em&gt;Installing&lt;/em&gt; operation and nothing can ever mistake it for an active install again, with the service stopped, move the stale file aside:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl stop vmware-casa
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv /storage/log/vcops/log/casa/casa_pak_history_vRealizeOperationsManagerEnterprise-910040025541550.json /root/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl start vmware-casa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Re-run the express patch from the beginning&lt;/strong&gt;, not as a resume. With the staged &lt;code&gt;.pak&lt;/code&gt; in place there is nothing to re-download; the workflow re-stages, re-validates, and (with &lt;code&gt;/etc/yum.repos.d/&lt;/code&gt; populated) should get past the two-second mark it never survived before. Expect the cluster to go offline again for the apply; that is the designed behavior (&lt;code&gt;bring_cluster_offline: true&lt;/code&gt; in the manifest), so schedule it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;What success looks like once the re-run goes through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The appliance reports &lt;strong&gt;9.1.0.0400.25541550&lt;/strong&gt; and the express patch workflow completes without a reference code.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -k -u admin https://localhost/casa/deployment/cluster/installationstate&lt;/code&gt; returns &lt;code&gt;&amp;quot;DONE&amp;quot;&lt;/code&gt;, with no failed step behind it this time.&lt;/li&gt;
&lt;li&gt;The new &lt;code&gt;casa_pak_history_vRealizeOperationsManagerEnterprise-910040025541550.json&lt;/code&gt; shows every operation, &lt;code&gt;APPLY_OS_UPDATE&lt;/code&gt; included, with a &lt;strong&gt;non-null&lt;/strong&gt; &lt;code&gt;completed_time&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The cluster slice is &lt;code&gt;ONLINE&lt;/code&gt; and collecting, and no &lt;code&gt;apply_os_update&lt;/code&gt; invocations appear in the pakManager logs after completion, the loop stays dead.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/yum.repos.d/&lt;/code&gt; is still populated. If it is empty again, find the culprit before the next patch does this all over.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-actually-emptied-etcyumreposd"&gt;What Actually Emptied /etc/yum.repos.d?&lt;/h2&gt;
&lt;p&gt;The unresolved thread. The directory was demonstrably populated on July 5 (the 0300 patch&amp;rsquo;s &lt;code&gt;sed&lt;/code&gt; succeeded and copied &lt;code&gt;local-pak-iso.repo&lt;/code&gt; into it) and demonstrably held nothing the glob could match on July 28. Neither observed upgrade run removed those files, and the PAK cleanup actions do not reach into &lt;code&gt;/etc&lt;/code&gt;. Something else did, in the three-week window between patches.&lt;/p&gt;
&lt;p&gt;The usual suspects are STIG/hardening remediation, a compliance scan &amp;ldquo;fixing&amp;rdquo; findings, or an overzealous cleanup script, and the hardening theory is less hypothetical than it sounds: the appliance ships a STIG-hardening Ansible role that the upgrade itself runs during &lt;code&gt;apply_system_update&lt;/code&gt;, and its task list includes a literal &lt;strong&gt;&amp;ldquo;Find yum repos&amp;rdquo;&lt;/strong&gt; step. A framework that polices exactly this directory demonstrably lives on the box; the July runs used it non-destructively, but whatever emptied the directory operated on the same territory. I have not caught the culprit in the act, so the case stays open.&lt;/p&gt;
&lt;p&gt;If that something is scheduled, it will do it again, and the next express patch will die the same two-second death. Before every PAK-based upgrade on a VCF Operations appliance, it now costs me one command to check:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /etc/yum.repos.d/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Empty directory, no upgrade. It is that direct.&lt;/p&gt;
&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A stuck progress bar is a claim, not a fact.&lt;/strong&gt; The UI renders CaSA&amp;rsquo;s operation history; a null &lt;code&gt;completed_time&lt;/code&gt; displays as &lt;em&gt;Installing&lt;/em&gt; forever, even when the failure happened in two seconds and nothing has run since. The pakManager logs are where the truth lives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Know the four state stores&lt;/strong&gt;: per-PAK results file, &lt;code&gt;vcopsPakManagerCommonHistory.json&lt;/code&gt;, CaSA&amp;rsquo;s &lt;code&gt;casa_pak_history_&amp;lt;pak&amp;gt;.json&lt;/code&gt;, and CaSA&amp;rsquo;s runtime orchestrator documents. Every confusing symptom in this saga was two of them disagreeing, including the 409, where the precheck disagreed with the assessment install it had launched itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The retry guard message is honest but the CLI is not literal about it&lt;/strong&gt;: &lt;code&gt;remove_history&lt;/code&gt; is a parameter of &lt;code&gt;--action cleanup&lt;/code&gt;, not an action, and a missing argument makes it eat the next flag with a misleading error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify what state-clearing commands actually cleared.&lt;/strong&gt; &lt;code&gt;--remove_history all&lt;/code&gt; reported nothing wrong while leaving the &lt;code&gt;apply_os_update: Failed&lt;/code&gt; keys (the exact ones the guard checks) untouched. After any cleanup, read the &lt;code&gt;.results&lt;/code&gt; file; do not assume.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cleanup&lt;/code&gt; without the root cause fixed is a trap.&lt;/strong&gt; The guard fires &lt;em&gt;before&lt;/em&gt; the script runs; clear the state while &lt;code&gt;/etc/yum.repos.d/&lt;/code&gt; is still empty and the next attempt fails in two seconds and re-arms it, from an offline cluster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reboots do not clear persisted upgrade state.&lt;/strong&gt; Offline stays offline, &lt;code&gt;Failed&lt;/code&gt; stays &lt;code&gt;Failed&lt;/code&gt;, and the null completion stays null. What a reboot &lt;em&gt;did&lt;/em&gt; do here is wipe CaSA&amp;rsquo;s runtime orchestrator: which killed the retry loop, made the wedge quieter and easier to misread as idle, and set up the eventual task-is-null NPE.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fatal-error support bundles skew timelines.&lt;/strong&gt; Nearly all of the ten minutes this &amp;ldquo;upgrade&amp;rdquo; ran were &lt;code&gt;generateSupportBundle.py&lt;/code&gt; executing after the fatal error. Read the stderr log inward from the first ERROR, not the timestamps outward.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check &lt;code&gt;/etc/yum.repos.d/&lt;/code&gt; before any PAK upgrade&lt;/strong&gt;, and find out what is emptying it, whatever removed those files will break the next patch identically if it runs again.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="final-notes"&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;Every stage of this one was the same lesson wearing different clothes: the upgrade machinery is several loosely-coupled state machines, and each error message was one machine reporting its own local truth. pakManager said &lt;em&gt;previously failed&lt;/em&gt;; CaSA said &lt;em&gt;still installing&lt;/em&gt;; the precheck said &lt;em&gt;installation active&lt;/em&gt;, correctly, about the assessment install it had just started itself; LCM said &lt;em&gt;task is null&lt;/em&gt;. Every statement was locally accurate, none of them described the system, and the actual root cause (a directory that a three-week-old patch run proves used to be populated) never appeared in any of them.&lt;/p&gt;
&lt;p&gt;The two-second failure was trivial. The day was spent on state.&lt;/p&gt;</content:encoded></item><item><title>VCF Operations for Networks 9.1 Search Queries: The vRNI Query Language Lives On</title><link>https://cosmin.us/vcf-operations-for-networks-9-1-search-queries/</link><pubDate>Mon, 27 Jul 2026 07:00:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/vcf-operations-for-networks-9-1-search-queries/</guid><description>&lt;p&gt;If you spent years typing &lt;code&gt;flows where firewall action = deny&lt;/code&gt; into vRealize Network Insight, then watched the product get renamed to Aria Operations for Networks and then absorbed into VCF Operations as &lt;strong&gt;VCF Operations for Networks&lt;/strong&gt;, you probably have one practical question: did the search language survive?&lt;/p&gt;
&lt;p&gt;It did, completely. I compared the VCF Operations for Networks 9.1 search documentation against the legacy Aria Operations for Networks 6.13 docs page by page, and the query grammar is identical: same entity types, same &lt;code&gt;where&lt;/code&gt; operators, same &lt;code&gt;group by&lt;/code&gt; / &lt;code&gt;order by&lt;/code&gt; / &lt;code&gt;limit&lt;/code&gt; clauses, same planning and path queries. Even the REST API still answers under the old &lt;code&gt;/api/ni/&lt;/code&gt; (Network Insight) namespace. Your saved searches and your muscle memory carry over as-is.&lt;/p&gt;</description><content:encoded>&lt;p&gt;If you spent years typing &lt;code&gt;flows where firewall action = deny&lt;/code&gt; into vRealize Network Insight, then watched the product get renamed to Aria Operations for Networks and then absorbed into VCF Operations as &lt;strong&gt;VCF Operations for Networks&lt;/strong&gt;, you probably have one practical question: did the search language survive?&lt;/p&gt;
&lt;p&gt;It did, completely. I compared the VCF Operations for Networks 9.1 search documentation against the legacy Aria Operations for Networks 6.13 docs page by page, and the query grammar is identical: same entity types, same &lt;code&gt;where&lt;/code&gt; operators, same &lt;code&gt;group by&lt;/code&gt; / &lt;code&gt;order by&lt;/code&gt; / &lt;code&gt;limit&lt;/code&gt; clauses, same planning and path queries. Even the REST API still answers under the old &lt;code&gt;/api/ni/&lt;/code&gt; (Network Insight) namespace. Your saved searches and your muscle memory carry over as-is.&lt;/p&gt;
&lt;p&gt;The short version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VCF Operations 9.1 has &lt;strong&gt;one console but at least four separate query languages&lt;/strong&gt;: the networks entity search (vRNI heritage), the Enhanced Search metric queries (vROps heritage), log search under Operate &amp;gt; Logs, and the new-in-9.1 PromQL Custom Query for real-time metrics. Knowing which bar you are typing into matters more than any syntax detail.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;networks search DSL is unchanged&lt;/strong&gt; from vRNI/AON: &lt;code&gt;&amp;lt;projection&amp;gt; of &amp;lt;entity&amp;gt; where &amp;lt;condition&amp;gt; group by &amp;lt;property&amp;gt; order by &amp;lt;field&amp;gt; limit N&lt;/code&gt;, plus &lt;code&gt;top N&lt;/code&gt;, &lt;code&gt;in last N days&lt;/code&gt;, path queries (&lt;code&gt;VM 'a' to VM 'b'&lt;/code&gt;), and &lt;code&gt;plan&lt;/code&gt; queries for micro-segmentation.&lt;/li&gt;
&lt;li&gt;The 9.1 differences are cosmetic or peripheral: NSX Advanced Load Balancer is renamed &lt;strong&gt;Avi Load Balancer&lt;/strong&gt; in the docs, &amp;ldquo;VMware Cloud (VMC)&amp;rdquo; prose became &amp;ldquo;VMware Cloud on AWS&amp;rdquo;, the VMware SD-WAN (VeloCloud) search-queries page is gone from the 9.1 doc tree, and &lt;strong&gt;AWS/Azure data sources are deprecated&lt;/strong&gt; in 9.1.&lt;/li&gt;
&lt;li&gt;The classic community query lists (the ones we all bookmarked in the vRNI days) still apply. I have collected the best of them below, together with the official examples, into one cookbook.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything here is based on the 9.1 documentation set and verified against the legacy 6.13 docs; sources are linked at the end.&lt;/p&gt;
&lt;h2 id="one-console-four-query-languages"&gt;One Console, Four Query Languages&lt;/h2&gt;
&lt;p&gt;The single most confusing thing about search in VCF Operations 9.1 is that &amp;ldquo;search&amp;rdquo; is not one feature. The console consolidates products that each brought their own query engine, and none of them were merged:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Query surface&lt;/th&gt;
					&lt;th&gt;Where it lives in 9.1&lt;/th&gt;
					&lt;th&gt;Grammar&lt;/th&gt;
					&lt;th&gt;Lineage&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Networks entity search&lt;/td&gt;
					&lt;td&gt;Inside the VCF Operations for Networks section (Operate pillar)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;entity where ... group by ...&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;vRNI / Aria Operations for Networks&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Enhanced Search (metric queries)&lt;/td&gt;
					&lt;td&gt;The global search bar in the top menu, on every page&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Metric of Object Type where ... childOf ...&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;vROps / Aria Operations&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Log search&lt;/td&gt;
					&lt;td&gt;Operate &amp;gt; Logs&lt;/td&gt;
					&lt;td&gt;Log filtering, alert queries, field extraction&lt;/td&gt;
					&lt;td&gt;Aria Operations for Logs&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Custom Query (new in 9.1)&lt;/td&gt;
					&lt;td&gt;Operate &amp;gt; Real-Time Metrics / Troubleshooting Workbench&lt;/td&gt;
					&lt;td&gt;PromQL&lt;/td&gt;
					&lt;td&gt;New real-time metrics pipeline&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This post is mainly about the first one, because that is where the network troubleshooting value is. The second gets its own section further down, since the two are easy to conflate: the same word &lt;code&gt;where&lt;/code&gt; appears in both grammars but the operator sets are different. The 9.1 release notes only call out one genuinely new query mechanism, and it is the fourth: &amp;ldquo;Use PromQL-based search queries to derive operational insights.&amp;rdquo; Neither the networks DSL nor the Enhanced Search grammar changed in 9.1.&lt;/p&gt;
&lt;p&gt;A note on architecture, since the rebrand hides it: VCF Operations for Networks is still a &lt;strong&gt;separate, pre-hardened appliance&lt;/strong&gt;, deployed as a Day-2 operation from VCF Operations and lifecycle-managed by Fleet Management, not code merged into the core VCF Operations binary. Only one instance can be integrated per fleet. Licensing is automatic starting with VCF 9: the component is licensed through the vCenter instance it is connected to, and there is nothing to license manually anymore.&lt;/p&gt;
&lt;h2 id="anatomy-of-a-networks-search-query"&gt;Anatomy of a Networks Search Query&lt;/h2&gt;
&lt;p&gt;The documentation splits queries into four categories: structured queries, entity queries, planning queries, and path queries. In practice you will spend most of your time on structured queries, which read like a relaxed SQL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sum(bytes) of flows where Flow Type = &amp;#39;Routed&amp;#39; group by Source Subnet Network order by sum(bytes)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The pieces, in the order the parser expects them:&lt;/p&gt;
&lt;h3 id="entity-type-mandatory"&gt;Entity Type (Mandatory)&lt;/h3&gt;
&lt;p&gt;Every structured query is anchored on an entity type: &lt;code&gt;vms&lt;/code&gt;, &lt;code&gt;hosts&lt;/code&gt;, &lt;code&gt;flows&lt;/code&gt;, &lt;code&gt;firewall rules&lt;/code&gt;, &lt;code&gt;switch ports&lt;/code&gt;, &lt;code&gt;routes&lt;/code&gt;, &lt;code&gt;nsx managers&lt;/code&gt;, &lt;code&gt;kubernetes pods&lt;/code&gt;, and many more. Singular and plural both work, and synonyms are accepted (&lt;code&gt;virtual machine&lt;/code&gt; = &lt;code&gt;vm&lt;/code&gt;). Queries are not case-sensitive.&lt;/p&gt;
&lt;p&gt;Typing just the entity type is already a valid query: &lt;code&gt;vms&lt;/code&gt; lists every VM. The search bar validates as you type: a check mark means the query is valid, a cross means it is not. An old vRNI trick from the community lists that is still worth trying: type &lt;code&gt;help&lt;/code&gt; into the search field to bring up the search help.&lt;/p&gt;
&lt;h3 id="filters-where-plus-operators"&gt;Filters: &lt;code&gt;where&lt;/code&gt; Plus Operators&lt;/h3&gt;
&lt;p&gt;Conditions are &lt;code&gt;property, operator, value&lt;/code&gt;, combined with &lt;code&gt;and&lt;/code&gt; / &lt;code&gt;or&lt;/code&gt; and parentheses:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Operator&lt;/th&gt;
					&lt;th&gt;Example&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;=&lt;/code&gt; / &lt;code&gt;!=&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;flows where source ip address = '10.16.240.0/24'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;=&lt;/code&gt; &lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vms where memory &amp;gt;= 4096 mb&lt;/code&gt;, &lt;code&gt;vms where cpu usage rate &amp;lt; 70%&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;like&lt;/code&gt; / &lt;code&gt;not like&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vms where name like 'app'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;in&lt;/code&gt; / &lt;code&gt;not in&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;flows where port in (22, 23, 80, 443)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;is set&lt;/code&gt; / &lt;code&gt;is not set&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vms where firewall rule is set&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;matches&lt;/code&gt; / &lt;code&gt;not matches&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vm where name matches '[a-z]vm-delta[0-9]'&lt;/code&gt; (regex)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;grouping &lt;code&gt;()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;flows where (src tier = 'App' and destination tier = 'DB') OR (destination tier = 'App' and source tier = 'DB')&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The underrated one is the &lt;strong&gt;nested &lt;code&gt;in&lt;/code&gt;&lt;/strong&gt;: a sub-query as the right-hand side:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vm where host in (host where Blade like &amp;#39;sys/chassis-1&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vm where vlan in (vlan of vm where os in (&amp;#39;Microsoft Windows Server 2003&amp;#39;, &amp;#39;Microsoft Windows Server 2008&amp;#39;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The second example is a trimmed version of the documented &amp;ldquo;total attack surface&amp;rdquo; query (the full one lists five vulnerable operating systems and ends with &lt;code&gt;group by Vlan&lt;/code&gt;): every VM that shares a VLAN with a VM running a vulnerable OS.&lt;/p&gt;
&lt;h3 id="projections-what-to-show"&gt;Projections: What to Show&lt;/h3&gt;
&lt;p&gt;By default a query returns the entity&amp;rsquo;s standard field set. A projection in front changes that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Property list&lt;/strong&gt;: &lt;code&gt;os of vms&lt;/code&gt;, &lt;code&gt;cpu cores of vms&lt;/code&gt;, or several at once: &lt;code&gt;CPU Usage Rate, Network Rate, mac address, ip, host of vm 'Quality control-VM26'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Count&lt;/strong&gt;: &lt;code&gt;count of vms&lt;/code&gt;, &lt;code&gt;count of vm where operating system like 'Microsoft Windows Server 2008'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;List()&lt;/strong&gt;: fetch one entity while filtering on another: &lt;code&gt;List(host) of vms where memory &amp;lt;= 2gb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aggregates&lt;/strong&gt; (&lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;avg&lt;/code&gt;): &lt;code&gt;sum(memory) of hosts&lt;/code&gt;, &lt;code&gt;sum(bytes) of flows&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Series&lt;/strong&gt; for time-series graphs: &lt;code&gt;series(avg(cpu usage)) of vms where cpu cores = 4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="grouping-ordering-limiting"&gt;Grouping, Ordering, Limiting&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vms group by host
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sum(bytes) of flows group by dest vm order by sum(bytes)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vms order by memory limit 5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Three rules worth memorizing, because they are the usual cause of the red X:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;limit&lt;/code&gt; must be preceded by &lt;code&gt;order by&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order by&lt;/code&gt; accepts exactly one field; descending is the default (&lt;code&gt;asc&lt;/code&gt; flips it).&lt;/li&gt;
&lt;li&gt;When a &lt;code&gt;group by&lt;/code&gt; query has a projection or an &lt;code&gt;order by&lt;/code&gt;, the projection &lt;strong&gt;must contain an aggregation function&lt;/strong&gt;. &lt;code&gt;sum(bytes) of flows group by dest vm&lt;/code&gt; is valid; &lt;code&gt;bytes of flows group by dest vm&lt;/code&gt; is explicitly called out in the docs as invalid.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="time-top-n-and-in-last-n-days"&gt;Time: &lt;code&gt;top N&lt;/code&gt; and &lt;code&gt;in last N days&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The examples in the official advanced-queries page lean heavily on two inline constructs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;top 7 vm group by name, Vlan order by sum(Total Network Traffic) in last 7 days
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Kubernetes alerts where alert code = &amp;#39;ImagePullBackOff&amp;#39; in last 24 hours
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;New firewall rules in last 24 hours
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is also a UI time control next to the search bar with presets (&amp;ldquo;last 24 hours&amp;rdquo;, &amp;ldquo;last 3 days&amp;rdquo;), an &lt;strong&gt;At&lt;/strong&gt; option for a point in time, and a &lt;strong&gt;Between&lt;/strong&gt; option for a range, useful for re-running the same query against last Tuesday&amp;rsquo;s state, which remains one of this product&amp;rsquo;s superpowers.&lt;/p&gt;
&lt;h3 id="path-and-planning-queries"&gt;Path and Planning Queries&lt;/h3&gt;
&lt;p&gt;Path queries draw the hop-by-hop topology between two endpoints, including the underlay:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VMware VM &amp;#39;VM01&amp;#39; to VMware VM &amp;#39;VM02&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vm &amp;#39;app1-web&amp;#39; to Internet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Planning queries feed the micro-segmentation donut, the flow analysis view you use before writing distributed-firewall rules. The documented forms take a bare argument:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plan security in last 7 days
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plan securitygroup1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;plan host1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The community lists extend these with filters: &lt;code&gt;plan vm where folder = 'Production'&lt;/code&gt; and &lt;code&gt;plan flows where vm = 'app1-web' and traffic type = 'INTERNET_TRAFFIC'&lt;/code&gt; both come from &lt;a href="https://gist.github.com/mtellin/d48e7cfec03173f6c994e7132a6ebb02"&gt;mtellin&amp;rsquo;s gist&lt;/a&gt; rather than the official grammar reference, but they follow the same &lt;code&gt;where&lt;/code&gt; rules as everything else.&lt;/p&gt;
&lt;h3 id="entity-and-free-text-searches"&gt;Entity and Free-Text Searches&lt;/h3&gt;
&lt;p&gt;Plain strings work too: &lt;code&gt;'prod-68-1'&lt;/code&gt; (exact name, quoted), &lt;code&gt;prod&lt;/code&gt; (partial name), &lt;code&gt;vm app1&lt;/code&gt; (entity type plus partial name). And a community favorite from the gist: paste a bare MAC address like &lt;code&gt;00:50:56:a6:c9:6a&lt;/code&gt; into the search bar to find the machine that owns it, a great party trick when someone shows up with nothing but a switch log.&lt;/p&gt;
&lt;h3 id="vcenter-tags"&gt;vCenter Tags&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vm where tag = &amp;#39;Environment:Production&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The syntax is &lt;code&gt;'{category}:{tagname}'&lt;/code&gt;. Tags are also available as a Group-by criterion in flow analysis (up to three at once).&lt;/p&gt;
&lt;h3 id="saved-searches-and-the-widget-trick"&gt;Saved Searches and the Widget Trick&lt;/h3&gt;
&lt;p&gt;The bookmark icon next to the search bar saves any valid query; saved searches are per-user, and six defaults ship with the product (All Flows, Applications, Azure, Kubernetes Dashboard, Top Trends, NSX). Two features worth more attention than they get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Help &amp;gt; Useful Searches&lt;/strong&gt; is a curated, tagged library of pre-built queries, parameterized ones open pre-filled with sample values you swap out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View Search Query&lt;/strong&gt; on dashboard widgets (VM Details, Host Details, NSX Manager, Flow Insights, and a few others) reveals the query powering the widget, which you can copy into the search bar and modify. This is the fastest way I know to learn the DSL: find a widget that almost shows what you want, steal its query, adjust.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And almost any search can become an alert: run the query, then create a notification from the results page. Threshold queries (&lt;code&gt;flows where firewall action = deny&lt;/code&gt;, packet-drop queries) make surprisingly good custom alerts.&lt;/p&gt;
&lt;h2 id="the-query-cookbook"&gt;The Query Cookbook&lt;/h2&gt;
&lt;p&gt;The queries below are collected from the official 9.1 search-queries reference and the two classic community lists (&lt;a href="https://letstalkvirtual.com/vrealize-network-insight-search-queries/"&gt;Pat&amp;rsquo;s vRNI search queries post&lt;/a&gt; and &lt;a href="https://gist.github.com/mtellin/d48e7cfec03173f6c994e7132a6ebb02"&gt;mtellin&amp;rsquo;s gist&lt;/a&gt;) deduplicated and grouped by what I actually use them for. Since the grammar is unchanged from vRNI, the community-era queries remain valid in 9.1 unless they depend on a data source that is gone (more on that below).&lt;/p&gt;
&lt;h3 id="flows-and-traffic-patterns"&gt;Flows and Traffic Patterns&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;What it answers&lt;/th&gt;
					&lt;th&gt;Query&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Denied flows, environment-wide&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;flows where firewall action = deny&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Internet traffic by source VM&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sum(bytes) of flows where Flow Type = 'Internet' group by src vm&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Top talkers, limit 10&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sum(bytes) of flows group by src vm order by sum(bytes) limit 10&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Top ports by volume&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sum(bytes) of flow group by port order by sum(bytes)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Sum and average per port&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sum(bytes), avg(bytes) of flows group by port&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Top routed subnet pairs (last 7 days)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;top 7 flow where Flow Type = 'Routed' group by Source Subnet Network, Destination Subnet Network order by sum(Bytes) in last 7 days&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Traffic that never leaves its subnet, micro-segmentation candidates&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;top 7 flow where Flow Type = 'Switched' group by Subnet Network order by sum(Bytes) in last 7 days&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMs talking outside the country&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;top 7 flow where Destination Country != 'United States' group by Source VM, Destination Country order by sum(Bytes) in last 7 days&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Traffic between two application tiers, either direction&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Flows where (src tier = 'App' and destination Tier = 'DB') OR (destination tier = 'App' and source tier = 'DB')&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Data center interconnect traffic between two sites&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sum(bytes) of flows where (Dst Manager = 'site2' AND src manager = 'site1') OR (Dst Manager = 'site1' AND src manager = 'site2')&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="nsx-firewall-and-security"&gt;NSX Firewall and Security&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;What it answers&lt;/th&gt;
					&lt;th&gt;Query&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Effective rules between two VMs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;firewall rules from 'Prod-Midtier-1' to 'Prod-Db-1'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Any/any allow rules, segmentation debt&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;firewall rule where action = allow and service any = true&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Masked (shadowed) rules&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Firewall Rule Masked Alert&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Rules created recently&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;New firewall rules in last 24 hours&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Rules no flow has ever hit&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Firewall rule where flow is not set&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Flow count per rule&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Flow group by firewall rule&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Flows hitting specific rule IDs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Flow where rule id in (1011, 1012, 1013)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMs excluded from the DFW&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vm where firewall status = 'Excluded'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMs covered by a given rule&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vm where Firewall Rule = 'Prod MidTier to Prod DB - DBService'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Security groups referenced by no rule at all&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Security group where Indirect Incoming Rules is not set and Indirect Outgoing Rules is not set and Direct Incoming Rules is not set and Direct Outgoing Rules is not set&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Rule and group membership churn&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;firewall rule membership change&lt;/code&gt;, &lt;code&gt;security group membership change&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="vm-and-host-inventory"&gt;VM and Host Inventory&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;What it answers&lt;/th&gt;
					&lt;th&gt;Query&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;VM count per OS&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vms group by operating system&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Segments with the most VMs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vm group by l2 network&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Datastores with the most VMs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;vm group by datastore&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Hosts per vSphere version / build&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;host group by version&lt;/code&gt;, &lt;code&gt;host group by OS&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Network identity card for every VM&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;l2 network, vlan, ip address, default gateway of vms&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VMs still running vulnerable operating systems&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;count of vm where Operating System like 'Microsoft Windows Server 2003' or Operating System like 'Microsoft Windows Server 2008'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Everything about one VM in a single line&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CPU Usage Rate, Network Rate, Memory Usage Rate, mac address, ip, vxlan, host of vm 'Quality control-VM26'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="physical-network-and-routing"&gt;Physical Network and Routing&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;What it answers&lt;/th&gt;
					&lt;th&gt;Query&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;All switches from one vendor&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;switches where vendor = Cisco&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Switch ports dropping packets, worst first&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;switchport where vendor = 'Cisco' order by total packet drops&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Routes in a VRF&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;routes where vrf = 'Provider Edge 3'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Routes via a given next hop&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;routes where NextHop Router = 'California-Edge'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BGP sessions that are not up&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;BGP Connection where BGP Status != 'ACTIVE'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BGP neighbors of a router&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;list(BGP Neighbor) of NSX-T Router 'Router Name'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ECMP-enabled routers on a manager&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;NSX-T Router where ECMP = 'Enabled' and manager = 'NSX-T Manager Name'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="kubernetes-vks--antrea"&gt;Kubernetes (VKS / Antrea)&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;What it answers&lt;/th&gt;
					&lt;th&gt;Query&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Pod distribution per node&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;kubernetes Pods group by Kubernetes Node&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Nodes not in Ready state&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;kubernetes nodes where Ready != 'True'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Pods created in the last hour&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;new kubernetes pod in last 1 hour&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Dropped flows per service&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;flows where firewall action = 'DROP' group by Kubernetes Service&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Cross-namespace compliance check&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;flows from Kubernetes Namespace 'PCI' to Kubernetes Namespace 'Non-PCI'&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This category got more relevant in 9.1: container IPFIX flows from VKS clusters running Antrea now export to the VCF Operations for Networks collector, with pod-to-pod and pod-to-external traffic dashboards.&lt;/p&gt;
&lt;h3 id="dashboard-shortcuts"&gt;Dashboard Shortcuts&lt;/h3&gt;
&lt;p&gt;Not structured queries, but single keywords from the gist that jump straight to built-in views: &lt;code&gt;problem&lt;/code&gt;, &lt;code&gt;change&lt;/code&gt; (recent changes in the environment), &lt;code&gt;topn&lt;/code&gt;, &lt;code&gt;storage&lt;/code&gt;, and &lt;code&gt;pci compliance of VC Manager '192.168.10.10'&lt;/code&gt; (the PCI dashboard: which, per the gist, required an Enterprise license back in the vRNI days).&lt;/p&gt;
&lt;h3 id="a-caveat-on-community-shorthand"&gt;A Caveat on Community Shorthand&lt;/h3&gt;
&lt;p&gt;The community lists include a few compact forms you will not find in the official grammar reference: &lt;code&gt;vm by VLAN&lt;/code&gt;, &lt;code&gt;show VLAN&lt;/code&gt;, &lt;code&gt;vm by network rate&lt;/code&gt;, &lt;code&gt;top 10 vms by max packet drops&lt;/code&gt;, &lt;code&gt;flows where flow type = 'VM-Physical' by bytes&lt;/code&gt;. They come from vRNI-era posts that predate the current documented grammar, which only uses &lt;code&gt;group by&lt;/code&gt; / &lt;code&gt;order by&lt;/code&gt; for these jobs. I have kept them out of the tables above for that reason. If you rely on one of them, the in-product validation check mark will tell you immediately whether your build still accepts it.&lt;/p&gt;
&lt;h2 id="the-other-search-bar-enhanced-search-metric-queries"&gt;The Other Search Bar: Enhanced Search Metric Queries&lt;/h2&gt;
&lt;p&gt;The global search bar at the top of the VCF Operations console (the one that is on every page) is a different animal with its own documented query language, under the section Broadcom titles &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/infrastructure-operations/enhanced-search-capability.html"&gt;&amp;ldquo;Enhanced Search Capability&amp;rdquo;&lt;/a&gt;. It searches the vROps-side world: objects, metrics, properties, dashboards, reports, views, alert definitions, symptom definitions, recommendations, notifications, IP addresses, super metrics, and (since recent releases) features, type &lt;code&gt;li&lt;/code&gt; and select Feature to jump straight to Licenses, navigation path included.&lt;/p&gt;
&lt;p&gt;Its metric query grammar looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CPU|Usage % of Virtual Machine
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CPU|Usage % of Virtual Machine where CPU|Usage % &amp;gt; 15 and Memory|Usage % &amp;gt; 15
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CPU|Demand MHz of Virtual Machine where Configuration|Name contains &amp;#39;Centos&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CPU|Usage % of Virtual Machine where CPU|Usage % &amp;gt; 15 or Memory|Usage % &amp;gt; 15 childOf vSphere World
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The differences from the networks DSL are exactly where you would trip:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pattern is &lt;code&gt;Metric of Object Type&lt;/code&gt;, with the pipe character separating metric group and metric name (&lt;code&gt;CPU|Usage %&lt;/code&gt;). If you start with a metric name, naming the object type is mandatory.&lt;/li&gt;
&lt;li&gt;String operators are camelCase keywords: &lt;code&gt;equals&lt;/code&gt;, &lt;code&gt;notEquals&lt;/code&gt;, &lt;code&gt;contains&lt;/code&gt;, &lt;code&gt;notContains&lt;/code&gt;, &lt;code&gt;startsWith&lt;/code&gt;, &lt;code&gt;notStartsWith&lt;/code&gt;: there is no &lt;code&gt;like&lt;/code&gt;, no &lt;code&gt;in&lt;/code&gt;, no &lt;code&gt;matches&lt;/code&gt; here. Numeric operators (&lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;) plus arithmetic (&lt;code&gt;+ - * /&lt;/code&gt; with parentheses) and &lt;code&gt;and&lt;/code&gt;/&lt;code&gt;or&lt;/code&gt; round out the set. String values are case-insensitive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;childOf&lt;/code&gt; at the end of the query scopes results to descendants of an ancestor object; the closest thing this grammar has to the networks DSL&amp;rsquo;s nested &lt;code&gt;in&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hard limits: 300 characters per query, at most five different metric names. Break either and a red banner explains the issue; for syntax errors specifically it reads &amp;ldquo;The query contains syntax error(s). Please modify it to get suggestions.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;There is no &lt;code&gt;group by&lt;/code&gt; or &lt;code&gt;order by&lt;/code&gt; in the query itself; slicing happens on the Metric Search Results page instead, via Transformation (Min/Max/Average/Sum/First/Last/Current), Roll Up (hour through year), Parents, value-distribution buckets, and time settings. The Transformation filter only activates when the query has a &lt;code&gt;where&lt;/code&gt; condition and the object type has at most 200 objects over at most one month. From any result row, the vertical-ellipsis menu jumps into the Troubleshooting Workbench.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One honest note: none of this is new in 9.1. I compared the 9.0 and 9.1 pages (the content is identical) and the same grammar exists in Aria Operations 8.x. What is new in 9.1 on the metrics side is the PromQL-based Custom Query in Real-Time Metrics, which is a separate topic (and a separate language) altogether.&lt;/p&gt;
&lt;h2 id="what-actually-changed-in-91-for-operations-for-networks"&gt;What Actually Changed in 9.1 for Operations for Networks&lt;/h2&gt;
&lt;p&gt;Since search itself did not move, here is what did: the 9.1 items relevant to a networks operator, from the release notes and product support notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Network Assessment and Value report&lt;/strong&gt;: evaluates your current VDS-based networking and produces a CAPEX/OPEX analysis for VCF networking capabilities. It replaces the vCenter Assessment report, which was removed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPC Planning&lt;/strong&gt;: guided vSphere-to-VPC transition planning, with subnet tables and a CSV export of the generated VPC design.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expanded IPFIX for VKS clusters&lt;/strong&gt;: Antrea container flows land in the collector; pod-to-pod and pod-to-external dashboards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expanded migration planning&lt;/strong&gt;: automatic migration wave generation, clustering workloads by flow, latency, and bandwidth data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network health dashboards&lt;/strong&gt;: NSX Edge appliance and ESX host networking capacity monitoring surfaced through VCF Operations Health and Diagnostics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deprecations&lt;/strong&gt;: AWS and Azure data sources are deprecated in 9.1, and the networks API had 22 operations marked deprecated, the largest deprecation set in the Operations component. The VMware SD-WAN (VeloCloud) search-queries reference page is also absent from the 9.1 documentation tree.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That deprecation list is worth acting on if you have search-based alerting or scripts built on AWS/Azure entity queries (&lt;code&gt;AWS EC2 where Security Group = ...&lt;/code&gt;, &lt;code&gt;Azure NSG Rule where Action = 'ALLOW'&lt;/code&gt;), the syntax still exists in the 9.1 reference today, but the data sources feeding those entities are on the way out.&lt;/p&gt;
&lt;h2 id="getting-there-from-standalone-6x"&gt;Getting There from Standalone 6.x&lt;/h2&gt;
&lt;p&gt;If you are still on a standalone appliance (I have covered &lt;a href="https://cosmin.us/upgrading-aria-operations-for-networks-to-6-14-via-upgrade-bundle/"&gt;upgrading Aria Operations for Networks to 6.14 via the upgrade bundle&lt;/a&gt; and &lt;a href="https://cosmin.us/upgrading-aria-operations-for-networks-to-6-14-via-aria-suite-lifecycle/"&gt;via Aria Suite Lifecycle&lt;/a&gt; before) the path into 9.x is: get to &lt;strong&gt;6.14.0 Patch 6 or 6.14.1+&lt;/strong&gt;, import the instance into VCF Operations Fleet Management, upgrade it in place to VCF Operations for Networks 9.0.x, and from there directly to 9.1. Only one instance can be imported per fleet. Every search query in this post works the same on both sides of that migration, which is precisely the point.&lt;/p&gt;
&lt;h2 id="the-api-corner"&gt;The API Corner&lt;/h2&gt;
&lt;p&gt;For automation, the search subsystem is exposed over REST, still under the Network Insight namespace:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/ni/search/ql&lt;/code&gt;: takes the same query-language strings you type in the search bar&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/ni/search&lt;/code&gt;: entity search&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/ni/search/aggregation&lt;/code&gt;: aggregations&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/ni/search/groupby&lt;/code&gt;: group-by queries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The schemas are on the &lt;a href="https://developer.broadcom.com/xapis/vcf-operations-for-networks-api/latest/"&gt;VCF Operations for Networks API reference&lt;/a&gt;. The &lt;code&gt;ql&lt;/code&gt; endpoint is the interesting one: anything you prototype in the search bar can be lifted verbatim into a script.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/infrastructure-operations/network-operationss/search/search-queries.html"&gt;Broadcom TechDocs - Working with Search Queries (VCF Operations for Networks 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/infrastructure-operations/enhanced-search-capability.html"&gt;Broadcom TechDocs - Enhanced Search Capability (VCF Operations 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/infrastructure-operations/enhanced-search-capability/searching-for-metrics-properties-or-object-types-using-queries.html"&gt;Broadcom TechDocs - Searching for Metrics, Properties, or Object Types Using Queries (VCF Operations 9.1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/aria/aria-operations-for-networks/6-13/vrealize-network-insight-ug-4-1-and-later-6-13/search/search-queries.html"&gt;Broadcom TechDocs - Search Queries (Aria Operations for Networks 6.13, the legacy twin of the 9.1 pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/what-s-new/whats-new-vcf-ops.html"&gt;Broadcom TechDocs - What&amp;rsquo;s New in VCF Operations (VCF 9.1 Release Notes)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/vmware-cloud-foundation-9-1-0-0-release-notes/vcf-91-product-support-notes.html"&gt;Broadcom TechDocs - VCF 9.1 Product Support Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://letstalkvirtual.com/vrealize-network-insight-search-queries/"&gt;letstalkvirtual.com - vRealize Network Insight Search Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/mtellin/d48e7cfec03173f6c994e7132a6ebb02"&gt;GitHub gist (mtellin) - vRealize Network Insight Search Queries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>VCF 9.1 NSX Rotation Error: PASSWORD_MANAGER_NSX_USER_API_FAILED</title><link>https://cosmin.us/fixing-nsx-service-account-rotation-loop-password-manager-nsx-user-api-failed-vcf-9-1/</link><pubDate>Wed, 15 Jul 2026 17:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/fixing-nsx-service-account-rotation-loop-password-manager-nsx-user-api-failed-vcf-9-1/</guid><description>&lt;p&gt;Continuing the credential cleanup in the &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;same 9.1 environment&lt;/a&gt; from the &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;expired password sync&lt;/a&gt; and &lt;a href="https://cosmin.us/fixing-vcfopspwid03-call-from-nsx-received-invalid-response/"&gt;VCFOPSPWID03&lt;/a&gt; posts, one credential refused to settle: the service account SDDC Manager uses to talk to the NSX Manager API, &lt;code&gt;svc-sddcmanager-a-nsx-mgmt--8199&lt;/code&gt; in my lab. It showed up as &lt;strong&gt;disconnected&lt;/strong&gt;, every remediation attempt failed, and the environment kept trying to rotate it in a loop.&lt;/p&gt;
&lt;p&gt;This one took several wrong turns before the actual root cause surfaced, and almost every wrong turn taught me something worth writing down. The short version:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Continuing the credential cleanup in the &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;same 9.1 environment&lt;/a&gt; from the &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;expired password sync&lt;/a&gt; and &lt;a href="https://cosmin.us/fixing-vcfopspwid03-call-from-nsx-received-invalid-response/"&gt;VCFOPSPWID03&lt;/a&gt; posts, one credential refused to settle: the service account SDDC Manager uses to talk to the NSX Manager API, &lt;code&gt;svc-sddcmanager-a-nsx-mgmt--8199&lt;/code&gt; in my lab. It showed up as &lt;strong&gt;disconnected&lt;/strong&gt;, every remediation attempt failed, and the environment kept trying to rotate it in a loop.&lt;/p&gt;
&lt;p&gt;This one took several wrong turns before the actual root cause surfaced, and almost every wrong turn taught me something worth writing down. The short version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SDDC Manager generated a &lt;strong&gt;128-character&lt;/strong&gt; password for the service account, but its own remediate path enforces a &lt;strong&gt;127-character&lt;/strong&gt; maximum, an off-by-one between the generator and the validator that keeps the rotation failing.&lt;/li&gt;
&lt;li&gt;The service account is an &lt;strong&gt;OS-level PAM user&lt;/strong&gt; on the NSX appliance: invisible to the NSX API, UI, and CLI, manageable only as &lt;code&gt;root&lt;/code&gt; with standard Linux tools.&lt;/li&gt;
&lt;li&gt;Failed rotation attempts had &lt;strong&gt;locked the account&lt;/strong&gt; at the NSX API level.&lt;/li&gt;
&lt;li&gt;And the final boss: SDDC Manager&amp;rsquo;s rotation machinery was &lt;strong&gt;re-changing the password within a couple of seconds&lt;/strong&gt; of any manual reset, so every fix I tested was already stale by the time I tested it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-symptom-a-service-account-stuck-disconnected"&gt;The Symptom: A Service Account Stuck Disconnected&lt;/h2&gt;
&lt;p&gt;The credential in question, as SDDC Manager tracks it:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Field&lt;/th&gt;
					&lt;th&gt;Value&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Username&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;svc-sddcmanager-a-nsx-mgmt--8199&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Resource type&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;NSXT_MANAGER&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Credential type&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;API&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Account type&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;SERVICE&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The rotation failures are visible on the SDDC Manager appliance in the operations manager log:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -f /var/log/vmware/vcf/operationsmanager/operationsmanager.log &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; grep -Ei &lt;span class="s1"&gt;&amp;#39;svc-sddcmanager|ROTATE|REMEDIATE|diagnosticMessage&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The recurring entry that matters (flattened here):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;errorCode: PASSWORD_MANAGER_NSX_USER_API_FAILED
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diagnosticMessage: Response from NSX &amp;lt;nsx-manager-fqdn&amp;gt;: 403 -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The credentials were incorrect or the account specified has been locked.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A 403 for a service account that only SDDC Manager itself manages. Nobody had touched this password by hand: SDDC Manager rotated it, and then could no longer authenticate with the value it had just set.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The examples in this post use &lt;code&gt;curl -k&lt;/code&gt;, which skips TLS certificate verification, fine in a lab where the appliances still run self-signed certificates. In production, drop &lt;code&gt;-k&lt;/code&gt; and trust the appliance CA instead. If any password you type contains &lt;code&gt;!&lt;/code&gt;, disable history expansion first (&lt;code&gt;set +H&lt;/code&gt; in bash, &lt;code&gt;unsetopt BANG_HIST&lt;/code&gt; in zsh) so the shell does not mangle it. And the &lt;code&gt;read -rp&lt;/code&gt; / &lt;code&gt;read -rsp&lt;/code&gt; prompts use bash syntax: on the appliances that is the shell you get, but if you run any of this locally from zsh, start &lt;code&gt;bash&lt;/code&gt; first or use the zsh form (&lt;code&gt;read -rs 'VAR?prompt: '&lt;/code&gt;); in zsh, &lt;code&gt;read -rsp&lt;/code&gt; silently leaves the variable empty, and an empty password produces confusing downstream errors instead of a clear failure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="the-off-by-one-128-generated-vs-127-accepted"&gt;The Off-by-One: 128 Generated vs 127 Accepted&lt;/h2&gt;
&lt;p&gt;Digging through the failed rotation tasks showed the first real clue: the password SDDC Manager had generated for the service account was &lt;strong&gt;128 characters&lt;/strong&gt; long, while the remediate path rejects anything over &lt;strong&gt;127 characters&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The generator takes its cue from the NSX node authentication policy. NSX advertises a &lt;code&gt;maximum_password_length&lt;/code&gt; of 128 by default, SDDC Manager generates a password at that maximum, and then its own validation refuses to remediate with it. The account ends up in the worst possible state: the rotation half-succeeds often enough to keep changing the password, but remediation can never complete, so the credential is marked disconnected and the platform keeps retrying.&lt;/p&gt;
&lt;h2 id="dead-ends-worth-knowing-about"&gt;Dead Ends Worth Knowing About&lt;/h2&gt;
&lt;p&gt;Before the fix, the detours, each one reasonable, each one wrong.&lt;/p&gt;
&lt;h3 id="remediating-from-the-ui"&gt;Remediating from the UI&lt;/h3&gt;
&lt;p&gt;The obvious first move. The remediation workflow failed with the same 403, and the UI adds nothing to the diagnosis, the useful error text only exists in &lt;code&gt;operationsmanager.log&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="guessing-the-credential-tuple"&gt;Guessing the Credential Tuple&lt;/h3&gt;
&lt;p&gt;My first API attempts failed validation before doing anything, because a &lt;code&gt;PATCH /v1/credentials&lt;/code&gt; call must reference the &lt;strong&gt;exact tuple&lt;/strong&gt; SDDC Manager has on file: &lt;code&gt;resourceName&lt;/code&gt;, &lt;code&gt;resourceType&lt;/code&gt;, &lt;code&gt;credentialType&lt;/code&gt;, and &lt;code&gt;username&lt;/code&gt; all have to match. Do not guess any of them. Read them back first.&lt;/p&gt;
&lt;p&gt;Get a token (I ran these directly on the SDDC Manager appliance against &lt;code&gt;localhost&lt;/code&gt;, but the FQDN works the same):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SDDC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://localhost&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rp &lt;span class="s2"&gt;&amp;#34;SSO username: &amp;#34;&lt;/span&gt; SSO_USER
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;SSO password: &amp;#34;&lt;/span&gt; SSO_PASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;jq -nc --arg u &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SSO_USER&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --arg p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SSO_PASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;{username:$u,password:$p}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -sk -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/tokens&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r .accessToken&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; SSO_PASS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;null&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Token acquisition failed&amp;#34;&lt;/span&gt; &amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The block prints nothing on success, the token lands silently in &lt;code&gt;$TOKEN&lt;/code&gt;. Test it with a cheap authenticated call before building anything on top of it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -o /dev/null -w &lt;span class="s2"&gt;&amp;#34;%{http_code}\n&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/domains&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A &lt;code&gt;200&lt;/code&gt; means the token works. Anything else, start over at the token block.&lt;/p&gt;
&lt;p&gt;List the NSX credentials and pull the exact tuple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/credentials?resourceType=NSXT_MANAGER&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.elements[] | select(.accountType==&amp;#34;SERVICE&amp;#34;) |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; [.resource.resourceName, .resource.resourceType, .credentialType, .username] | @tsv&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That returns the values used in the remediation calls later in this post.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;jq&lt;/code&gt; fails here with &lt;em&gt;&amp;ldquo;Cannot iterate over null&amp;rdquo;&lt;/em&gt;, the response was not a credentials list; it is almost always an authentication error object instead. Check the HTTP status and the raw body:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -o /tmp/creds.json -w &lt;span class="s2"&gt;&amp;#34;%{http_code}\n&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/credentials?resourceType=NSXT_MANAGER&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq . /tmp/creds.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A &lt;code&gt;401&lt;/code&gt; means the token is empty, expired (they are short-lived), or the literal string &lt;code&gt;null&lt;/code&gt; from a failed acquisition, re-run the token block above and mind its failure check. A &lt;code&gt;401&lt;/code&gt; body complaining that &lt;em&gt;&amp;ldquo;jwt strings must contain exactly 2 period characters&amp;rdquo;&lt;/em&gt; is the same problem stated more directly: whatever is in &lt;code&gt;$TOKEN&lt;/code&gt; is not a JWT at all, and the usual cause is a rejected &lt;code&gt;/v1/tokens&lt;/code&gt; login quietly turning into &lt;code&gt;null&lt;/code&gt;. Check that the username is a full SSO identity such as &lt;code&gt;administrator@vsphere.local&lt;/code&gt;, not a bare username.&lt;/p&gt;
&lt;p&gt;Capture the service account username while you are here, the remediation and rotation calls later run in this same SDDC Manager session and reuse it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SVC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -sk -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/credentials?resourceType=NSXT_MANAGER&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.elements[] | select(.accountType==&amp;#34;SERVICE&amp;#34;) | .username&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you spend time in this API, the &lt;a href="https://cosmin.us/mastering-the-v1-credentials-api-in-sddc-manager-for-enhanced-security-management/"&gt;/v1/credentials overview&lt;/a&gt; covers the basic operations.&lt;/p&gt;
&lt;h3 id="changing-the-vcf-operations-password-policies"&gt;Changing the VCF Operations Password Policies&lt;/h3&gt;
&lt;p&gt;VCF Operations 9.1 exposes password policy settings, and lowering a maximum length there looked like the clean fix for the 128-character problem. It did nothing. Those policies do &lt;strong&gt;not&lt;/strong&gt; govern what SDDC Manager generates for service accounts, the generator follows the NSX node authentication policy, not VCF Operations. Worth knowing before you spend an afternoon proving it.&lt;/p&gt;
&lt;h2 id="the-first-fix-lower-the-nsx-maximum-password-length"&gt;The First Fix: Lower the NSX Maximum Password Length&lt;/h2&gt;
&lt;p&gt;Since the generator follows the NSX policy maximum and the validator caps at 127, the workaround is to lower the NSX &lt;code&gt;maximum_password_length&lt;/code&gt; so generated passwords land under the limit. I went to 100, comfortably below 127, still far longer than any human-managed password.&lt;/p&gt;
&lt;p&gt;One trap first: the setting lives in the &lt;strong&gt;auth-policy&lt;/strong&gt; endpoint. There is no &lt;code&gt;/api/v1/node/aaa/password-complexity&lt;/code&gt; endpoint, that name belongs to the NSX CLI command (&lt;code&gt;get&lt;/code&gt;/&lt;code&gt;set password-complexity&lt;/code&gt;), and the API returns 404 for it. The REST path you want is &lt;code&gt;/api/v1/node/aaa/auth-policy&lt;/code&gt;, the same endpoint from the &lt;a href="https://cosmin.us/fixing-vcfopspwid03-call-from-nsx-received-invalid-response/"&gt;password reuse post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Back up the current policy before changing anything:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;NSX admin password: &amp;#34;&lt;/span&gt; NSXPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tee /tmp/auth-policy-backup.json &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;api_failed_auth_lockout_period&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;api_max_auth_failures&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;minimum_password_length&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;maximum_password_length&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lower the maximum (&lt;code&gt;maximum_password_length&lt;/code&gt; accepts 8 to 128):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;maximum_password_length&amp;#34;: 100}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Policy changes take a short while to apply and synchronize across the manager cluster nodes in 9.x. Read the value back before moving on:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="p"&gt;|&lt;/span&gt; jq .maximum_password_length
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;New rotations now generate passwords of at most 100 characters, comfortably under the 127-character validation. Problem solved, except the account was still disconnected, and remediation still failed with the same 403.&lt;/p&gt;
&lt;h2 id="plot-twist-test_before_remediate"&gt;Plot Twist: TEST_BEFORE_REMEDIATE&lt;/h2&gt;
&lt;p&gt;The remediation task logs showed the failure happening in a &lt;code&gt;TEST_BEFORE_REMEDIATE&lt;/code&gt; stage. Before SDDC Manager remediates a credential, it first &lt;strong&gt;authenticates against NSX as the service account&lt;/strong&gt; with the password it believes is current. If that test fails (wrong password &lt;em&gt;or&lt;/em&gt; locked account) the whole remediation aborts with &lt;code&gt;PASSWORD_MANAGER_NSX_USER_API_FAILED&lt;/code&gt;, and nothing is remediated.&lt;/p&gt;
&lt;p&gt;That explains the loop: the earlier failed rotations had burned through NSX&amp;rsquo;s API authentication failure allowance (&lt;code&gt;api_max_auth_failures: 5&lt;/code&gt; in the policy above), the account got locked, and from then on even a correct password could not pass the pre-remediation test.&lt;/p&gt;
&lt;p&gt;So before anything else could work, I had to look at the account itself on the NSX side, which is where this got interesting.&lt;/p&gt;
&lt;h2 id="the-hidden-user-an-api-only-pam-account"&gt;The Hidden User: An API-Only PAM Account&lt;/h2&gt;
&lt;p&gt;The service account does not exist as far as the NSX management plane is concerned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /api/v1/node/users&lt;/code&gt;: not listed.&lt;/li&gt;
&lt;li&gt;NSX UI under user management, not there.&lt;/li&gt;
&lt;li&gt;NSX CLI &lt;code&gt;get user&lt;/code&gt; / &lt;code&gt;set user&lt;/code&gt;: unknown user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But on the NSX Manager appliance as &lt;code&gt;root&lt;/code&gt;, it is a perfectly ordinary Linux account:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep svc- /etc/passwd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;svc-sddcmanager-a-nsx-mgmt--8199:x:...:...:/home/svc-sddcmanager-a-nsx-mgmt--8199:...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The account authenticates to the NSX API through PAM, has password history in &lt;code&gt;/etc/security/opasswd&lt;/code&gt;, and is managed by exactly nothing except &lt;code&gt;root&lt;/code&gt; and the standard Linux toolbox. No SSH access, no UI, API-only. That means the diagnostics you would normally run through the NSX API happen with &lt;code&gt;faillock&lt;/code&gt; and &lt;code&gt;chage&lt;/code&gt; instead:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SVC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;svc-sddcmanager-a-nsx-mgmt--8199&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;faillock --user &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chage -l &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;faillock&lt;/code&gt; confirmed the lockout, a stack of recent authentication failures, courtesy of the rotation loop. Clear it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;faillock --user &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --reset
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While in there, two more root-level tools are worth knowing for this account type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;passwd &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;# set a known password, as root&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt; &amp;gt; /etc/security/opasswd &lt;span class="c1"&gt;# wipe PAM password history. See warning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;/etc/security/opasswd&lt;/code&gt; holds the PAM password history for &lt;strong&gt;every&lt;/strong&gt; user on the appliance, not just the service account. Emptying it is a blunt lab move to get past &amp;ldquo;password has been already used&amp;rdquo; rejections during repeated testing. Do not do this on a production appliance without a support ticket telling you to.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="keeping-the-account-from-locking-again"&gt;Keeping the Account from Locking Again&lt;/h3&gt;
&lt;p&gt;The lockout pattern here matches &lt;a href="https://knowledge.broadcom.com/external/article?articleNumber=420736"&gt;Broadcom KB 420736&lt;/a&gt;: SDDC Manager trips the NSX API lockout with its own failed authentication attempts, and remediation can never win against a locked account. The durable fix is to add SDDC Manager&amp;rsquo;s IP to the NSX &lt;code&gt;lockout_immune_addresses&lt;/code&gt; list, so its authentication failures never lock anything.&lt;/p&gt;
&lt;p&gt;Run this &lt;strong&gt;on the SDDC Manager appliance&lt;/strong&gt;, so &lt;code&gt;hostname -i&lt;/code&gt; resolves to the right IP; the jq filter appends it to the existing list without clobbering other entries:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;PUT /api/v1/cluster/api-service&lt;/code&gt; replaces the entire cluster-wide API service configuration document, and NSX restarts the API service to apply it, expect a brief API interruption, so run this when nothing else is mid-call. The pipeline below reads the full current document and keeps a copy in &lt;code&gt;/tmp/api-service-backup.json&lt;/code&gt; before anything is overwritten.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/cluster/api-service &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tee /tmp/api-service-backup.json &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; jq --arg ip &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname -i&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;.lockout_immune_addresses += [$ip] | .lockout_immune_addresses |= unique&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -sk -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/cluster/api-service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the lockout cleared and immunity in place, I reset the service account password as &lt;code&gt;root&lt;/code&gt;, confirmed it worked with a quick authentication test&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;Service account password you just set: &amp;#34;&lt;/span&gt; SVCPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -o /dev/null -w &lt;span class="s2"&gt;&amp;#34;%{http_code}\n&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -u &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$SVCPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/cluster/status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; SVCPASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;and got &lt;code&gt;403&lt;/code&gt;. Seconds after setting it. With a password I had just set moments earlier.&lt;/p&gt;
&lt;h2 id="the-real-root-cause-racing-the-rotation-engine"&gt;The Real Root Cause: Racing the Rotation Engine&lt;/h2&gt;
&lt;p&gt;This was the point where the investigation stopped being about policies and started being about timing. The sequence kept repeating:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;As &lt;code&gt;root&lt;/code&gt; on NSX: &lt;code&gt;passwd&lt;/code&gt; the service account to a known value.&lt;/li&gt;
&lt;li&gt;Test authentication with that value: &lt;code&gt;200&lt;/code&gt;: for a moment.&lt;/li&gt;
&lt;li&gt;Test again a few seconds later: &lt;code&gt;403&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nothing was &amp;ldquo;wrong&amp;rdquo; with any password. &lt;strong&gt;SDDC Manager&amp;rsquo;s rotation machinery was re-changing the service account password within a couple of seconds of any reset.&lt;/strong&gt; The disconnected credential kept the retry loop hot, every retry rotated the password on the appliance, and every manual test raced the engine and lost. The vault was not stale, the policy was not blocking anything anymore, my known-good password simply stopped being the current password almost immediately after I set it.&lt;/p&gt;
&lt;p&gt;Watching the log in one terminal makes the race visible:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -f /var/log/vmware/vcf/operationsmanager/operationsmanager.log &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; grep -Ei &lt;span class="s1"&gt;&amp;#39;svc-sddcmanager|ROTATE|REMEDIATE&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The fix is to stop fighting the engine and synchronize with it instead: set the password and hand it to SDDC Manager &lt;strong&gt;inside that couple-second window&lt;/strong&gt;, so the value on the appliance and the value being remediated converge before the next rotation fires.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ What follows is a lab maneuver. Manually resetting a platform-managed service account and racing the rotation engine is recoverable here; on a production NSX Manager, capture &lt;code&gt;operationsmanager.log&lt;/code&gt;, the failed task IDs, and the &lt;code&gt;faillock&lt;/code&gt; output and open a support request first. See the last bullet in Hardening Takeaways.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, that means staging everything in advance:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Terminal 1: NSX Manager as root&lt;/strong&gt;, with a non-interactive password set ready to run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;New service account password: &amp;#34;&lt;/span&gt; SVCPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$SVCPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; chpasswd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; SVCPASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Terminal 2 (the same SDDC Manager session from earlier&lt;/strong&gt;, so &lt;code&gt;$SDDC&lt;/code&gt;, &lt;code&gt;$TOKEN&lt;/code&gt;, and &lt;code&gt;$SVC&lt;/code&gt; are still set, with the remediation payload pre-built) the only thing left is to press Enter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;Same password as set on NSX: &amp;#34;&lt;/span&gt; SVCPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TASK_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;jq -nc &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg fqdn &lt;span class="s2"&gt;&amp;#34;&amp;lt;nsx-manager-fqdn&amp;gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg user &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg pw &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVCPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;{operationType:&amp;#34;REMEDIATE&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; elements:[{resourceName:$fqdn, resourceType:&amp;#34;NSXT_MANAGER&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; credentials:[{credentialType:&amp;#34;API&amp;#34;, username:$user, password:$pw}]}]}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -sk -X PATCH &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/credentials&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r .id&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; SVCPASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run terminal 1, then terminal 2 immediately, within the window, before the engine rotates again. Poll the task:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/credentials/tasks/&lt;/span&gt;&lt;span class="nv"&gt;$TASK_ID&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;&amp;#39;{name, status}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This time &lt;code&gt;TEST_BEFORE_REMEDIATE&lt;/code&gt; authenticated successfully (the password it tested was, at that moment, actually the password on the appliance) and the remediation completed. The credential flipped back to healthy, and the rotation loop stopped, because there was nothing left to retry.&lt;/p&gt;
&lt;p&gt;To finish cleanly, trigger one supervised rotation so the account ends up on a fresh SDDC Manager-generated password (now capped at 100 characters by the lowered policy) instead of a hand-typed one:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq -nc &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg fqdn &lt;span class="s2"&gt;&amp;#34;&amp;lt;nsx-manager-fqdn&amp;gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg user &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SVC&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;{operationType:&amp;#34;ROTATE&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; elements:[{resourceName:$fqdn, resourceType:&amp;#34;NSXT_MANAGER&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; credentials:[{credentialType:&amp;#34;API&amp;#34;, username:$user}]}]}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -X PATCH &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$SDDC&lt;/span&gt;&lt;span class="s2"&gt;/v1/credentials&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Poll the task the same way as before; with the loop broken and the policy cap in place, the rotation completes cleanly.&lt;/p&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The rotation task in SDDC Manager completes successfully, and no new &lt;code&gt;ROTATE&lt;/code&gt;/&lt;code&gt;REMEDIATE&lt;/code&gt; retries appear in &lt;code&gt;operationsmanager.log&lt;/code&gt; for the service account.&lt;/li&gt;
&lt;li&gt;The credential status is back to healthy (&lt;code&gt;GET /v1/credentials&lt;/code&gt; shows no error state for the tuple).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;faillock --user &amp;quot;$SVC&amp;quot;&lt;/code&gt; on the NSX appliance stays empty.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lockout_immune_addresses&lt;/code&gt; in &lt;code&gt;GET /api/v1/cluster/api-service&lt;/code&gt; contains the SDDC Manager IP.&lt;/li&gt;
&lt;li&gt;The NSX auth-policy holds the values you intend to keep, in my case &lt;code&gt;maximum_password_length: 100&lt;/code&gt; stays, since the 128/127 mismatch would otherwise come straight back on the next rotation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Clean up the working files, since the backups describe your security posture and the lockout-immune IP list:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -f /tmp/auth-policy-backup.json /tmp/api-service-backup.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; NSXPASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="hardening-takeaways"&gt;Hardening Takeaways&lt;/h2&gt;
&lt;p&gt;A few things I am keeping from this one, beyond the fix itself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add SDDC Manager to &lt;code&gt;lockout_immune_addresses&lt;/code&gt; proactively.&lt;/strong&gt; Any credential workflow that can fail more times than &lt;code&gt;api_max_auth_failures&lt;/code&gt; allows can lock its own account and wedge remediation. &lt;a href="https://knowledge.broadcom.com/external/article?articleNumber=420736"&gt;KB 420736&lt;/a&gt; describes the pattern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Back up &lt;code&gt;auth-policy&lt;/code&gt; before any PUT&lt;/strong&gt;: &lt;code&gt;tee&lt;/code&gt; to a file costs nothing, and the endpoint carries every knob (lockout periods, complexity, history) in one document, so an overzealous edit has a wide blast radius.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check NTP while you are in the logs.&lt;/strong&gt; This environment&amp;rsquo;s &lt;code&gt;operationsmanager.log&lt;/code&gt; also showed intermittent JWT clock-skew errors between components, harmless-looking noise that can turn into real authentication failures. Time sync issues and credential troubleshooting mix badly; rule them out early.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Know when to stop and open an SR.&lt;/strong&gt; Manually resetting a service account password as &lt;code&gt;root&lt;/code&gt; and racing the rotation engine is recoverable in a lab. In production, the moment a platform-managed service account is in a rotation loop, capture &lt;code&gt;operationsmanager.log&lt;/code&gt;, the failed task IDs, and the &lt;code&gt;faillock&lt;/code&gt; output, and open a support request: &lt;a href="https://knowledge.broadcom.com/external/article?articleNumber=420736"&gt;KB 420736&lt;/a&gt; describes the lockout pattern, and &lt;a href="https://knowledge.broadcom.com/external/article?articleNumber=423038"&gt;KB 423038&lt;/a&gt; is a related reference worth attaching alongside it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="final-notes"&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;Every layer of this problem produced the same useless symptom (a 403) for four different reasons: a password too long to remediate, a locked account, a pre-remediation test that authenticates as the account it is about to fix, and finally a rotation engine overwriting the password faster than I could test it. The 128-versus-127 mismatch set the loop in motion, but the thing that made it unfixable-looking was the timing: every diagnostic I ran was measuring a password that had already been replaced.&lt;/p&gt;
&lt;p&gt;Two habits would have shortened this significantly. First, &lt;code&gt;tail -f&lt;/code&gt; the operations manager log &lt;em&gt;before&lt;/em&gt; forming a theory: the rotation attempts were right there, timestamped, showing the engine acting seconds after every manual change. Second, when a platform manages an account, assume it will keep managing it while you troubleshoot: either pause the machinery or synchronize with it. Fighting an automated rotation engine with manual password resets is a race you lose every time, until you make the race the plan.&lt;/p&gt;</content:encoded></item><item><title>Fixing VCFOPSPWID03: NSX Password Update Failed as Call from NSX Received Invalid Response (VCF 9.1)</title><link>https://cosmin.us/fixing-vcfopspwid03-call-from-nsx-received-invalid-response/</link><pubDate>Sat, 11 Jul 2026 17:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/fixing-vcfopspwid03-call-from-nsx-received-invalid-response/</guid><description>&lt;p&gt;While rotating credentials in the &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;same 9.1 environment&lt;/a&gt; I covered in the &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;expired password sync post&lt;/a&gt;, an &lt;strong&gt;Update&lt;/strong&gt; of the NSX Manager &lt;code&gt;admin&lt;/code&gt; password (credential type &lt;strong&gt;API&lt;/strong&gt;) from VCF Operations kept failing after about a minute with error code &lt;strong&gt;VCFOPSPWID03&lt;/strong&gt; and a spectacularly unhelpful message: &lt;em&gt;&amp;ldquo;call from NSX received invalid response.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The actual cause turned out to be simple, NSX rejected the new password because it had &lt;strong&gt;already been used&lt;/strong&gt; on that manager. This being a lab, I was deliberately recycling a previous password. That goes against best practices, and NSX enforces it. But the way the error surfaces (and the way the reuse policy behaves in this build) is worth writing down.&lt;/p&gt;</description><content:encoded>&lt;p&gt;While rotating credentials in the &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;same 9.1 environment&lt;/a&gt; I covered in the &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;expired password sync post&lt;/a&gt;, an &lt;strong&gt;Update&lt;/strong&gt; of the NSX Manager &lt;code&gt;admin&lt;/code&gt; password (credential type &lt;strong&gt;API&lt;/strong&gt;) from VCF Operations kept failing after about a minute with error code &lt;strong&gt;VCFOPSPWID03&lt;/strong&gt; and a spectacularly unhelpful message: &lt;em&gt;&amp;ldquo;call from NSX received invalid response.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The actual cause turned out to be simple, NSX rejected the new password because it had &lt;strong&gt;already been used&lt;/strong&gt; on that manager. This being a lab, I was deliberately recycling a previous password. That goes against best practices, and NSX enforces it. But the way the error surfaces (and the way the reuse policy behaves in this build) is worth writing down.&lt;/p&gt;
&lt;h2 id="the-error-call-from-nsx-received-invalid-response"&gt;The Error: &amp;ldquo;Call from NSX Received Invalid Response&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;The password update banner in VCF Operations:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/nsx-vcfopspwid03-password-reuse/024-capture-024.webp" alt="VCF Operations banner showing the NSX appliance password update failed because the call from NSX received an invalid response." width="1115" height="61" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The failed request under &lt;strong&gt;Management Tasks&lt;/strong&gt;, with the task failing in Stage 1 after roughly a minute:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/nsx-vcfopspwid03-password-reuse/025-capture-025.webp" alt="Update Password task in VCF Operations showing Request Failed with error code VCFOPSPWID03 after one minute in Stage 1." width="1402" height="528" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The full error text:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error Code: VCFOPSPWID03
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Password task UPDATE for &amp;lt;nsx-manager-fqdn&amp;gt; has failed. Error message:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NSX password update failed at &amp;lt;nsx-manager-fqdn&amp;gt;: Failed to update password
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;for NSX user admin for &amp;lt;nsx-manager-fqdn&amp;gt;, as call from NSX received
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;invalid response.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same failure is visible on the VCF Operations node in the &lt;code&gt;component-manager-plugin-*.log&lt;/code&gt; (in a support bundle it is under &lt;code&gt;logs/&lt;/code&gt;; on the appliance under &lt;code&gt;/storage/log/vcops/log/&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...UpdatePasswordTask.execute] - Executing Update password task...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...PasswordTaskUtil.monitorPasswordTask] - Password Task : &amp;lt;task-id&amp;gt; Status: IN_PROGRESS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...PasswordTaskUtil.monitorPasswordTask] - Password Task : &amp;lt;task-id&amp;gt; Status: FAILED
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...Task.injectFailedEventWithLocale] - Injecting task failure event. Error Code : &amp;#39;VCFOPSPWID03&amp;#39;, Retry : &amp;#39;false&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;java.lang.RuntimeException: Password task UPDATE for &amp;lt;nsx-manager-fqdn&amp;gt; has failed. [...]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;as call from NSX received invalid response.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;ldquo;Invalid response&amp;rdquo; suggests connectivity or certificate problems, and that is exactly the wrong place to go digging. NSX was up, reachable, and answering; it just did not like the request.&lt;/p&gt;
&lt;h2 id="finding-the-real-error"&gt;Finding the Real Error&lt;/h2&gt;
&lt;p&gt;Drill into the failed password task and expand the details. The &lt;code&gt;Cause&lt;/code&gt; field carries the message that the top-level error flattened away:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/nsx-vcfopspwid03-password-reuse/027-capture-027.webp" alt="Failed password update task details showing the cause: specified password invalid, password has been already used, choose another." width="1800" height="359" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Description: Password update for resource : &amp;lt;nsx-manager-fqdn&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user : admin and credential type : API
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Progress Messages: Failed to get NSX user details.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cause: Specified password invalid: Password has been already
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; used. Choose another.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There it is. Not a connectivity issue, not a certificate issue, &lt;strong&gt;password reuse&lt;/strong&gt;. NSX checked the new password against its password history and refused it.&lt;/p&gt;
&lt;h2 id="the-nsx-password-reuse-policy"&gt;The NSX Password Reuse Policy&lt;/h2&gt;
&lt;p&gt;Password history on NSX is not the classic PAM &lt;code&gt;/etc/security/opasswd&lt;/code&gt; mechanism (mine was empty; that was my first dead end). It is governed by the &lt;code&gt;password_remembrance&lt;/code&gt; setting in the node authentication policy, alongside the complexity settings.&lt;/p&gt;
&lt;p&gt;Prompt for the admin password once instead of putting it inline: passwords containing &lt;code&gt;!&lt;/code&gt; get mangled by history expansion in interactive shells (&lt;code&gt;set +H&lt;/code&gt; disables that in bash; in zsh use &lt;code&gt;unsetopt BANG_HIST&lt;/code&gt;), and inline credentials linger in shell history:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +H
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;NSX admin password: &amp;#34;&lt;/span&gt; NSXPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;api_failed_auth_lockout_period&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;api_max_auth_failures&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;minimum_password_length&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;password_remembrance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or on the NSX CLI: &lt;code&gt;get password-complexity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Per the &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/advanced-network-management/authentication-and-authorization/authentication-policy-settings.html"&gt;VCF 9.1 NSX documentation&lt;/a&gt;, &lt;code&gt;password_remembrance&lt;/code&gt; is the number of previous passwords a user cannot reuse. Three details matter here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NSX supports &lt;strong&gt;one password policy&lt;/strong&gt; (you cannot exempt a single user like &lt;code&gt;admin&lt;/code&gt; from history checks) and the manager password-policy settings synchronize across the management cluster nodes.&lt;/li&gt;
&lt;li&gt;In VCF 9.1 the &lt;strong&gt;default value is 5&lt;/strong&gt; and the documented &lt;strong&gt;valid range is 1 to 12&lt;/strong&gt; for new configurations. Out of the box, the last five passwords are blocked, which is why my recycled lab password was refused without anyone ever hardening this environment. (The same doc notes that policy settings customized before an upgrade are retained afterward, so upgraded environments may be carrying older values.)&lt;/li&gt;
&lt;li&gt;Older NSX 4.x documentation describes &lt;code&gt;0&lt;/code&gt; as &amp;ldquo;check disabled&amp;rdquo;. This 9.1 build rejects &lt;code&gt;0&lt;/code&gt; outright, as I found out next.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These examples use &lt;code&gt;curl -k&lt;/code&gt;, which skips TLS certificate verification, fine in a lab where the manager still has a self-signed certificate. In production, drop &lt;code&gt;-k&lt;/code&gt; and trust the NSX CA instead. When you are done, &lt;code&gt;unset NSXPASS&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-you-cannot-just-disable-password-history"&gt;Why You Cannot Just Disable Password History&lt;/h2&gt;
&lt;p&gt;My first instinct was to turn the history check off entirely, since &lt;code&gt;0&lt;/code&gt; was the documented disabled/default value in NSX 4.x. Both the CLI (&lt;code&gt;set password-complexity&lt;/code&gt;) and the API refuse it in this build:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;password_remembrance&amp;#34;: 0}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;error_code&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;error_message&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Request body not valid - PasswordComplexityProperties.password_remembrance: value &amp;#39;0&amp;#39; must be greater than or equal to &amp;#39;1&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;module_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;common-services&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That matches the 9.1 documentation, which lists a valid range of &lt;strong&gt;1 to 12&lt;/strong&gt; for new &lt;code&gt;password_remembrance&lt;/code&gt; configurations. In this build there is no accepted way to set &lt;code&gt;0&lt;/code&gt;: the lowest you can configure is &lt;code&gt;1&lt;/code&gt;, which blocks only the single most recent password.&lt;/p&gt;
&lt;h2 id="recommended-fix-use-a-new-compliant-password"&gt;Recommended Fix: Use a New Compliant Password&lt;/h2&gt;
&lt;p&gt;In production (and honestly in most labs too) the right response to &lt;em&gt;&amp;ldquo;Password has been already used&amp;rdquo;&lt;/em&gt; is the boring one: leave the history policy alone, pick a &lt;strong&gt;new&lt;/strong&gt; password that satisfies the policy (minimum length, character classes, no dictionary-based words, not among the remembered previous passwords), and re-run the &lt;strong&gt;Update&lt;/strong&gt; action in VCF Operations. The workflow completes, and the appliance password, the stored credential, and the expiration metadata all stay in sync.&lt;/p&gt;
&lt;p&gt;The next section covers the lab case, where re-using one specific password was the whole point.&lt;/p&gt;
&lt;h2 id="lab-only-workaround-temporarily-lower-password-history-to-1"&gt;Lab-Only Workaround: Temporarily Lower Password History to 1&lt;/h2&gt;
&lt;p&gt;Treat this as a reversible change, not a new setting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Confirm the cause first.&lt;/strong&gt; The failed task&amp;rsquo;s &lt;code&gt;Cause&lt;/code&gt; must actually say &lt;em&gt;&amp;ldquo;Password has been already used&amp;rdquo;&lt;/em&gt;; this workaround fixes nothing else.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Record the current value&lt;/strong&gt;, so you can restore it exactly:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="p"&gt;|&lt;/span&gt; jq .password_remembrance
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;Lower it to &lt;code&gt;1&lt;/code&gt;&lt;/strong&gt; (the minimum of the valid range) so NSX only blocks reuse of the immediately previous password; anything older becomes acceptable again:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;password_remembrance&amp;#34;: 1}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="4"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read the value back before retrying.&lt;/strong&gt; API policy changes take about 20 seconds to apply and synchronize across the manager cluster nodes, rerun the &lt;code&gt;GET&lt;/code&gt; from step 2 and confirm it returns &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Re-run the Update action in VCF Operations.&lt;/strong&gt; In my case the task completed with the recycled password, and because the change went through the supported workflow, the appliance password, the stored credential, and the expiration metadata all ended up in sync, no &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;manual vault surgery&lt;/a&gt; required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Restore the exact value you recorded in step 2&lt;/strong&gt;: not &amp;ldquo;whatever the default is&amp;rdquo;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;password_remembrance&amp;#34;: &amp;lt;original-value&amp;gt;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Two follow-ups worth knowing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Even with &lt;code&gt;password_remembrance: 1&lt;/code&gt;, you can never &amp;ldquo;change&amp;rdquo; to the password that is currently set (the workflow requires current and new to differ) and the most recent entry in the history may still be blocked. If you absolutely must land back on a very recently used password (labs again), rotate through one or two throwaway passwords first.&lt;/li&gt;
&lt;li&gt;Keep an eye on &lt;code&gt;api_max_auth_failures&lt;/code&gt;: enough failed update attempts with a wrong current password will lock the account on top of everything else.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="if-reuse-is-not-your-problem"&gt;If Reuse Is Not Your Problem&lt;/h2&gt;
&lt;p&gt;The same flattened &lt;em&gt;&amp;ldquo;call from NSX received invalid response&amp;rdquo;&lt;/em&gt; error can hide any password policy rejection, not just reuse. Start with the failed task&amp;rsquo;s &lt;code&gt;Cause&lt;/code&gt; field: in this environment it carried NSX&amp;rsquo;s real error text, and reading it costs nothing.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;Cause&lt;/code&gt; is still too vague, you can provoke NSX into stating its verbatim reason by attempting the change directly against the node API, with one important caveat:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;This is not a validation call.&lt;/strong&gt; &lt;code&gt;PUT /api/v1/node/users/&amp;lt;userid&amp;gt;&lt;/code&gt; is the real password-change API; there is no dry-run. If the request &lt;em&gt;succeeds&lt;/em&gt;, the NSX &lt;code&gt;admin&lt;/code&gt; password has just changed outside VCF Operations: the Fleet vault and SDDC Manager still hold the old credential, and every workflow that authenticates to NSX inherits that drift until you rotate once more through the VCF Operations &lt;strong&gt;Update&lt;/strong&gt; action (entering the just-set password as the current one). Only run this with a password you actually intend to keep.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First find the user ID (the built-in &lt;code&gt;admin&lt;/code&gt; is typically &lt;code&gt;10000&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/users
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then attempt the change, letting &lt;code&gt;jq&lt;/code&gt; build the payload so special characters survive the shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;New password: &amp;#34;&lt;/span&gt; NEWPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq -nc --arg old &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --arg new &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NEWPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;{password: $new, old_password: $old}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/users/&amp;lt;userid&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; NEWPASS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Whatever check is failing comes back in plain text: reuse, minimum length, character classes, or the Linux PAM dictionary baseline. That last one deserves a mention: the docs state the default password complexity rules &amp;ldquo;as enforced by the Linux PAM module&amp;rdquo; always apply on top of the configurable settings, and there is no auth-policy knob to turn them off. Dictionary-based passwords (including the &lt;code&gt;&amp;lt;VendorName&amp;gt;1!&lt;/code&gt;-style classics every lab inherits) get rejected on API-driven changes even when they satisfy length and character-class rules. If the error says &amp;ldquo;dictionary word&amp;rdquo; or &amp;ldquo;too simplistic,&amp;rdquo; no &lt;code&gt;password_remembrance&lt;/code&gt; setting will save you; pick a password without recognizable words.&lt;/p&gt;
&lt;p&gt;If the direct call succeeds but the VCF Operations workflow still fails, then you genuinely have a workflow-side problem, and the &lt;code&gt;component-manager-plugin-*.log&lt;/code&gt; on the VCF Operations node is the place to look, but remember the vault is now behind, so plan one more rotation through &lt;strong&gt;Update&lt;/strong&gt; once the workflow is fixed.&lt;/p&gt;
&lt;h2 id="verification"&gt;Verification&lt;/h2&gt;
&lt;p&gt;After the update task completes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Update Password&lt;/strong&gt; request in Management Tasks completes successfully.&lt;/li&gt;
&lt;li&gt;The new password authenticates against the NSX API: a quick policy read doubles as a credential check (prompt again so the variable holds the &lt;em&gt;new&lt;/em&gt; password, and &lt;code&gt;unset NSXPASS&lt;/code&gt; when done):&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;New NSX admin password: &amp;#34;&lt;/span&gt; NSXPASS&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -u admin:&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NSXPASS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://&amp;lt;nsx-manager-fqdn&amp;gt;/api/v1/node/aaa/auth-policy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;UI login to NSX Manager with the new password works.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password_remembrance&lt;/code&gt; is restored to the exact value you recorded before the workaround, not whatever the troubleshooting session left behind.&lt;/li&gt;
&lt;li&gt;The password entry in Fleet shows a healthy status and refreshed expiration metadata, the &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;account query from the expired password sync post&lt;/a&gt; works for this.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="final-notes"&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;The error message is the villain of this story. &lt;em&gt;&amp;ldquo;Call from NSX received invalid response&amp;rdquo;&lt;/em&gt; sent me looking at connectivity and certificates, when the task details had the real answer one click deeper: &lt;em&gt;&amp;ldquo;Password has been already used. Choose another.&amp;rdquo;&lt;/em&gt; When a VCF Operations password task fails with VCFOPSPWID03, expand the task and read the &lt;code&gt;Cause&lt;/code&gt; before touching anything else.&lt;/p&gt;
&lt;p&gt;The second lesson is that the NSX build in VCF 9.1 rejects disabling password history, new &lt;code&gt;password_remembrance&lt;/code&gt; values are limited to &lt;code&gt;1&lt;/code&gt; through &lt;code&gt;12&lt;/code&gt;, with a default of &lt;code&gt;5&lt;/code&gt;. In a lab, temporarily dropping it to &lt;code&gt;1&lt;/code&gt; is a reasonable escape hatch for recycling a password, as long as you restore the original value afterward. In production, reusing passwords is the actual problem, use a new compliant password and keep the history policy strict.&lt;/p&gt;</content:encoded></item><item><title>Fixing Expired Password Sync in VCF 9.1 Fleet Management</title><link>https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/</link><pubDate>Tue, 07 Jul 2026 17:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/</guid><description>&lt;p&gt;In VCF 9.1, Fleet Password Management accounts can get stuck in &lt;strong&gt;EXPIRED&lt;/strong&gt; status, and the password workflows changed compared to 9.0. In 9.0, you may have seen UI actions such as &lt;strong&gt;Disconnected&lt;/strong&gt; or &lt;strong&gt;Remediate&lt;/strong&gt;. In the &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;9.1 environment I was working on&lt;/a&gt;, those actions were not available. The UI exposed &lt;strong&gt;Update&lt;/strong&gt;, and the Fleet Password Management API provides the same kind of workflow: query password accounts, then update or rotate the password.&lt;/p&gt;</description><content:encoded>&lt;p&gt;In VCF 9.1, Fleet Password Management accounts can get stuck in &lt;strong&gt;EXPIRED&lt;/strong&gt; status, and the password workflows changed compared to 9.0. In 9.0, you may have seen UI actions such as &lt;strong&gt;Disconnected&lt;/strong&gt; or &lt;strong&gt;Remediate&lt;/strong&gt;. In the &lt;a href="https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/"&gt;9.1 environment I was working on&lt;/a&gt;, those actions were not available. The UI exposed &lt;strong&gt;Update&lt;/strong&gt;, and the Fleet Password Management API provides the same kind of workflow: query password accounts, then update or rotate the password.&lt;/p&gt;
&lt;h2 id="symptoms"&gt;Symptoms&lt;/h2&gt;
&lt;p&gt;The issue in this case was simple to describe but easy to chase in the wrong place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some password accounts showed as &lt;strong&gt;EXPIRED&lt;/strong&gt; in Fleet password management.&lt;/li&gt;
&lt;li&gt;The VCF Operations &lt;code&gt;root&lt;/code&gt; password had already been changed outside Fleet.&lt;/li&gt;
&lt;li&gt;The 9.1 UI did not expose the older remediation-style options, so the useful paths were the &lt;strong&gt;Update&lt;/strong&gt; action for single accounts and the API for repeatable remediation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This post walks through the recovery path I used for VCF 9.1.&lt;/p&gt;
&lt;h2 id="what-changed-in-vcf-91-password-management"&gt;What Changed in VCF 9.1 Password Management&lt;/h2&gt;
&lt;p&gt;The important realization is that VCF 9.1 Fleet Password Management does not expose a documented &amp;ldquo;store this already changed password in the vault&amp;rdquo; workflow.&lt;/p&gt;
&lt;p&gt;The UI exposes &lt;strong&gt;Update&lt;/strong&gt; for a password account. For automation or for working through a larger list of expired entries, the official API exposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /suite-api/api/fleet-management/password-management/accounts/query&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT /suite-api/api/fleet-management/password-management/accounts/{passwordAccountKey}/password&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The update workflow requires both the current password and the new password. In the API these fields are &lt;code&gt;currentPassword&lt;/code&gt; and &lt;code&gt;newPassword&lt;/code&gt;; in the UI they are entered through the &lt;strong&gt;Update&lt;/strong&gt; action. Either way, this is a rotation workflow. If a password was already changed directly on the appliance, you need to provide that current real password and rotate once more through Fleet so the appliance password, the vault, and the expiration metadata are back in sync.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/suite-api/api/fleet-management/password-management/accounts/query/post/"&gt;Get VCF Password Accounts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/suite-api/api/fleet-management/password-management/accounts/passwordAccountKey/password/put/"&gt;Update Password&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vcf-operations-api/latest/"&gt;VCF Operations API Authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-a-vcf-operations-api-token"&gt;Get a VCF Operations API Token&lt;/h2&gt;
&lt;p&gt;The VCF Operations API supports &lt;code&gt;OpsToken&lt;/code&gt; authorization. Set the VCF Operations API host first:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OPS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://&amp;lt;vcf-operations-fqdn&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These examples use &lt;code&gt;curl -k&lt;/code&gt;, which skips TLS certificate verification, common in labs where the appliance still has its self-signed certificate. With &lt;code&gt;-k&lt;/code&gt; you are sending credentials to whatever answers on that FQDN. In production, drop &lt;code&gt;-k&lt;/code&gt; and trust the VCF Operations CA instead, for example &lt;code&gt;curl --cacert /path/to/vcf-ops-ca.pem ...&lt;/code&gt;, or add the CA to the system trust store.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use an account that is authorized to call the Fleet password management APIs. Avoid echoing the password back to the terminal. The &lt;code&gt;read -rp&lt;/code&gt; / &lt;code&gt;read -rsp&lt;/code&gt; prompts in this post use bash syntax; if your interactive shell is zsh, either start &lt;code&gt;bash&lt;/code&gt; first or use the zsh form, for example &lt;code&gt;read -rs 'VCFOPS_PASSWORD?VCF Operations password: '&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Acquire a token:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rp &lt;span class="s2"&gt;&amp;#34;VCF Operations username: &amp;#34;&lt;/span&gt; VCFOPS_USERNAME
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;VCF Operations password: &amp;#34;&lt;/span&gt; VCFOPS_PASSWORD&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;jq -nc &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg u &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCFOPS_USERNAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --arg p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCFOPS_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;{username:$u,password:$p}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -sk -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/auth/token/acquire&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r .token&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; VCFOPS_PASSWORD
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;null&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Token acquisition failed&amp;#34;&lt;/span&gt; &amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Test the token:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: OpsToken &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/versions/current&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="query-expired-password-accounts"&gt;Query Expired Password Accounts&lt;/h2&gt;
&lt;p&gt;Now query the expired password entries:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: OpsToken &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;status&amp;#34;:&amp;#34;EXPIRED&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/fleet-management/password-management/accounts/query?pageSize=200&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; tee /tmp/expired-password-accounts.json &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For a cleaner table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq -r &lt;span class="s1"&gt;&amp;#39;.vcfPasswordAccounts[] |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; [.appliance, .applianceFqdn, .userName, .credentialType, .expiryDate, .passwordAccountKey] |
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; @tsv&amp;#39;&lt;/span&gt; /tmp/expired-password-accounts.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I usually sort the output into a tracking table like this:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Appliance&lt;/th&gt;
					&lt;th&gt;FQDN&lt;/th&gt;
					&lt;th&gt;User&lt;/th&gt;
					&lt;th&gt;Credential Type&lt;/th&gt;
					&lt;th&gt;Action&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF_OPERATIONS&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;vcf-operations-fqdn&amp;gt;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;root&lt;/td&gt;
					&lt;td&gt;SSH&lt;/td&gt;
					&lt;td&gt;Update in UI or rotate through API&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SDDC_MANAGER&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;sddc-manager-fqdn&amp;gt;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;root&lt;/td&gt;
					&lt;td&gt;SSH&lt;/td&gt;
					&lt;td&gt;Confirm current password, then rotate&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF_SERVICES_RUNTIME&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;lt;vcf-services-runtime-fqdn&amp;gt;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;vmware-system-user&lt;/td&gt;
					&lt;td&gt;SSH&lt;/td&gt;
					&lt;td&gt;Confirm ownership before rotating&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Do not blindly rotate everything at once. Some accounts may be service users, some may belong to appliances that are temporarily unreachable, and some may be stale entries for components that no longer exist. Also note that domain-level credentials such as ESXi, vCenter, and NSX are owned by SDDC Manager rather than the Fleet vault; those rotate through the &lt;a href="https://cosmin.us/mastering-the-v1-credentials-api-in-sddc-manager-for-enhanced-security-management/"&gt;SDDC Manager /v1/credentials API&lt;/a&gt; instead.&lt;/p&gt;
&lt;h2 id="update-an-expired-password-account"&gt;Update an Expired Password Account&lt;/h2&gt;
&lt;p&gt;For a single account, you can do this from the VCF Operations UI by selecting the expired password account and using &lt;strong&gt;Update&lt;/strong&gt;. Enter the current working password and the new final password.&lt;/p&gt;
&lt;p&gt;For repeatable remediation, use the API equivalent below.&lt;/p&gt;
&lt;p&gt;One important CLI note: do not paste passwords with special characters directly into an inline curl or shell variable assignment. Passwords that contain an exclamation mark can be changed or rejected by the shell before they ever reach the API because &lt;code&gt;!&lt;/code&gt; may trigger history expansion in interactive shells.&lt;/p&gt;
&lt;p&gt;If you are using Bash, disable history expansion for the session:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +H
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are using Zsh, disable bang history expansion:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unsetopt BANG_HIST
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The safer pattern is to prompt for the password and let &lt;code&gt;jq&lt;/code&gt; build the JSON payload.&lt;/p&gt;
&lt;p&gt;Pick one expired entry and export the key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;passwordAccountKey&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the update call. The &lt;code&gt;currentPassword&lt;/code&gt; must be the password that works on the target right now. The &lt;code&gt;newPassword&lt;/code&gt; is the new final password you want Fleet to set and store.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;Current password: &amp;#34;&lt;/span&gt; CUR&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -rsp &lt;span class="s2"&gt;&amp;#34;New password: &amp;#34;&lt;/span&gt; NEW&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq -nc --arg c &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$CUR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --arg n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$NEW&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;{currentPassword:$c,newPassword:$n}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk -X PUT &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: OpsToken &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d @- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/fleet-management/password-management/accounts/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/password&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; tee /tmp/pwupdate-task.json &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;unset&lt;/span&gt; CUR NEW
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The response should create a password update workflow request. Track the task in VCF Operations, or use the returned request ID if your environment exposes the workflow request endpoint.&lt;/p&gt;
&lt;p&gt;After the task completes, query the account again. Filter by the FQDN of the appliance you just updated (it is in your tracking table or &lt;code&gt;/tmp/expired-password-accounts.json&lt;/code&gt;) so the result does not depend on how many password accounts the fleet has:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: OpsToken &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;applianceFqdn&amp;#34;:&amp;#34;&amp;lt;appliance-fqdn&amp;gt;&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/fleet-management/password-management/accounts/query?pageSize=200&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq --arg KEY &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$KEY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.vcfPasswordAccounts[] | select(.passwordAccountKey==$KEY)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You want to see the account move out of &lt;code&gt;EXPIRED&lt;/code&gt; and show a new &lt;code&gt;expiryDate&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="if-the-password-was-already-changed-outside-fleet"&gt;If the Password Was Already Changed Outside Fleet&lt;/h2&gt;
&lt;p&gt;This was the awkward case in my environment.&lt;/p&gt;
&lt;p&gt;If the password has already been changed manually on the appliance, the Fleet vault may still have the old value. Since 9.1 does not provide a documented vault-only update, use the actual current appliance password as the current password and rotate once more to a new final password through the UI &lt;strong&gt;Update&lt;/strong&gt; action or the API.&lt;/p&gt;
&lt;p&gt;That gives Fleet a successful workflow and lets it update:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The appliance password&lt;/li&gt;
&lt;li&gt;The stored credential&lt;/li&gt;
&lt;li&gt;The expiration metadata&lt;/li&gt;
&lt;li&gt;The password account status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to keep the exact same password that was already set manually, that is where the product gap shows up. The documented workflow wants a change from current to new.&lt;/p&gt;
&lt;h2 id="if-the-current-password-is-unknown"&gt;If the Current Password Is Unknown&lt;/h2&gt;
&lt;p&gt;If nobody knows the current password, Fleet cannot update it because the workflow requires the current password.&lt;/p&gt;
&lt;p&gt;Use the native recovery method for that appliance first. For example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the VM console.&lt;/li&gt;
&lt;li&gt;Reset the account to a temporary known password.&lt;/li&gt;
&lt;li&gt;Confirm SSH or console login works.&lt;/li&gt;
&lt;li&gt;Immediately rotate from temporary to final through the UI &lt;strong&gt;Update&lt;/strong&gt; action or the Fleet API.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do not leave the temporary password as the final state. The point is to re-enter the supported Fleet workflow as quickly as possible.&lt;/p&gt;
&lt;h2 id="if-an-entry-looks-stale"&gt;If an Entry Looks Stale&lt;/h2&gt;
&lt;p&gt;Before rotating, verify that the appliance still exists and belongs to the environment:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: OpsToken &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;applianceFqdn&amp;#34;:&amp;#34;&amp;lt;appliance-fqdn&amp;gt;&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/fleet-management/password-management/accounts/query?pageSize=50&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also check DNS and reachability from the shell where you are running the remediation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getent hosts &amp;lt;appliance-fqdn&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -k -I https://&amp;lt;appliance-fqdn&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the component has been removed but the password entry remains, do not delete database rows manually. Open a support case or use the &lt;a href="https://cosmin.us/scripted-components-cleanup-from-vcf-operations-9-1/"&gt;supported inventory cleanup path for that component&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="verification-checklist"&gt;Verification Checklist&lt;/h2&gt;
&lt;p&gt;After the expired entries are addressed, verify the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The expired account query returns fewer entries, ideally zero for the scope you remediated.&lt;/li&gt;
&lt;li&gt;Updated accounts show a refreshed &lt;code&gt;expiryDate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The password update workflow completed successfully.&lt;/li&gt;
&lt;li&gt;Direct login to the target appliance works with the new password.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Query all remaining expired entries:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sk &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: OpsToken &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;status&amp;#34;:&amp;#34;EXPIRED&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OPS&lt;/span&gt;&lt;span class="s2"&gt;/suite-api/api/fleet-management/password-management/accounts/query?pageSize=200&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;&amp;#39;.vcfPasswordAccounts&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, clean up the working files, since they contain fleet inventory details such as appliance FQDNs, usernames, and password account keys:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -f /tmp/expired-password-accounts.json /tmp/pwupdate-task.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="final-notes"&gt;Final Notes&lt;/h2&gt;
&lt;p&gt;The main lesson is that VCF 9.1 password management needs to be treated as an update or rotation workflow. The password account state is exposed through VCF Operations Fleet Password Management, and expired entries need to be handled through the UI &lt;strong&gt;Update&lt;/strong&gt; action or the documented account query and password update API calls. This is the same rotate-only philosophy the platform has had since the &lt;a href="https://cosmin.us/changing-passwords-for-the-vrealize-suite-via-vrslcm-vrealize-suite-lifecycle-manager/"&gt;vRSLCM Locker password management&lt;/a&gt; days; the tooling changed, the workflow shape did not.&lt;/p&gt;
&lt;p&gt;For this kind of issue, I would avoid two shortcuts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do not use VCF 9.0 UI guidance for VCF 9.1.&lt;/li&gt;
&lt;li&gt;Do not update Fleet LCM database rows by hand.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reliable path is to update expired accounts through the UI or API and verify the resulting password account state.&lt;/p&gt;</content:encoded></item><item><title>Upgrading VCF 9.1 to 9.1.0.0300 Step by Step</title><link>https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/</link><pubDate>Sun, 05 Jul 2026 17:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/upgrading-vcf-9-1-to-9-1-0-0300-step-by-step/</guid><description>&lt;p&gt;The 9.1.0.0300 patch train for VMware Cloud Foundation 9.1 is applied through a few different lifecycle views. In my lab, the update covered the Fleet Lifecycle component, VCF Operations, SDDC Lifecycle, and SDDC Manager.&lt;/p&gt;
&lt;p&gt;Before starting, review the official Broadcom release notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-installer/sddc-manager-9-1-0-0300-release-notes.html"&gt;SDDC Manager 9.1.0.0300 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-operations/9-1-0-0300.html"&gt;VCF Operations 9.1.0.0300 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Broadcom describes these patch releases as time-sensitive fixes that can be applied between major, minor, and maintenance releases. That also means every component may not move at the same time, so check what is actually offered in your environment instead of assuming the whole VCF bill of materials changes together.&lt;/p&gt;</description><content:encoded>&lt;p&gt;The 9.1.0.0300 patch train for VMware Cloud Foundation 9.1 is applied through a few different lifecycle views. In my lab, the update covered the Fleet Lifecycle component, VCF Operations, SDDC Lifecycle, and SDDC Manager.&lt;/p&gt;
&lt;p&gt;Before starting, review the official Broadcom release notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-installer/sddc-manager-9-1-0-0300-release-notes.html"&gt;SDDC Manager 9.1.0.0300 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vcf/vcf-9-0-and-later/9-1/release-notes/patch-releases-9-1-0-x/vcf-operations/9-1-0-0300.html"&gt;VCF Operations 9.1.0.0300 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Broadcom describes these patch releases as time-sensitive fixes that can be applied between major, minor, and maintenance releases. That also means every component may not move at the same time, so check what is actually offered in your environment instead of assuming the whole VCF bill of materials changes together.&lt;/p&gt;
&lt;h2 id="versions-in-this-upgrade"&gt;Versions in This Upgrade&lt;/h2&gt;
&lt;p&gt;Here is what was upgraded in this run.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;From&lt;/th&gt;
					&lt;th&gt;To&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Fleet Lifecycle&lt;/td&gt;
					&lt;td&gt;9.1.0.0.25371109&lt;/td&gt;
					&lt;td&gt;9.1.0.0300.25536195&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;VCF Operations&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25500350&lt;/td&gt;
					&lt;td&gt;9.1.0.0300.25531073&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SDDC Lifecycle&lt;/td&gt;
					&lt;td&gt;9.1.0.0200.25495903&lt;/td&gt;
					&lt;td&gt;9.1.0.0300.25536194&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SDDC Manager&lt;/td&gt;
					&lt;td&gt;9.1.0.0200 build 25496021&lt;/td&gt;
					&lt;td&gt;9.1.0.0300 build 25536191&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As always, take backups or snapshots that match your normal rollback procedure, confirm that the Broadcom depot is reachable, and make sure no other lifecycle operations are running before you start.&lt;/p&gt;
&lt;h2 id="start-in-vcf-management"&gt;Start in VCF Management&lt;/h2&gt;
&lt;p&gt;Log in to VCF Operations and go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Management -&amp;gt; Upgrade&lt;/strong&gt;. If the lifecycle metadata has not synced recently, use &lt;strong&gt;Sync&lt;/strong&gt; before checking for available target versions.&lt;/p&gt;
&lt;p&gt;The Fleet Lifecycle card is the first item I updated.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/001-capture-001.webp" alt="VCF Operations Build Lifecycle page showing the Fleet Lifecycle upgrade card and target version selector." width="1592" height="310" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Click the target version selector and choose the 9.1.0.0300 target.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/002-navigate-to-vcf-operations-build-lifecycle-vcf-management-upgrade-sync.webp" alt="Fleet Lifecycle Component Target Version dialog showing 9.1.0.0300.25536195 as an available target version." width="773" height="214" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;After selecting the target, the Fleet Lifecycle card should show the upgrade path to &lt;strong&gt;9.1.0.0300.25536195&lt;/strong&gt;. Click &lt;strong&gt;Upgrade&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/004-capture-004.webp" alt="Fleet Lifecycle card showing the upgrade path from 9.1.0.0.25371109 to 9.1.0.0300.25536195." width="844" height="121" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-fleet-lifecycle"&gt;Upgrade Fleet Lifecycle&lt;/h2&gt;
&lt;p&gt;Once the task starts, the Fleet Lifecycle card changes to &lt;strong&gt;Upgrade in progress&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/005-capture-005.webp" alt="Fleet Lifecycle card showing upgrade in progress with a link to upgrade details." width="850" height="135" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Open &lt;strong&gt;Upgrade details&lt;/strong&gt; to monitor the subtask list. In my run, the task staged binaries, ran component stage prechecks, and initialized the VCF component stage.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/006-capture-006.webp" alt="Fleet Lifecycle upgrade details showing staging binaries and component stage precheck messages." width="1036" height="440" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;When this finishes, the Fleet Lifecycle card should show the new current version.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/007-capture-007.webp" alt="Fleet Lifecycle card showing current version 9.1.0.0300.25536195." width="751" height="357" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="set-the-vcf-management-target-version"&gt;Set the VCF Management Target Version&lt;/h2&gt;
&lt;p&gt;Next, set the management component target version. In the &lt;strong&gt;Target Version 9.1.0.*&lt;/strong&gt; section, click &lt;strong&gt;Change Target Version&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In my lab I used the wildcard &lt;strong&gt;9.1.0.*&lt;/strong&gt; global version. Select the patch release for VCF Operations and any other management components that might need to be upgraded.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/008-capture-008.webp" alt="Set Target Version dialog showing VCF global version 9.1.0.* and VCF Operations target 9.1.0.0300.25531073." width="761" height="515" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Set Version&lt;/strong&gt; and then run the prechecks. The page should show the components that are ready for upgrade.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/009-capture-009.webp" alt="VCF Management upgrade page showing VCF Operations and SDDC Lifecycle ready for upgrade." width="970" height="320" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-vcf-operations"&gt;Upgrade VCF Operations&lt;/h2&gt;
&lt;p&gt;Start with VCF Operations. The row in my environment moved from &lt;strong&gt;9.1.0.0200.25500350&lt;/strong&gt; to &lt;strong&gt;9.1.0.0300.25531073&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Upgrade&lt;/strong&gt; for the VCF Operations row.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/010-capture-010.webp" alt="VCF Operations row showing upgrade in progress from 9.1.0.0200.25500350 to 9.1.0.0300.25531073." width="822" height="96" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Use &lt;strong&gt;Upgrade details&lt;/strong&gt; to monitor the precheck and update process. In this run, the task started an appliance precheck, initiated the VCF Ops precheck, and then began applying the system update.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/011-capture-011.webp" alt="VCF Operations upgrade details showing component upgrade prechecks and system update messages." width="1047" height="480" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;When the VCF Operations update completes, the &lt;strong&gt;Tasks&lt;/strong&gt; tab should show the refresh and upgrade tasks as completed.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/012-capture-012.webp" alt="VCF Management Tasks tab showing Refresh component VCF Operations and VCF Operations Upgrade completed." width="545" height="210" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;h2 id="upgrade-sddc-lifecycle"&gt;Upgrade SDDC Lifecycle&lt;/h2&gt;
&lt;p&gt;After VCF Operations is done, return to the upgrade list. SDDC Lifecycle should still show as ready if you did not upgrade everything at once.&lt;/p&gt;
&lt;p&gt;In my environment, SDDC Lifecycle moved from &lt;strong&gt;9.1.0.0200.25495903&lt;/strong&gt; to &lt;strong&gt;9.1.0.0300.25536194&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/013-capture-013.webp" alt="SDDC Lifecycle row showing ready for upgrade from 9.1.0.0200.25495903 to 9.1.0.0300.25536194." width="979" height="93" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Upgrade&lt;/strong&gt; for SDDC Lifecycle and monitor the upgrade details.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/014-capture-014.webp" alt="SDDC Lifecycle row showing upgrade in progress." width="837" height="150" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;The details panel should show the SDDC Lifecycle plugin being staged in the VCF services runtime.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/015-capture-015.webp" alt="SDDC Lifecycle upgrade details showing staging in the VCF services runtime." width="880" height="283" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Wait for the task to complete before moving on to the SDDC Manager upgrade plan.&lt;/p&gt;
&lt;h2 id="download-the-sddc-manager-patch-binary"&gt;Download the SDDC Manager Patch Binary&lt;/h2&gt;
&lt;p&gt;Now go to &lt;strong&gt;Build -&amp;gt; Lifecycle -&amp;gt; VCF Instances -&amp;gt; instance-a -&amp;gt; Binary Management&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Set &lt;strong&gt;VCF Version&lt;/strong&gt; to &lt;strong&gt;9.1&lt;/strong&gt;, select &lt;strong&gt;Patch Binaries&lt;/strong&gt;, and confirm the &lt;strong&gt;SDDC Manager 9.1.0.0300&lt;/strong&gt; binary is downloaded. In this run the binary was released on &lt;strong&gt;Jun 29, 2026&lt;/strong&gt; and was &lt;strong&gt;2.41 GB&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/016-capture-016.webp" alt="Binary Management page showing SDDC Manager 9.1.0.0300 patch binary downloaded." width="1338" height="380" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;If it is not downloaded yet, select the binary and click &lt;strong&gt;Download&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="edit-the-workload-domain-upgrade-plan"&gt;Edit the Workload Domain Upgrade Plan&lt;/h2&gt;
&lt;p&gt;Go to the management domain under the VCF instance, then open the &lt;strong&gt;Upgrades&lt;/strong&gt; tab. In this example the management domain is &lt;strong&gt;mgmt-a&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Edit Plan&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/017-capture-017.webp" alt="Management domain Upgrades tab showing Edit Plan for the component upgrade plan." width="876" height="318" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;Plan Component Upgrade&lt;/strong&gt;, select &lt;strong&gt;SDDC Manager&lt;/strong&gt; and choose target version &lt;strong&gt;9.1.0.0300&lt;/strong&gt;. In my run, ESX, NSX, and vCenter were already on 9.1.0.0100 and were not selected for this 0300 SDDC Manager patch plan.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/018-capture-018.webp" alt="Plan Component Upgrade wizard showing SDDC Manager selected with target version 9.1.0.0300." width="1023" height="531" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt; and review the plan. The wizard notes that SDDC Manager is upgraded first so it can continue orchestrating the remaining component lifecycle work.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/019-capture-019.webp" alt="Plan Overview page showing VMware SDDC Manager 9.1.0.0300 Upgrade with a release notes link." width="1024" height="523" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Submit Plan&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="start-or-schedule-the-sddc-manager-upgrade"&gt;Start or Schedule the SDDC Manager Upgrade&lt;/h2&gt;
&lt;p&gt;The upgrade sequence should now show the SDDC Manager 9.1.0.0300 upgrade as the available step. You can run it immediately with &lt;strong&gt;Upgrade Now&lt;/strong&gt; or schedule it for a maintenance window.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/020-capture-020.webp" alt="Upgrade Sequence page showing VMware SDDC Manager 9.1.0.0300 Upgrade with Upgrade Now and Schedule buttons." width="837" height="196" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;After starting the upgrade, monitor the &lt;strong&gt;VMware Cloud Foundation Upgrade Status&lt;/strong&gt; page. You can also click &lt;strong&gt;View Upgrade Activity&lt;/strong&gt; for deeper task progress.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/021-capture-021.webp" alt="VMware Cloud Foundation Upgrade Status page showing SDDC Manager upgrade in progress." width="1315" height="651" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;In my run, the visible steps included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run VCF Prerequisite&lt;/li&gt;
&lt;li&gt;Setup Common Appliance Platform&lt;/li&gt;
&lt;li&gt;Validate Services Before Upgrade&lt;/li&gt;
&lt;li&gt;Remove Packages Pre Upgrade&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not refresh services or reboot appliances manually while the upgrade is running. Let the lifecycle workflow complete.&lt;/p&gt;
&lt;h2 id="validate-the-upgrade"&gt;Validate the Upgrade&lt;/h2&gt;
&lt;p&gt;After the workflow completes, return to the management domain and open &lt;strong&gt;Component Versions&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The SDDC Manager row should show the same current and target version, with status &lt;strong&gt;On Target&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cosmin.us/images/2026/07/vcf-9-1-0300-upgrade/022-capture-022.webp" alt="Component Versions page showing SDDC Manager current version and target version 9.1.0.0300.25536191 with On Target status." width="1591" height="425" loading="lazy" decoding="async"&gt;
&lt;/p&gt;
&lt;p&gt;I also recommend checking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VCF Management -&amp;gt; Tasks&lt;/strong&gt; for failed or partially completed tasks&lt;/li&gt;
&lt;li&gt;VCF Operations health and adapters&lt;/li&gt;
&lt;li&gt;SDDC Manager service health&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fleet password management&lt;/strong&gt; for accounts showing &lt;strong&gt;EXPIRED&lt;/strong&gt;. I covered the remediation in &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;Fixing Expired Password Sync in VCF 9.1 Fleet Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Workload domain upgrade status&lt;/li&gt;
&lt;li&gt;Depot/binary cleanup after you are comfortable with the rollback window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you keep older bundles around for too long, they can consume a lot of space. I covered bundle cleanup separately in &lt;a href="https://cosmin.us/cleaning-up-vcf-bundles/"&gt;Cleaning up VCF Bundles&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>Exporting and Restoring vCenter 8.x Permissions Before Breaking Enhanced Linked Mode</title><link>https://cosmin.us/exporting-and-restoring-vcenter-8-x-permissions-before-breaking-enhanced-linked-mode/</link><pubDate>Tue, 30 Jun 2026 15:45:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/exporting-and-restoring-vcenter-8-x-permissions-before-breaking-enhanced-linked-mode/</guid><description>&lt;p&gt;Breaking Enhanced Linked Mode is one of those changes where the technical command is not the hardest part. The hard part is making sure administrators, service accounts, and external products can still log in and do their jobs after the vCenters no longer share the same SSO domain.&lt;/p&gt;
&lt;p&gt;In this post I will walk through a repeatable way to export and restore vCenter 8.x RBAC data before splitting Enhanced Linked Mode. The focus is on three permission layers:&lt;/p&gt;</description><content:encoded>&lt;p&gt;Breaking Enhanced Linked Mode is one of those changes where the technical command is not the hardest part. The hard part is making sure administrators, service accounts, and external products can still log in and do their jobs after the vCenters no longer share the same SSO domain.&lt;/p&gt;
&lt;p&gt;In this post I will walk through a repeatable way to export and restore vCenter 8.x RBAC data before splitting Enhanced Linked Mode. The focus is on three permission layers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom roles&lt;/li&gt;
&lt;li&gt;Explicit object or inventory permissions&lt;/li&gt;
&lt;li&gt;Global permissions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The short version is this: &lt;strong&gt;object permissions usually survive the split because they live in the vCenter database, but global permissions and SSO-domain objects need special handling&lt;/strong&gt;. If you depend on global permissions, do not start the split until you have exported them and have a plan to recreate or import them afterward.&lt;/p&gt;
&lt;h2 id="what-changes-when-you-split-elm"&gt;What Changes When You Split ELM&lt;/h2&gt;
&lt;p&gt;Enhanced Linked Mode lets multiple vCenter Server instances share one vCenter Single Sign-On domain. When you break that relationship, the vCenters stop sharing the same SSO namespace.&lt;/p&gt;
&lt;p&gt;That matters because not all permissions are stored the same way.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Item&lt;/th&gt;
					&lt;th&gt;What to expect&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Custom roles&lt;/td&gt;
					&lt;td&gt;Stored in the vCenter database, so they usually survive the split. Export them anyway and re-import if anything drifted.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Object permissions&lt;/td&gt;
					&lt;td&gt;Usually remain on the vCenter inventory objects, but the principals must still resolve after the split.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Global permissions&lt;/td&gt;
					&lt;td&gt;Must be exported and recreated/imported after the split.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Local SSO users/groups&lt;/td&gt;
					&lt;td&gt;Must be recreated if they are still needed.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;AD/LDAP identity sources&lt;/td&gt;
					&lt;td&gt;Must be recreated or verified on the standalone vCenter.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Solution users/plugins&lt;/td&gt;
					&lt;td&gt;Usually need product-specific re-registration or repair.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If the environment is managed by VMware Cloud Foundation / SDDC Manager, stop and validate supportability first. Cross-domain repointing is not something I would treat as a casual vCenter-only operation in a VCF managed environment.&lt;/p&gt;
&lt;h2 id="download-the-helper-scripts"&gt;Download the Helper Scripts&lt;/h2&gt;
&lt;p&gt;I use three helper scripts for this workflow:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Script&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://cosmin.us/downloads/vcenter-elm-rbac/Export-VCenterRbac.ps1"&gt;Export-VCenterRbac.ps1&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Exports custom roles and explicit object permissions from a vCenter.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://cosmin.us/downloads/vcenter-elm-rbac/Convert-AuthzDoctorPermissions.ps1"&gt;Convert-AuthzDoctorPermissions.ps1&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Converts &lt;code&gt;authz-doctor&lt;/code&gt; output into a clean CSV for global permissions.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a href="https://cosmin.us/downloads/vcenter-elm-rbac/Import-VCenterRbac.ps1"&gt;Import-VCenterRbac.ps1&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Imports roles, optional global permissions, and object permissions after the split.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The scripts assume PowerShell 7+ and PowerCLI:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Install-Module&lt;/span&gt; &lt;span class="n"&gt;VMware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;PowerCLI&lt;/span&gt; &lt;span class="n"&gt;-Scope&lt;/span&gt; &lt;span class="n"&gt;CurrentUser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Set-PowerCLIConfiguration&lt;/span&gt; &lt;span class="n"&gt;-InvalidCertificateAction&lt;/span&gt; &lt;span class="n"&gt;Warn&lt;/span&gt; &lt;span class="n"&gt;-Confirm:&lt;/span&gt;&lt;span class="vm"&gt;$false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the import with &lt;code&gt;-WhatIf&lt;/code&gt; first. This is especially important when restoring global permissions.&lt;/p&gt;
&lt;h2 id="before-you-export-anything"&gt;Before You Export Anything&lt;/h2&gt;
&lt;p&gt;Do the boring checks first. This is where most bad outcomes are avoided.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Confirm which vCenters are staying linked and which vCenters are being split.&lt;/li&gt;
&lt;li&gt;Confirm you have working SSO administrator access.&lt;/li&gt;
&lt;li&gt;Confirm you have root access to each VCSA so you can run &lt;code&gt;authz-doctor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Take a file-based backup of each vCenter.&lt;/li&gt;
&lt;li&gt;Take powered-off snapshots of all ELM nodes at the same point in time if that is your rollback method.&lt;/li&gt;
&lt;li&gt;If vCenter HA is enabled, remove it before the split.&lt;/li&gt;
&lt;li&gt;Identify any local SSO users/groups that need to exist after the split.&lt;/li&gt;
&lt;li&gt;Identify all AD/LDAP identity sources that need to be recreated.&lt;/li&gt;
&lt;li&gt;Identify solution accounts for NSX, SRM, Aria, backup products, monitoring tools, and plugins.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I also like to create at least one explicit vCenter-root permission for a known AD admin group on each vCenter before the change. Do not rely only on global permissions for your break-glass path.&lt;/p&gt;
&lt;h2 id="step-1-export-roles-and-object-permissions"&gt;Step 1: Export Roles and Object Permissions&lt;/h2&gt;
&lt;p&gt;Create one export folder per vCenter. Do not mix them. The object paths and managed object references are specific to the vCenter they came from.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="n"&gt;C:&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;vcenter-elm&lt;/span&gt;&lt;span class="n"&gt;-rbac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Export-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-OutDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Export-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa02&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-OutDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa02&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Export-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa03&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-OutDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa03&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each export folder should contain:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;manifest.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;roles.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;object-permissions.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;object-permissions.csv
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;global-permissions.template.csv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;roles.json&lt;/code&gt; is used for import. &lt;code&gt;object-permissions.json&lt;/code&gt; is also used for import. The CSV is there so you can review the permissions quickly in Excel or another editor.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;manifest.json&lt;/code&gt; and make sure the count looks reasonable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Get-Content&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;json&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;ConvertFrom-Json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-export-global-permissions-with-authz-doctor"&gt;Step 2: Export Global Permissions with authz-doctor&lt;/h2&gt;
&lt;p&gt;Global permissions are the part I care about most in an ELM split. They are easy to forget because they live under &lt;strong&gt;Administration &amp;gt; Access Control &amp;gt; Global Permissions&lt;/strong&gt;, not on the normal inventory tree.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;authz-doctor&lt;/code&gt; tool is preinstalled on recent vCenter builds, but not on all of them. If the path below does not exist on your appliance, download the RPM attached to &lt;a href="https://knowledge.broadcom.com/external/article/369938/using-the-authzdoctor-tool-to-identify-v.html"&gt;Broadcom KB 369938&lt;/a&gt; and install it with &lt;code&gt;rpm -i --force&lt;/code&gt; first, which is the install command the KB uses.&lt;/p&gt;
&lt;p&gt;On each vCenter appliance, SSH in as &lt;code&gt;root&lt;/code&gt; and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/lib/vmware-vpx/scripts/authz-doctor/authz-doctor.py permission_check &amp;gt; /tmp/authz-doctor-permissions.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Copy the file back to the matching export folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;scp root@vcsa01.example.com:/tmp/authz-doctor-permissions.txt ./exports/vcsa01/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The output is a bordered ASCII table. The permission rows look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------------+-------+---------+-----------+-----------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Principal | Group | Role Id | Role Name | Propagate | Entity |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------------+-------+---------+-----------+-----------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| VSPHERE.LOCAL\vpxd-extension-xxxx | False | -1 | Admin | True | Global |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| DOMAIN\vSphere-Admins | True | -1 | Admin | True | Global |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-----------------------------------+-------+---------+-----------+-----------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The converter detects permission rows by their six-column layout and skips the border and header lines, so you can feed it the raw &lt;code&gt;permission_check&lt;/code&gt; output without any cleanup.&lt;/p&gt;
&lt;p&gt;Then convert the global permission rows into CSV:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Convert-AuthzDoctorPermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-InputFile&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;authz-doctor&lt;/span&gt;&lt;span class="n"&gt;-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;txt&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-OutputFile&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;global-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;csv&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-GlobalOnly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Repeat this for each vCenter.&lt;/p&gt;
&lt;p&gt;The resulting file should have this shape:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;Principal&amp;#34;,&amp;#34;IsGroup&amp;#34;,&amp;#34;RoleId&amp;#34;,&amp;#34;RoleName&amp;#34;,&amp;#34;Propagate&amp;#34;,&amp;#34;Entity&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;DOMAIN\vSphere-Admins&amp;#34;,&amp;#34;True&amp;#34;,&amp;#34;-1&amp;#34;,&amp;#34;Admin&amp;#34;,&amp;#34;True&amp;#34;,&amp;#34;Global&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-3-review-principals-before-the-split"&gt;Step 3: Review Principals Before the Split&lt;/h2&gt;
&lt;p&gt;Do not blindly import the CSV later. Review it first.&lt;/p&gt;
&lt;p&gt;Pay special attention to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;administrator@vsphere.local&lt;/code&gt; or users from the old SSO domain&lt;/li&gt;
&lt;li&gt;Local SSO groups that will not exist after the split&lt;/li&gt;
&lt;li&gt;Solution users such as &lt;code&gt;vpxd-*&lt;/code&gt;, &lt;code&gt;vsphere-ui-*&lt;/code&gt;, NSX, SRM, backup, or monitoring accounts&lt;/li&gt;
&lt;li&gt;AD groups whose domain name or identity source alias may change&lt;/li&gt;
&lt;li&gt;Custom roles that exist on one vCenter but not another&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are moving from a shared SSO domain to standalone SSO domains, a principal name that made sense before the split may not resolve afterward. The permission entry can exist, but it is useless if the identity source cannot resolve the user or group.&lt;/p&gt;
&lt;h2 id="step-4-add-temporary-object-level-admin-access"&gt;Step 4: Add Temporary Object-Level Admin Access&lt;/h2&gt;
&lt;p&gt;Before breaking ELM, add a direct permission at the root of each vCenter inventory for the admin group you will use after the split.&lt;/p&gt;
&lt;p&gt;In the vSphere Client:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select the vCenter object at the top of the inventory.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Permissions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add your AD admin group.&lt;/li&gt;
&lt;li&gt;Assign the appropriate role, usually &lt;code&gt;Administrator&lt;/code&gt; for the migration window.&lt;/li&gt;
&lt;li&gt;Enable propagation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This gives you a local object permission that is independent of Global Permissions. It is your practical safety net.&lt;/p&gt;
&lt;h2 id="step-5-break-enhanced-linked-mode"&gt;Step 5: Break Enhanced Linked Mode&lt;/h2&gt;
&lt;p&gt;Follow the supported vCenter 8.x ELM split procedure for your environment. At a high level, the flow is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Shut down the vCenter being split from the SSO domain.&lt;/li&gt;
&lt;li&gt;From one of the remaining linked vCenters, unregister the powered-off node.&lt;/li&gt;
&lt;li&gt;Power on the vCenter being split.&lt;/li&gt;
&lt;li&gt;Repoint it to a standalone SSO domain.&lt;/li&gt;
&lt;li&gt;Validate that the vCenter no longer shows the other linked vCenters.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Be aware that the unregister step (&lt;code&gt;cmsso-util unregister&lt;/code&gt;) restarts all vCenter services on the node where you run it, so plan for a short vSphere Client outage on that remaining vCenter, not just on the one being split.&lt;/p&gt;
&lt;p&gt;One extra step if your ELM group has only two nodes: after the repoint, &lt;a href="https://knowledge.broadcom.com/external/article/370062/splitting-enhanced-linked-mode-elm.html"&gt;Broadcom KB 370062&lt;/a&gt; says to also run &lt;code&gt;cmsso-util unregister&lt;/code&gt; on the remaining node, so the stale partner information for the node that left is released.&lt;/p&gt;
&lt;p&gt;The key point for this post is timing: &lt;strong&gt;do not import permissions until the standalone vCenter has its identity source and SSO domain in the final state&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="step-6-recreate-identity-sources-and-local-sso-objects"&gt;Step 6: Recreate Identity Sources and Local SSO Objects&lt;/h2&gt;
&lt;p&gt;After the vCenter is standalone, log in with the new SSO administrator and recreate or verify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AD/LDAP identity sources&lt;/li&gt;
&lt;li&gt;Local SSO users&lt;/li&gt;
&lt;li&gt;Local SSO groups&lt;/li&gt;
&lt;li&gt;Any SSO group nesting used by the exported permissions&lt;/li&gt;
&lt;li&gt;Certificates or trust needed for LDAPS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also check &lt;strong&gt;Global Permissions&lt;/strong&gt; for stale entries that still reference the previous SSO domain and clean them up. The split KB links a dedicated procedure for removing stale global permissions after a domain repoint, and the import is much easier to reason about when the old domain&amp;rsquo;s dead entries are gone first.&lt;/p&gt;
&lt;p&gt;Before importing permissions, test that the principal resolves. For example, search for the AD group in the vSphere Client permission picker. If the picker cannot resolve it, the import will not give you meaningful access.&lt;/p&gt;
&lt;h2 id="step-7-dry-run-the-import"&gt;Step 7: Dry-Run the Import&lt;/h2&gt;
&lt;p&gt;Start with a dry run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Import-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-InDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-GlobalPermissionsCsv&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;global-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;csv&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-UsePrivateMobForGlobalPermissions&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-WhatIf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The import order is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create or update custom roles.&lt;/li&gt;
&lt;li&gt;Import global permissions if a CSV is provided.&lt;/li&gt;
&lt;li&gt;Import object permissions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The global permission import uses the vCenter MOB endpoint for &lt;code&gt;AuthorizationService.AddGlobalAccessControlList&lt;/code&gt;. That is why the switch is intentionally named &lt;code&gt;-UsePrivateMobForGlobalPermissions&lt;/code&gt;. I want it to be obvious that this is different from the normal object permission path through &lt;code&gt;AuthorizationManager&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The MOB route is specifically the vCenter 8.x answer. vSphere 9.0 added a supported REST API for global permissions (&lt;a href="https://developer.broadcom.com/xapis/vsphere-automation-api/latest/vcenter/vcenter-authorization-permissions/"&gt;&lt;code&gt;POST /api/vcenter/authorization/permissions&lt;/code&gt;&lt;/a&gt; with a &lt;code&gt;GlobalAcl&lt;/code&gt; DynamicID), so if you are doing this on 9.x, use that instead.&lt;/p&gt;
&lt;p&gt;If you only want to restore roles and global permissions first, skip object permissions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Import-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-InDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-GlobalPermissionsCsv&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;global-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;csv&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-UsePrivateMobForGlobalPermissions&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-SkipObjectPermissions&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-WhatIf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-8-run-the-import"&gt;Step 8: Run the Import&lt;/h2&gt;
&lt;p&gt;Once the dry run looks right, run it without &lt;code&gt;-WhatIf&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Import-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-InDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-GlobalPermissionsCsv&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;global-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;csv&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-UsePrivateMobForGlobalPermissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you changed principal names during the split, edit &lt;code&gt;global-permissions.csv&lt;/code&gt; before running the import. For example, change:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OLDSSO\vSphere Admins
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CORP\vSphere Admins
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;or whatever the correct identity source now exposes.&lt;/p&gt;
&lt;h2 id="step-9-verify-access"&gt;Step 9: Verify Access&lt;/h2&gt;
&lt;p&gt;Do not stop after the script completes. Verify the permission model from both the API side and the user side.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;authz-doctor&lt;/code&gt; again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/lib/vmware-vpx/scripts/authz-doctor/authz-doctor.py permission_check &amp;gt; /tmp/authz-doctor-permissions-after.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check Global Permissions in the vSphere Client:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Administration &amp;gt; Access Control &amp;gt; Global Permissions
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then test real logins:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Log out of the SSO administrator account.&lt;/li&gt;
&lt;li&gt;Log in as a user from the restored AD admin group.&lt;/li&gt;
&lt;li&gt;Confirm you can see the expected inventory.&lt;/li&gt;
&lt;li&gt;Confirm you can perform a low-risk administrative action.&lt;/li&gt;
&lt;li&gt;Test at least one non-admin role if you have delegated access.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For object permissions, you can also re-export and compare the count:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="nb"&gt;Export-VCenterRbac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ps1&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Server&lt;/span&gt; &lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;com&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-OutDir&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;vcsa01-after&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Compare-Object&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Import-Csv&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;vcsa01&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;object-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Import-Csv&lt;/span&gt; &lt;span class="p"&gt;.\&lt;/span&gt;&lt;span class="n"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;vcsa01-after&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;object-permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Property&lt;/span&gt; &lt;span class="n"&gt;Principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;RoleName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;Propagate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;EntityPath&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Some differences are expected if you intentionally changed principals or cleaned up stale entries. Unexpected missing admin groups are not expected.&lt;/p&gt;
&lt;h2 id="common-gotchas"&gt;Common Gotchas&lt;/h2&gt;
&lt;p&gt;The import cannot fix an identity source that does not exist. Recreate AD/LDAP first.&lt;/p&gt;
&lt;p&gt;Custom role IDs can change. The import script matches role names first because role IDs are not always stable across systems.&lt;/p&gt;
&lt;p&gt;Object permissions can point to objects that no longer exist. The script tries the original managed object reference first and then the inventory path. If neither resolves, review the CSV and decide whether the permission is still needed.&lt;/p&gt;
&lt;p&gt;Solution users are not normal human permissions. If NSX, SRM, Aria, a backup product, or a monitoring tool owns a registration, use that product&amp;rsquo;s supported reconnect or repair procedure instead of blindly restoring stale solution-user permissions.&lt;/p&gt;
&lt;p&gt;Global permissions are broad. Review them carefully before bringing them back into a standalone vCenter.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/370062/splitting-enhanced-linked-mode-elm.html"&gt;Broadcom KB 370062 - Splitting Enhanced Linked Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/369938/using-the-authzdoctor-tool-to-identify-v.html"&gt;Broadcom KB 369938 - Using authz-doctor to identify vCenter permissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/407544/vcls-vms-deployment-fails-vcenter-report.html"&gt;Broadcom KB 407544 - vCLS VMs deployment fails (documents the &lt;code&gt;AuthorizationService.AddGlobalAccessControlList&lt;/code&gt; MOB workflow)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vsphere-web-services-api/latest/vim.AuthorizationManager.html"&gt;vSphere Web Services API - AuthorizationManager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.broadcom.com/xapis/vsphere-automation-api/latest/vcenter/vcenter-authorization-permissions/"&gt;vSphere Automation API - vCenter Authorization Permissions (vSphere 9.0+)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal is not just to preserve a list of permissions. The goal is to preserve access that still resolves, still matches the right role, and still works after each vCenter stands on its own.&lt;/p&gt;</content:encoded></item><item><title>Clearing a Full vSAN Trace Ramdisk Across ESXi Hosts in Parallel</title><link>https://cosmin.us/clearing-a-full-vsan-trace-ramdisk-across-esxi-hosts-in-parallel/</link><pubDate>Wed, 24 Jun 2026 10:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/clearing-a-full-vsan-trace-ramdisk-across-esxi-hosts-in-parallel/</guid><description>&lt;p&gt;While reviewing an SOS support bundle from a VMware Cloud Foundation environment, I noticed every ESXi host in the management cluster was logging the same warning, over and over, right up to the moment the bundle was collected:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[vob.visorfs.ramdisk.full] Cannot extend visorfs file
/vsantraces/vsantracesLSOMVerbose--...zst because its ramdisk
(vsantraceFailover) is full.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are &lt;code&gt;-INFO&lt;/code&gt; level VOB events, not errors, and they do not touch your data or VMs. But when the same symptom appears on all hosts at once, fires continuously, and never clears on its own, it is worth understanding what is actually happening and fixing it cluster-wide rather than logging into each host by hand. This post walks through the diagnosis and a small Bash script that queries, fixes, and reclaims space on every host in parallel.&lt;/p&gt;</description><content:encoded>&lt;p&gt;While reviewing an SOS support bundle from a VMware Cloud Foundation environment, I noticed every ESXi host in the management cluster was logging the same warning, over and over, right up to the moment the bundle was collected:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[vob.visorfs.ramdisk.full] Cannot extend visorfs file
/vsantraces/vsantracesLSOMVerbose--...zst because its ramdisk
(vsantraceFailover) is full.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are &lt;code&gt;-INFO&lt;/code&gt; level VOB events, not errors, and they do not touch your data or VMs. But when the same symptom appears on all hosts at once, fires continuously, and never clears on its own, it is worth understanding what is actually happening and fixing it cluster-wide rather than logging into each host by hand. This post walks through the diagnosis and a small Bash script that queries, fixes, and reclaims space on every host in parallel.&lt;/p&gt;
&lt;h2 id="understanding-the-vsan-trace-ramdisk"&gt;Understanding the vSAN Trace Ramdisk&lt;/h2&gt;
&lt;p&gt;vSAN writes diagnostic traces (DOM, LSOM, CLOM, PLOG, and others) to &lt;code&gt;/vsantraces&lt;/code&gt;, an in-memory location backed by a ramdisk. Under normal operation these traces rotate into compressed &lt;code&gt;.zst&lt;/code&gt; archives and the ramdisk stays well under capacity. ESXi also keeps a secondary &lt;code&gt;vsantraceFailover&lt;/code&gt; ramdisk that catches trace writes when the primary cannot be extended.&lt;/p&gt;
&lt;p&gt;The warning above means the &lt;em&gt;failover&lt;/em&gt; ramdisk has hit 100% and the trace daemon can no longer write new trace data. Because tracing is purely diagnostic, the cluster keeps running normally, but you lose trace history, the logs fill with noise, and a genuinely useful troubleshooting tool is effectively offline.&lt;/p&gt;
&lt;p&gt;A few things are easy to get wrong here, so it is worth being precise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This is &lt;strong&gt;not&lt;/strong&gt; caused by verbose tracing being left on. On a healthy vSAN ESA cluster, &lt;code&gt;LSOMVerbose&lt;/code&gt; is enabled by default. Confirm the configured level before assuming someone changed it.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;vsantraced&lt;/code&gt; restart re-initializes the daemon but does &lt;strong&gt;not&lt;/strong&gt; purge files already sitting on the failover ramdisk. If the ramdisk is full, restarting alone will often leave it full.&lt;/li&gt;
&lt;li&gt;The real reclaim comes from removing the old rotated &lt;code&gt;.zst&lt;/code&gt; archives, which are the bulk of the consumed space.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="diagnosing-before-you-touch-anything"&gt;Diagnosing Before You Touch Anything&lt;/h2&gt;
&lt;p&gt;The first job is to confirm the state on every host with read-only commands. Three pieces of information tell you almost everything:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# What trace level is actually configured?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;esxcli vsan trace get
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Is the failover ramdisk full?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vdf -h &lt;span class="p"&gt;|&lt;/span&gt; grep -i vsantrace
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# What is consuming the space?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -lhS /vsantraces/ &lt;span class="p"&gt;|&lt;/span&gt; head
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;vdf&lt;/code&gt; shows a line like &lt;code&gt;vsantraceFailover 300M 300M 0B 100%&lt;/code&gt;, that is your smoking gun. The &lt;code&gt;ls&lt;/code&gt; output will typically show several large &lt;code&gt;vsantraces--*.zst&lt;/code&gt; archives (often the configured max file size each) as the dominant consumers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on SSH:&lt;/strong&gt; ESXi SSH is disabled by default, and a recent SOS bundle will reflect that. Enable it per host first (vCenter &amp;gt; Host &amp;gt; Configure &amp;gt; Services &amp;gt; SSH &amp;gt; Start) before running anything below, and disable it again when you are done. If you would rather keep SSH off entirely, the same commands can be issued through vCenter with PowerCLI &lt;code&gt;Get-EsxCli&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="querying-every-host-at-once"&gt;Querying Every Host at Once&lt;/h2&gt;
&lt;p&gt;Logging into hosts one at a time does not scale, and the whole point is that this condition tends to hit the entire cluster together. The script below fans out over SSH: it launches one background job per host, waits for all of them, and writes each host&amp;rsquo;s output to its own file. A per-connection timeout keeps a single unreachable host from hanging the whole run.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# query-vsan-traces.sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Query (and optionally fix) all ESXi hosts in parallel for the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# vSAN &amp;#34;vsantraceFailover ramdisk full&amp;#34; condition.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Usage:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ./query-vsan-traces.sh # QUERY only (read-only, default)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ./query-vsan-traces.sh --fix # QUERY, then restart vsantraced&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ./query-vsan-traces.sh --clean # QUERY, then delete OLD .zst archives&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ./query-vsan-traces.sh --clean host1 # restrict the action to specific hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ./query-vsan-traces.sh --clean --yes # skip the confirmation prompt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# SSH_USER=root ./query-vsan-traces.sh # override the SSH user (default: root)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -u
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --- config -----------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HOSTS_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; esx-01.example.lab
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; esx-02.example.lab
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; esx-03.example.lab
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; esx-04.example.lab
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SSH_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SSH_USER&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Per-connection timeouts so one unreachable host can&amp;#39;t hang the whole run.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SSH_OPTS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;-o &lt;span class="nv"&gt;ConnectTimeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; -o &lt;span class="nv"&gt;BatchMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes -o &lt;span class="nv"&gt;StrictHostKeyChecking&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;accept-new&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OUTDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;vsan-trace-report-&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date +%Y%m%d-%H%M%S&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ---------------------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --- arg parsing ------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DO_FIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DO_CLEAN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ASSUME_YES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; arg in &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --fix&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;DO_FIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --clean&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;DO_CLEAN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --yes&lt;span class="p"&gt;|&lt;/span&gt;-y&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;ASSUME_YES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -*&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Unknown option: &lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; *&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="o"&gt;+=(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOSTS_DEFAULT&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# The diagnostic commands run on each host. Keep them read-only.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r -d &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; QUERY_CMDS &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;===== $(hostname) =====&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- esxcli vsan trace get ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;esxcli vsan trace get 2&amp;gt;&amp;amp;1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- ramdisk usage (vsantrace) ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;vdf -h 2&amp;gt;/dev/null | grep -i vsantrace || echo &amp;#34;(no vsantrace ramdisk line)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- top trace files by size ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;ls -lhS /vsantraces/ 2&amp;gt;/dev/null | head -n 15 || echo &amp;#34;(/vsantraces not present)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- recent ramdisk-full VOBs (last 20) ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;grep &amp;#34;vob.visorfs.ramdisk.full&amp;#34; /var/log/vobd.log 2&amp;gt;/dev/null | tail -n 20 || echo &amp;#34;(none)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Remediation A: restart vsantraced and show before/after ramdisk usage.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r -d &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; FIX_CMDS &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;===== $(hostname) =====&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- BEFORE: ramdisk usage ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;vdf -h 2&amp;gt;/dev/null | grep -i vsantrace || echo &amp;#34;(no vsantrace ramdisk line)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- restarting vsantraced ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;/etc/init.d/vsantraced restart 2&amp;gt;&amp;amp;1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;sleep 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- AFTER: ramdisk usage ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;vdf -h 2&amp;gt;/dev/null | grep -i vsantrace || echo &amp;#34;(no vsantrace ramdisk line)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Remediation B: delete OLD .zst archives, keeping the newest 3 per host.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Active (non-.zst) trace files are never touched.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r -d &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; CLEAN_CMDS &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;===== $(hostname) =====&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- BEFORE: ramdisk usage ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;vdf -h 2&amp;gt;/dev/null | grep -i vsantrace || echo &amp;#34;(no vsantrace ramdisk line)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- deleting all but the newest 3 .zst archives ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;ls -t /vsantraces/*.zst 2&amp;gt;/dev/null | tail -n +4 | while read -r f; do
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; echo &amp;#34;rm $f&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; rm -f &amp;#34;$f&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;--- AFTER: ramdisk usage ---&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;vdf -h 2&amp;gt;/dev/null | grep -i vsantrace || echo &amp;#34;(no vsantrace ramdisk line)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run_on_host&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;cmds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;suffix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="si"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;suffix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; ssh &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SSH_OPTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SSH_USER&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cmds&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;OK &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FAIL &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt; (see &lt;/span&gt;&lt;span class="nv"&gt;$out&lt;/span&gt;&lt;span class="s2"&gt; for error)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fan_out&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;cmds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;suffix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; h in &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; run_on_host &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$h&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$cmds&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$suffix&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="o"&gt;+=(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;confirm&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$ASSUME_YES&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -eq &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Proceed on all %d hosts? [y/N] &amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;read&lt;/span&gt; -r reply
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$reply&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; in y&lt;span class="p"&gt;|&lt;/span&gt;Y&lt;span class="p"&gt;|&lt;/span&gt;yes&lt;span class="p"&gt;|&lt;/span&gt;YES&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; *&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Aborted.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt; &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --- 1. QUERY (always) ------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Querying &lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; hosts in parallel as user &amp;#39;&lt;/span&gt;&lt;span class="nv"&gt;$SSH_USER&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Output dir: &lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fan_out &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$QUERY_CMDS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Hosts with the failover ramdisk at 100%:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -l &lt;span class="s2"&gt;&amp;#34;vsantraceFailover.*100%&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$OUTDIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;/*.txt 2&amp;gt;/dev/null &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; (none; ramdisks have headroom)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --- 2. FIX (only with --fix) -----------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DO_FIX&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -eq &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; echo&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;FIX MODE: restart &amp;#39;vsantraced&amp;#39; on &lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; host(s).&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Only affects diagnostic tracing: no vSAN data, VMs, or I/O touched.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; confirm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fan_out &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$FIX_CMDS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;-fix&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --- 3. CLEAN (only with --clean) -------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DO_CLEAN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -eq &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; echo&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CLEAN MODE: delete old .zst archives on &lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;HOSTS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; host(s).&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Keeps the newest 3 archives per host; active trace files untouched.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; confirm
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fan_out &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$CLEAN_CMDS&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;-clean&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="step-1-run-the-query"&gt;Step 1: Run the Query&lt;/h3&gt;
&lt;p&gt;With your hostnames filled into &lt;code&gt;HOSTS_DEFAULT&lt;/code&gt; (or passed on the command line), run it with no arguments first. This is read-only and safe:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./query-vsan-traces.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You get one output file per host plus a summary line listing exactly which hosts are sitting at 100%. Confirm from the &lt;code&gt;esxcli vsan trace get&lt;/code&gt; output that the trace level is the default before going further, if it is, you know this is a stuck-ramdisk problem, not a misconfiguration.&lt;/p&gt;
&lt;h3 id="step-2-try-the-restart"&gt;Step 2: Try the Restart&lt;/h3&gt;
&lt;p&gt;The lightest-touch remediation is to restart the trace daemon, which re-initializes the trace directories:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./query-vsan-traces.sh --fix
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The script prints before/after &lt;code&gt;vdf&lt;/code&gt; output for each host. In my case the restart completed cleanly on all hosts but the failover ramdisk stayed at 100%; the daemon came back, but the files already on the ramdisk were not purged. That is the expected outcome when the ramdisk is already full, and it is exactly why the script does not stop here.&lt;/p&gt;
&lt;h3 id="step-3-reclaim-the-space"&gt;Step 3: Reclaim the Space&lt;/h3&gt;
&lt;p&gt;The reclaim step deletes the old rotated &lt;code&gt;.zst&lt;/code&gt; archives, which are what actually fills the ramdisk. The script keeps the newest three archives per host so you do not lose all recent history, and it never touches the active (non-&lt;code&gt;.zst&lt;/code&gt;) trace files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./query-vsan-traces.sh --clean
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each remediation mode prompts for confirmation once, listing the hosts it is about to act on, and you can skip the prompt with &lt;code&gt;--yes&lt;/code&gt; in an automation context. After the cleanup, the AFTER &lt;code&gt;vdf&lt;/code&gt; line should show the failover ramdisk back under capacity, and the &lt;code&gt;ramdisk.full&lt;/code&gt; VOBs should stop appearing within a minute or two.&lt;/p&gt;
&lt;h2 id="why-this-order-matters"&gt;Why This Order Matters&lt;/h2&gt;
&lt;p&gt;It is tempting to jump straight to deleting files, but running the query first buys you two things. You confirm the trace configuration is actually default (ruling out a real misconfiguration), and you capture a record of the pre-change state in the per-host output files. The restart is offered before the cleanup simply because it is the lower-impact action; when it does not free space, the cleanup is the definitive fix.&lt;/p&gt;
&lt;p&gt;If a host is &lt;em&gt;still&lt;/em&gt; at 100% after a cleanup, that points to something actively re-filling the ramdisk faster than rotation can drain it: a stuck writer, or a persistent trace target that is unwritable. At that point you are past the mechanical fixes and it is worth opening a support request rather than looping on the same commands.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The &amp;ldquo;vsantraceFailover ramdisk full&amp;rdquo; warning looks alarming because it repeats endlessly across every host, but it is a contained, diagnostic-only condition with a safe, repeatable fix. The key is to treat the whole cluster as a unit: query every host in parallel, confirm the configuration is default, attempt the cheap restart, and reclaim space by clearing old trace archives when the restart is not enough. A small Bash wrapper turns what would be a tedious host-by-host chore into three commands you can run from your workstation, with a written record of each host&amp;rsquo;s state along the way.&lt;/p&gt;</content:encoded></item><item><title>Fixing "Error attempting Upgrade Database Schema" When Upgrading vCenter 8.0 U3x to 9.1.0.0</title><link>https://cosmin.us/fixing-error-attempting-upgrade-database-schema-vcenter-9-1-0-0-upgrade/</link><pubDate>Tue, 16 Jun 2026 12:45:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/fixing-error-attempting-upgrade-database-schema-vcenter-9-1-0-0-upgrade/</guid><description>&lt;p&gt;If you&amp;rsquo;re moving vCenter Server from 8.0 U3x to 9.1.0.0 (typically as part of a &lt;a href="https://cosmin.us/deploy-a-vcf-9-instance-in-an-existing-vcf-fleet/"&gt;VCF 9.1 deployment&lt;/a&gt; or a VVF 9.1 upgrade) the run can fail partway through with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error attempting Upgrade Database Schema
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Please check vcintegrity migration logs for details.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is one of those failures that looks scary in the UI but has a clean, well-understood root cause: a handful of &lt;strong&gt;orphaned rows in the vcIntegrity database&lt;/strong&gt; that trip a new foreign-key constraint introduced in 9.1. Below is the whole story; what the error means, how to read the logs, why it happens, and how to clear it so the upgrade completes. It&amp;rsquo;s the same shape of problem I wrote about in &lt;a href="https://cosmin.us/fixing-postgresql-wont-start-after-reboot-on-vcf-operations-fleet-management-9-0-1-and-automating-it/"&gt;fixing PostgreSQL on Fleet Management 9.0.1&lt;/a&gt;: a schema change colliding with pre-existing data.&lt;/p&gt;</description><content:encoded>&lt;p&gt;If you&amp;rsquo;re moving vCenter Server from 8.0 U3x to 9.1.0.0 (typically as part of a &lt;a href="https://cosmin.us/deploy-a-vcf-9-instance-in-an-existing-vcf-fleet/"&gt;VCF 9.1 deployment&lt;/a&gt; or a VVF 9.1 upgrade) the run can fail partway through with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error attempting Upgrade Database Schema
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Please check vcintegrity migration logs for details.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is one of those failures that looks scary in the UI but has a clean, well-understood root cause: a handful of &lt;strong&gt;orphaned rows in the vcIntegrity database&lt;/strong&gt; that trip a new foreign-key constraint introduced in 9.1. Below is the whole story; what the error means, how to read the logs, why it happens, and how to clear it so the upgrade completes. It&amp;rsquo;s the same shape of problem I wrote about in &lt;a href="https://cosmin.us/fixing-postgresql-wont-start-after-reboot-on-vcf-operations-fleet-management-9-0-1-and-automating-it/"&gt;fixing PostgreSQL on Fleet Management 9.0.1&lt;/a&gt;: a schema change colliding with pre-existing data.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is documented in &lt;strong&gt;Broadcom KB 442223&lt;/strong&gt;. The supported fix uses a script attached to that KB. I&amp;rsquo;ll walk through the official steps first, then share an &lt;em&gt;unofficial&lt;/em&gt; helper of my own for the curious: clearly marked, and not a replacement for the KB script.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="the-symptom"&gt;The symptom&lt;/h2&gt;
&lt;p&gt;The upgrade proceeds normally until the &lt;strong&gt;vcIntegrity import phase&lt;/strong&gt;, then halts with the generic schema error shown above. The UI doesn&amp;rsquo;t tell you &lt;em&gt;what&lt;/em&gt; in the schema failed; it just points you at the vcIntegrity migration logs. That&amp;rsquo;s your cue to SSH in and read the actual exception.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="reading-the-upgrade-log"&gt;Reading the upgrade log&lt;/h2&gt;
&lt;p&gt;On the source vCenter, open the vcIntegrity import log:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/var/log/vmware/upgrade/Import_com.vmware.vcIntegrity_####_##_##_##_##.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The meaningful lines look like this (timestamps and IDs trimmed):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DEBUG vmware-vci-vciInstallUtils [VdbODBCError::VdbODBCError] SQLGetDiagRec
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SQLState=&amp;#39;23503&amp;#39; NativeError=1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MessageText=&amp;#39;ERROR: insert or update on table &amp;#34;pm_recommendation_spec&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; violates foreign key constraint &amp;#34;fk_pm_recommendation_spec&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; DETAIL: Key (entity_id, spec_id)=(domain-##, -1000) is not present in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; table &amp;#34;pm_recommendation_info&amp;#34;.&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR vmware-vci-vciInstallUtils [installerRunDBCommand 626] [DATABASE]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Vdb::RunScript, SQL Exec Error: &amp;#34;ODBC error: (23503) - ERROR: insert or
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; update on table &amp;#34;pm_recommendation_spec&amp;#34; violates foreign key constraint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;fk_pm_recommendation_spec&amp;#34; ... &amp;#34; is returned when executing SQL statement
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;ALTER TABLE IF EXISTS PM_RECOMMENDATION_SPEC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ADD CONSTRAINT FK_PM_RECOMMENDATION_SPEC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; FOREIGN KEY (ENTITY_ID, SPEC_ID)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; REFERENCES PM_RECOMMENDATION_INFO (ENTITY_ID, SPEC_ID)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ON DELETE CASCADE&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR __main__ Upgrade Phase &amp;#39;vcIntegrity:Import&amp;#39; failed.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Exception: Error attempting Upgrade Database Schema
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;upgrade_errors.PermanentError: Error attempting Upgrade Database Schema
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Three things are worth pulling out of that wall of text:&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;SQLState is &lt;code&gt;23503&lt;/code&gt;&lt;/strong&gt;, which in PostgreSQL is &lt;code&gt;foreign_key_violation&lt;/code&gt;, not a connectivity, permissions, or disk problem. The database is doing exactly what it was told to do and refusing bad data.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;failing statement is an &lt;code&gt;ALTER TABLE ... ADD CONSTRAINT&lt;/code&gt;&lt;/strong&gt;, not an insert from your workload. The migration is trying to &lt;em&gt;add&lt;/em&gt; the new constraint &lt;code&gt;FK_PM_RECOMMENDATION_SPEC&lt;/code&gt; to an existing table, and Postgres validates the rows already in that table before it will accept the constraint.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;offending key is &lt;code&gt;(entity_id, spec_id) = (domain-##, -1000)&lt;/code&gt;&lt;/strong&gt;. There&amp;rsquo;s a row in &lt;code&gt;pm_recommendation_spec&lt;/code&gt; whose &lt;code&gt;(entity_id, spec_id)&lt;/code&gt; pair has no matching parent row in &lt;code&gt;pm_recommendation_info&lt;/code&gt;. The &lt;code&gt;-1000&lt;/code&gt; is a sentinel/placeholder value, and &lt;code&gt;domain-##&lt;/code&gt; is a managed-object reference, classic leftovers from objects that were removed or never fully written.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="root-cause"&gt;Root cause&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;pm_recommendation_*&lt;/code&gt; tables live in the &lt;strong&gt;vcIntegrity&lt;/strong&gt; database, the component behind vSphere Lifecycle Manager / Update Planner. They store lifecycle &amp;ldquo;recommendation&amp;rdquo; data: &lt;code&gt;pm_recommendation_info&lt;/code&gt; holds the parent records, and &lt;code&gt;pm_recommendation_spec&lt;/code&gt; holds child spec rows that are supposed to reference a parent.&lt;/p&gt;
&lt;p&gt;Over the life of an 8.0 environment, it&amp;rsquo;s possible to end up with &lt;strong&gt;child spec rows whose parent info row is gone&lt;/strong&gt; (or was never created): for example after domains/clusters are removed, or from older code paths that didn&amp;rsquo;t clean up specs. In 8.0 there was no enforced relationship between the two tables, so these orphans sat there harmlessly.&lt;/p&gt;
&lt;p&gt;vCenter &lt;strong&gt;9.1.0.0 hardens the schema&lt;/strong&gt;. The migration adds a composite foreign key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PM_RECOMMENDATION_SPEC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FK_PM_RECOMMENDATION_SPEC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOREIGN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ENTITY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SPEC_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REFERENCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PM_RECOMMENDATION_INFO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ENTITY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SPEC_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When PostgreSQL adds a foreign key, it &lt;strong&gt;validates every existing row&lt;/strong&gt; in the child table against the parent table. Any orphan (a &lt;code&gt;(entity_id, spec_id)&lt;/code&gt; pair with no parent) violates the new constraint, so the engine aborts the &lt;code&gt;ALTER TABLE&lt;/code&gt; with error &lt;code&gt;23503&lt;/code&gt;. Because the migration treats this as a &lt;code&gt;PermanentError&lt;/code&gt;, the whole vcIntegrity import phase fails and the upgrade stops.&lt;/p&gt;
&lt;p&gt;In short: &lt;strong&gt;9.1 is correct to demand referential integrity; your 8.0 data just doesn&amp;rsquo;t satisfy it yet.&lt;/strong&gt; The fix is to remove the orphaned spec rows so the constraint can be created cleanly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Broadcom notes that a fix to prevent this will be included in a future VCF release. Until then, the workaround below is the path forward.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="the-official-fix-kb-442223-workaround"&gt;The official fix (KB 442223 workaround)&lt;/h2&gt;
&lt;p&gt;Do this on the &lt;strong&gt;source&lt;/strong&gt; vCenter appliance, before retrying the upgrade.&lt;/p&gt;
&lt;h3 id="1-snapshot-the-vcenter-appliance"&gt;1. Snapshot the vCenter appliance&lt;/h3&gt;
&lt;p&gt;Take a snapshot of the source vCenter VM first. Editing the embedded database is low-risk when done correctly, but a snapshot is your guaranteed rollback. (If your environment enforces a snapshot-age policy, see &lt;a href="https://cosmin.us/change-delete-old-snapshot-restriction-from-7-days/"&gt;changing the old-snapshot restriction&lt;/a&gt;, just remember to remove this snapshot once the upgrade succeeds.)&lt;/p&gt;
&lt;h3 id="2-download-the-cleanup-script-from-the-kb"&gt;2. Download the cleanup script from the KB&lt;/h3&gt;
&lt;p&gt;Download &lt;code&gt;cleanup_rec_orphans.py&lt;/code&gt; from the &lt;strong&gt;Attachments&lt;/strong&gt; section of &lt;a href="https://knowledge.broadcom.com/external/article/442223"&gt;KB 442223&lt;/a&gt;. This is the supported script, use it for production work.&lt;/p&gt;
&lt;h3 id="3-copy-the-script-to-the-appliance"&gt;3. Copy the script to the appliance&lt;/h3&gt;
&lt;p&gt;Place it in &lt;code&gt;/tmp&lt;/code&gt; on the vCenter server. You can use an SCP client such as WinSCP. If WinSCP fails with a &lt;em&gt;&amp;ldquo;Received too large … SFTP packet&amp;rdquo;&lt;/em&gt; error, follow &lt;a href="https://knowledge.broadcom.com/external/article/326317/connecting-to-vcenter-server-virtual-app.html"&gt;KB 326317&lt;/a&gt; (set the shell to &lt;code&gt;bash&lt;/code&gt; for the session, or use the SCP fallback).&lt;/p&gt;
&lt;h3 id="4-ssh-in-as-root"&gt;4. SSH in as root&lt;/h3&gt;
&lt;p&gt;Log in to the vCenter appliance over SSH with &lt;code&gt;root&lt;/code&gt;. Enable the shell if needed (&lt;code&gt;shell&lt;/code&gt; from the appliancesh prompt).&lt;/p&gt;
&lt;h3 id="5-dry-run-audit-read-only"&gt;5. Dry-run audit (read-only)&lt;/h3&gt;
&lt;p&gt;Run the script with no flags first. It reports orphans &lt;strong&gt;without changing anything&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;su updatemgr -s /bin/bash -c &lt;span class="s2"&gt;&amp;#34;python3 /tmp/cleanup_rec_orphans.py&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;su updatemgr&lt;/code&gt; matters: the &lt;code&gt;updatemgr&lt;/code&gt; account owns the vcIntegrity database connection, so the script authenticates correctly without you handling credentials.&lt;/p&gt;
&lt;h3 id="6-execute-the-cleanup"&gt;6. Execute the cleanup&lt;/h3&gt;
&lt;p&gt;Once you&amp;rsquo;ve reviewed the dry-run output, run it again with &lt;code&gt;--execute&lt;/code&gt; to delete the orphaned rows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;su updatemgr -s /bin/bash -c &lt;span class="s2"&gt;&amp;#34;python3 /tmp/cleanup_rec_orphans.py --execute&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="7-retry-the-upgrade"&gt;7. Retry the upgrade&lt;/h3&gt;
&lt;p&gt;Re-run the vCenter upgrade. With the orphans gone, the &lt;code&gt;ALTER TABLE ... ADD CONSTRAINT&lt;/code&gt; validates cleanly and the vcIntegrity import phase completes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-the-script-actually-does-the-sql-behind-it"&gt;What the script actually does (the SQL behind it)&lt;/h2&gt;
&lt;p&gt;You don&amp;rsquo;t need to know this to run the KB script, but it helps to understand &lt;em&gt;why&lt;/em&gt; it&amp;rsquo;s safe. The job is purely to find child rows with no parent and remove them. The detection is a straightforward anti-join:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- Orphans: spec rows whose (entity_id, spec_id) has no parent info row
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pm_recommendation_spec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pm_recommendation_info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the cleanup is the matching delete:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pm_recommendation_spec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pm_recommendation_info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spec_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. You&amp;rsquo;re deleting only spec rows that already point at nothing, exactly the rows the new constraint would reject. No valid recommendation data is touched.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="optional-an-unofficial-auditcleanup-helper"&gt;Optional: an unofficial audit/cleanup helper&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use the KB script for anything you care about.&lt;/strong&gt; The Bash helper below is a community convenience I wrote to mirror the same logic for quick auditing in labs. It is &lt;strong&gt;unofficial and unsupported&lt;/strong&gt;, runs &lt;strong&gt;read-only by default&lt;/strong&gt;, and should only be pointed at a vCenter you&amp;rsquo;ve snapshotted. If in doubt, stop and use &lt;code&gt;cleanup_rec_orphans.py&lt;/code&gt; from the KB.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It does three things: locate the database that actually owns the table (so it doesn&amp;rsquo;t matter what the DB is named in your build), report the orphan count and the offending pairs, and (only with &lt;code&gt;--execute&lt;/code&gt;) delete them inside a transaction.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# audit_rec_orphans.sh: UNOFFICIAL community helper (KB 442223)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Mirrors the intent of Broadcom&amp;#39;s cleanup_rec_orphans.py: find/remove&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# orphaned rows in pm_recommendation_spec that have no parent in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# pm_recommendation_info and therefore block the FK_PM_RECOMMENDATION_SPEC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# constraint added by the vCenter 9.1.0.0 vcIntegrity schema upgrade.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# DRY-RUN by default. Pass --execute to delete.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ALWAYS snapshot the vCenter appliance first.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prefer the official KB script for supported/production environments.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run it the same way the KB runs its script (as the vcIntegrity DB owner):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# su updatemgr -s /bin/bash -c &amp;#34;/tmp/audit_rec_orphans.sh&amp;#34; # audit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# su updatemgr -s /bin/bash -c &amp;#34;/tmp/audit_rec_orphans.sh --execute&amp;#34; # delete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -euo pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;EXECUTE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--execute&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;EXECUTE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;id -un&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;updatemgr&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[!] Not running as &amp;#39;updatemgr&amp;#39;: DB auth will likely fail.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34; Re-run: su updatemgr -s /bin/bash -c \&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Prefer the embedded vPostgres client if present&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PSQL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/opt/vmware/vpostgres/current/bin/psql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; -x &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSQL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;PSQL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; -v psql&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Discover which database owns pm_recommendation_spec (override with VCI_DB=...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;VCI_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VCI_DB&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCI_DB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; db in &lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSQL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -Atqc &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;SELECT datname FROM pg_database WHERE datistemplate=false&amp;#34;&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSQL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -Atqd &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -c &lt;span class="s2"&gt;&amp;#34;SELECT to_regclass(&amp;#39;pm_recommendation_spec&amp;#39;)&amp;#34;&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;VCI_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCI_DB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[x] Could not locate the vcIntegrity DB (set VCI_DB=...)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; 1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[*] Using database: &lt;/span&gt;&lt;span class="nv"&gt;$VCI_DB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ORPHAN_FILTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;FROM pm_recommendation_spec s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; LEFT JOIN pm_recommendation_info i
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ON i.entity_id = s.entity_id AND i.spec_id = s.spec_id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; WHERE i.entity_id IS NULL&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSQL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -Atqd &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCI_DB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -c &lt;span class="s2"&gt;&amp;#34;SELECT count(*) &lt;/span&gt;&lt;span class="nv"&gt;$ORPHAN_FILTER&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[*] Orphaned pm_recommendation_spec rows: &lt;/span&gt;&lt;span class="nv"&gt;$COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[+] No orphans: FK_PM_RECOMMENDATION_SPEC will validate cleanly.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[*] Offending (entity_id, spec_id) pairs:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSQL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCI_DB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -c &lt;span class="s2"&gt;&amp;#34;SELECT s.entity_id, s.spec_id &lt;/span&gt;&lt;span class="nv"&gt;$ORPHAN_FILTER&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ORDER BY s.entity_id, s.spec_id&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$EXECUTE&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -ne &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[i] DRY-RUN only. Re-run with --execute to delete the rows above.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[*] Deleting orphaned rows in a transaction…&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSQL&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -v &lt;span class="nv"&gt;ON_ERROR_STOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$VCI_DB&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;SQL&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;BEGIN;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;DELETE FROM pm_recommendation_spec s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;WHERE NOT EXISTS (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; SELECT 1 FROM pm_recommendation_info i
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; WHERE i.entity_id = s.entity_id AND i.spec_id = s.spec_id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;COMMIT;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;[+] Done. Re-run without --execute to confirm 0 orphans, then retry the upgrade.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save it to &lt;code&gt;/tmp/audit_rec_orphans.sh&lt;/code&gt;, then run the dry-run first and review the output before ever adding &lt;code&gt;--execute&lt;/code&gt;. Like the KB script, it&amp;rsquo;s idempotent, running it again after a successful cleanup simply reports zero orphans.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="verifying-the-fix"&gt;Verifying the fix&lt;/h2&gt;
&lt;p&gt;Re-run the audit (dry-run); it should now report &lt;strong&gt;0 orphaned rows&lt;/strong&gt;. That single number is the whole signal: zero orphans means the new foreign key has nothing left to reject.&lt;/p&gt;
&lt;p&gt;Then retry the vCenter upgrade and confirm the &lt;strong&gt;vcIntegrity:Import&lt;/strong&gt; phase passes. If you want belt-and-suspenders confirmation, tail the new import log and check that the &lt;code&gt;ALTER TABLE ... ADD CONSTRAINT FK_PM_RECOMMENDATION_SPEC&lt;/code&gt; statement executes without a &lt;code&gt;23503&lt;/code&gt; error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -i &lt;span class="s2"&gt;&amp;#34;FK_PM_RECOMMENDATION_SPEC\|23503\|Upgrade Database Schema&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /var/log/vmware/upgrade/Import_com.vmware.vcIntegrity_*.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No matches on &lt;code&gt;23503&lt;/code&gt; (and a clean run past the schema step) means you&amp;rsquo;re through it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="rollback"&gt;Rollback&lt;/h2&gt;
&lt;p&gt;If anything looks wrong after the cleanup or the retried upgrade, &lt;strong&gt;revert to the snapshot&lt;/strong&gt; you took in step 1 and reassess before trying again. The cleanup itself only removes already-orphaned rows, so a revert puts you exactly back where you started.&lt;/p&gt;
&lt;p&gt;Once the upgrade has completed successfully and vCenter is healthy, &lt;strong&gt;delete the snapshot&lt;/strong&gt;: leaving snapshots on a vCenter appliance long-term causes its own problems (disk growth, performance, and consolidation headaches).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="notes--gotchas"&gt;Notes &amp;amp; gotchas&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;su updatemgr&lt;/code&gt;?&lt;/strong&gt; That OS account maps to the database role that owns the vcIntegrity connection. Running the script under it means you never handle DB credentials by hand, and the connection has exactly the rights it needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is deleting these rows safe?&lt;/strong&gt; Yes; you&amp;rsquo;re only removing &lt;code&gt;pm_recommendation_spec&lt;/code&gt; rows that already reference a non-existent parent. They&amp;rsquo;re dead lifecycle-recommendation data; no live configuration depends on them. Recommendations regenerate as needed after the upgrade.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does it apply to VVF as well as VCF?&lt;/strong&gt; The KB lists both VMware Cloud Foundation 9.1 and VMware vSphere Foundation 9.1; the trigger is the vCenter 9.1.0.0 schema change, so it&amp;rsquo;s the same regardless of which edition you&amp;rsquo;re upgrading under.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Will it come back?&lt;/strong&gt; Broadcom has stated a fix is planned for a future VCF release so the orphans don&amp;rsquo;t block the migration. Until then, audit-then-clean is the routine.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/442223"&gt;Broadcom KB 442223 - &amp;ldquo;Error attempting Upgrade Database Schema&amp;rdquo; during vCenter 8.0 U3x to 9.1.0.0 upgrade&lt;/a&gt; (symptoms, cause, and the official &lt;code&gt;cleanup_rec_orphans.py&lt;/code&gt; workaround).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/326317/connecting-to-vcenter-server-virtual-app.html"&gt;Broadcom KB 326317 - Connecting to vCenter Server Virtual Appliance using WinSCP fails with &amp;ldquo;Received too large … SFTP packet&amp;rdquo;&lt;/a&gt; (needed if file transfer to the appliance fails).&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Fix: Unable to Update BOM Components, "Compatibility File Is Missing" in SDDC Manager</title><link>https://cosmin.us/unable-to-update-bom-components-from-sddc-manager-compatibility-file-is-missing/</link><pubDate>Fri, 05 Jun 2026 09:15:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/unable-to-update-bom-components-from-sddc-manager-compatibility-file-is-missing/</guid><description>&lt;p&gt;If you have &lt;a href="https://cosmin.us/upgrading-vcf-4-3-x-to-vcf-5-step-by-step/"&gt;upgraded your VMware Cloud Foundation (VCF) environment to version 5.x&lt;/a&gt; from an earlier release, you may find yourself unable to update BOM (Bill of Materials) components from the SDDC Manager UI. The &lt;strong&gt;&amp;ldquo;Update Now&amp;rdquo;&lt;/strong&gt; or &lt;strong&gt;&amp;ldquo;Configure Update&amp;rdquo;&lt;/strong&gt; button is greyed out and you see a frustrating error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Update cannot be started now as compatibility file is missing&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This post walks through the symptoms, root cause, and the step-by-step fix based on &lt;a href="https://knowledge.broadcom.com/external/article/396202/unable-to-update-bom-components-from-the.html"&gt;Broadcom KB 396202&lt;/a&gt;.&lt;/p&gt;</description><content:encoded>&lt;p&gt;If you have &lt;a href="https://cosmin.us/upgrading-vcf-4-3-x-to-vcf-5-step-by-step/"&gt;upgraded your VMware Cloud Foundation (VCF) environment to version 5.x&lt;/a&gt; from an earlier release, you may find yourself unable to update BOM (Bill of Materials) components from the SDDC Manager UI. The &lt;strong&gt;&amp;ldquo;Update Now&amp;rdquo;&lt;/strong&gt; or &lt;strong&gt;&amp;ldquo;Configure Update&amp;rdquo;&lt;/strong&gt; button is greyed out and you see a frustrating error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Update cannot be started now as compatibility file is missing&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This post walks through the symptoms, root cause, and the step-by-step fix based on &lt;a href="https://knowledge.broadcom.com/external/article/396202/unable-to-update-bom-components-from-the.html"&gt;Broadcom KB 396202&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="symptoms"&gt;Symptoms&lt;/h3&gt;
&lt;p&gt;You will typically notice one or more of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;Updates&lt;/strong&gt; tab of the relevant Workload Domain (WLD), the &lt;strong&gt;&amp;ldquo;Update Now&amp;rdquo;&lt;/strong&gt; or &lt;strong&gt;&amp;ldquo;Configure Update&amp;rdquo;&lt;/strong&gt; button is greyed out.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&amp;ldquo;Available Updates&amp;rdquo;&lt;/strong&gt; section displays the error: &lt;em&gt;&amp;ldquo;Update cannot be started now as compatibility file is missing&amp;rdquo;&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Attempting to manually download the &lt;code&gt;VmwareCompatibilityData.json&lt;/code&gt; file fails.&lt;/li&gt;
&lt;li&gt;In the SDDC Manager LCM debug log (&lt;code&gt;/var/log/vmware/vcf/lcm/lcm-debug.log&lt;/code&gt;), you see entries similar to:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Recoverable I/O exception (java.net.SocketException) caught when processing request to {s}-&amp;gt;https://storage.googleapis.com:443
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VVS Compatibility Data update failed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;com.vmware.vcf.compatibility.controllers.internal.vvs.exception.VvsException:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The VVS api call to https://vvs.esp.vmware.com/v1/products/bundles/type/vcf-lcm-bundle?format=json failed.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Response: Connection reset
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="root-cause"&gt;Root Cause&lt;/h3&gt;
&lt;p&gt;The compatibility data file &lt;code&gt;VmwareCompatibilityData.json&lt;/code&gt; is missing from the expected path on the SDDC Manager appliance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/nfs/vmware/vcf/nfs-mount/compatibility/VmwareCompatibilityData.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Why is it missing?&lt;/strong&gt; The most common reason is that the SDDC Manager was upgraded from a VCF version prior to 5.0.0.0. The VVS compatibility data directory was introduced in VCF 5.0, so environments that were upgraded (rather than freshly deployed) may never have had this directory created.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="step-by-step-resolution"&gt;Step-by-Step Resolution&lt;/h3&gt;
&lt;h4 id="step-1-take-a-snapshot"&gt;Step 1: Take a Snapshot&lt;/h4&gt;
&lt;p&gt;Before making any changes, take an &lt;strong&gt;offline snapshot&lt;/strong&gt; of the SDDC Manager appliance VM. This gives you a safe rollback point.&lt;/p&gt;
&lt;h4 id="step-2-ssh-into-sddc-manager"&gt;Step 2: SSH Into SDDC Manager&lt;/h4&gt;
&lt;p&gt;Connect via SSH using the &lt;code&gt;vcf&lt;/code&gt; user, then elevate to root:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh vcf@&amp;lt;sddc-manager-fqdn&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;su root
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="step-3-create-the-compatibility-directory"&gt;Step 3: Create the Compatibility Directory&lt;/h4&gt;
&lt;p&gt;The directory likely does not exist. Create it and navigate into it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /nfs/vmware/vcf/nfs-mount/compatibility/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /nfs/vmware/vcf/nfs-mount/compatibility/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="step-4-download-the-compatibility-data-file"&gt;Step 4: Download the Compatibility Data File&lt;/h4&gt;
&lt;p&gt;Run the following &lt;code&gt;curl&lt;/code&gt; command to pull the &lt;code&gt;VmwareCompatibilityData.json&lt;/code&gt; file from Broadcom&amp;rsquo;s VVS endpoint:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --location &lt;span class="s1"&gt;&amp;#39;https://vvs.broadcom.com/v1/products/bundles/type/vcf-lcm-v2-bundle?format=json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;X-Vmw-Esp-ClientId: vcf-lcm&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; VmwareCompatibilityData.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If the SDDC Manager does not have internet access, run the &lt;code&gt;curl&lt;/code&gt; command on a separate Linux machine that can reach &lt;code&gt;vvs.broadcom.com&lt;/code&gt;, then transfer the resulting &lt;code&gt;VmwareCompatibilityData.json&lt;/code&gt; file to the SDDC Manager appliance via SCP or another file transfer method.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="step-5-set-correct-permissions-and-ownership"&gt;Step 5: Set Correct Permissions and Ownership&lt;/h4&gt;
&lt;p&gt;Apply the proper ownership and permissions so the LCM service can read the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chown vcf_lcm:vcf -R /nfs/vmware/vcf/nfs-mount/compatibility
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;755&lt;/span&gt; -R /nfs/vmware/vcf/nfs-mount/compatibility/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="step-6-restart-the-lcm-service"&gt;Step 6: Restart the LCM Service&lt;/h4&gt;
&lt;p&gt;Restart the Lifecycle Manager service for the changes to take effect:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl restart lcm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait a couple of minutes for the service to fully come back up, then refresh the SDDC Manager UI. The &lt;strong&gt;&amp;ldquo;Update Now&amp;rdquo;&lt;/strong&gt; or &lt;strong&gt;&amp;ldquo;Configure Update&amp;rdquo;&lt;/strong&gt; button should no longer be greyed out.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="additional-step-update-depot-urls"&gt;Additional Step: Update Depot URLs&lt;/h3&gt;
&lt;p&gt;If you are also seeing depot-related errors, the download URLs in the LCM configuration may still reference old repository endpoints that require a valid download token. You should update the depot configuration in:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/opt/vmware/vcf/lcm/lcm-app/conf/application-prod.properties
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Broadcom has a dedicated KB for this issue: &lt;a href="https://knowledge.broadcom.com/external/article/389871"&gt;Depot connection has issues - SDDC fails to download updates from online repositories (KB 389871)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On a related note, if compatibility or interoperability checks are blocking upgrades in your lab, I covered a &lt;a href="https://cosmin.us/unstuck-your-vcf-lab-a-script-to-bypass-compatibility-interoperability-checks/"&gt;script to bypass VCF compatibility and interoperability checks&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="quick-reference-all-commands"&gt;Quick Reference: All Commands&lt;/h3&gt;
&lt;p&gt;For convenience, here are all the commands in sequence:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# SSH in and elevate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh vcf@&amp;lt;sddc-manager-fqdn&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;su root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /nfs/vmware/vcf/nfs-mount/compatibility/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /nfs/vmware/vcf/nfs-mount/compatibility/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Download compatibility data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl --location &lt;span class="s1"&gt;&amp;#39;https://vvs.broadcom.com/v1/products/bundles/type/vcf-lcm-v2-bundle?format=json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --header &lt;span class="s1"&gt;&amp;#39;X-Vmw-Esp-ClientId: vcf-lcm&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt; VmwareCompatibilityData.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Fix permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chown vcf_lcm:vcf -R /nfs/vmware/vcf/nfs-mount/compatibility
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;755&lt;/span&gt; -R /nfs/vmware/vcf/nfs-mount/compatibility/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Restart LCM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl restart lcm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="related-resources"&gt;Related Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/396202/unable-to-update-bom-components-from-the.html"&gt;Broadcom KB 396202 - Unable to update BOM components from SDDC Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/389871"&gt;Broadcom KB 389871 - Depot connection issues / Invalid credentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/327186/public-url-list-for-sddc-manager.html"&gt;Public URL list for VCF Products (KB 327186)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://knowledge.broadcom.com/external/article/390098#download_token"&gt;VCF authenticated downloads configuration update instructions (KB 390098)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Scripted Components Cleanup from VCF Operations 9.1: A Step-by-Step Guide</title><link>https://cosmin.us/scripted-components-cleanup-from-vcf-operations-9-1/</link><pubDate>Wed, 03 Jun 2026 10:30:00 +0000</pubDate><dc:creator>Cosmin Trif</dc:creator><guid>https://cosmin.us/scripted-components-cleanup-from-vcf-operations-9-1/</guid><description>&lt;p&gt;If you&amp;rsquo;ve been working with VCF Operations 9.1, you may have noticed that on the &lt;strong&gt;Build&lt;/strong&gt; &amp;gt; &lt;strong&gt;Lifecycle&lt;/strong&gt; &amp;gt; &lt;strong&gt;VCF Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Components&lt;/strong&gt; page, manually-added components such as VCF Operations for Networks, Log Management, Real-Time Metrics or VCF Automation no longer have a &amp;ldquo;Delete&amp;rdquo; option available in the UI.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://cosmin.us/deploying-vcf-operations-9-from-ova/"&gt;VCF Operations 9.0&lt;/a&gt;, this was possible on the &lt;strong&gt;Fleet Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Lifecycle&lt;/strong&gt; &amp;gt; &lt;strong&gt;Components&lt;/strong&gt; page by clicking the three vertical dots next to a component and selecting &lt;strong&gt;Delete&lt;/strong&gt;. That option is gone in 9.1.&lt;/p&gt;</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been working with VCF Operations 9.1, you may have noticed that on the &lt;strong&gt;Build&lt;/strong&gt; &amp;gt; &lt;strong&gt;Lifecycle&lt;/strong&gt; &amp;gt; &lt;strong&gt;VCF Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Components&lt;/strong&gt; page, manually-added components such as VCF Operations for Networks, Log Management, Real-Time Metrics or VCF Automation no longer have a &amp;ldquo;Delete&amp;rdquo; option available in the UI.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://cosmin.us/deploying-vcf-operations-9-from-ova/"&gt;VCF Operations 9.0&lt;/a&gt;, this was possible on the &lt;strong&gt;Fleet Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Lifecycle&lt;/strong&gt; &amp;gt; &lt;strong&gt;Components&lt;/strong&gt; page by clicking the three vertical dots next to a component and selecting &lt;strong&gt;Delete&lt;/strong&gt;. That option is gone in 9.1.&lt;/p&gt;
&lt;p&gt;Broadcom has published &lt;a href="https://knowledge.broadcom.com/external/article/441333"&gt;KB article 441333&lt;/a&gt; with an attached Python script (&lt;code&gt;cleanup_component.py&lt;/code&gt;) for specific failed or stale component scenarios. This is a destructive cleanup tool, not a general-purpose replacement for the product&amp;rsquo;s supported backup, restore, upgrade or uninstall workflows.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before running the cleanup script, make sure the following are in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; installed on the system where you will run the script (can be any system with network access to the Fleet and VCF Management Services components).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network access&lt;/strong&gt; to the &lt;a href="https://cosmin.us/deploying-vcf-fleet-management-9-from-ova-a-step-by-step-guide/"&gt;Fleet LCM appliance&lt;/a&gt; and VCF Services Runtime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Credentials&lt;/strong&gt;: use &lt;code&gt;admin@local&lt;/code&gt; for the VCF Services Runtime username. Enter the password of &lt;code&gt;vmware-system-user&lt;/code&gt;; according to KB 441333, that account and &lt;code&gt;admin@local&lt;/code&gt; have the same password.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FQDN values&lt;/strong&gt;: replace all placeholder FQDNs such as &lt;code&gt;&amp;lt;fleet-lcm-fqdn&amp;gt;&lt;/code&gt; with the actual values. These can be obtained from &lt;strong&gt;VCF Operations UI&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Build&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Lifecycle&lt;/strong&gt; -&amp;gt; &lt;strong&gt;VCF Management&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Components&lt;/strong&gt; (e.g., &lt;code&gt;vsp01.example.com&lt;/code&gt; for &lt;code&gt;&amp;lt;vcf-services-runtime-fqdn&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Before cleanup, verify that usable backups exist for every piece of critical component data that must be retained, including logs and databases. Do not treat this workflow, or a VM snapshot taken outside a product-supported procedure, as a way to restore a deleted component.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="supported-scope-and-safety-restrictions"&gt;Supported Scope and Safety Restrictions&lt;/h2&gt;
&lt;p&gt;Use the script only for a scenario explicitly covered by the current version of KB 441333, such as a duplicate 9.0 component import, an incorrect FQDN that requires a full redeployment or a component that must be removed before a fresh deployment.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;VCF Automation 9.1&lt;/strong&gt;, the restrictions are especially important:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The workflow completely removes VCF Automation from the Fleet.&lt;/li&gt;
&lt;li&gt;Use it only for permanent removal or to prepare for a fresh deployment.&lt;/li&gt;
&lt;li&gt;A fresh deployment performed after this cleanup must not be restored from the removed deployment&amp;rsquo;s backup as part of this workflow. Use Broadcom&amp;rsquo;s separate &lt;strong&gt;Redeploy and Restore VCF Automation&lt;/strong&gt; procedure when restoration is required.&lt;/li&gt;
&lt;li&gt;Do not use this procedure to clean up a VCF Automation upgrade failure. Contact Broadcom Support for that scenario.&lt;/li&gt;
&lt;li&gt;Do not use it to clean up and then import an existing VCF Automation 9.1 system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For imported 9.0 components, read the component-specific note before deleting anything: some operations remove only the Fleet lifecycle record and leave the existing 9.0 deployment intact. A failed upgrade entry can also remain visible after cleanup; KB 441333 states that this entry does not block subsequent upgrade tasks.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="download-and-verify-the-script"&gt;Download and Verify the Script&lt;/h2&gt;
&lt;p&gt;Download &lt;code&gt;cleanup_component.py&lt;/code&gt; from &lt;a href="https://knowledge.broadcom.com/external/article/441333"&gt;KB 441333&lt;/a&gt; (attached at the bottom of the article).&lt;/p&gt;
&lt;p&gt;Verify the SHA256 checksum before running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sha256sum cleanup_component.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected checksum for the script currently attached to KB 441333:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;253bf30d0b33e0c6640aa6cbdf96de41a4a6d75d0265db269b1f44099308ca4c
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Do not run the script if the checksum differs. Download the current attachment again and recheck the KB because Broadcom can replace the attachment and publish a new checksum.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="what-the-script-does"&gt;What the Script Does&lt;/h2&gt;
&lt;p&gt;The LCM component cleanup script enables administrators to manage Day-N deployed components visible in the VCF Operations UI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;List components&lt;/strong&gt;: View all deployed components currently eligible for removal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delete components&lt;/strong&gt;: Remove an eligible component record or deployment according to its component type and version. The effect is not the same for every component, so confirm the selected component ID and the relevant KB section before proceeding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Important notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If a component is running a version older than 9.1, it is removed solely from the Fleet lifecycle. The script does not delete the corresponding infrastructure deployments such as vCenter or VCF Services Runtime.&lt;/li&gt;
&lt;li&gt;VSP refers to VCF Management Services.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="1-ova-components"&gt;1. OVA Components&lt;/h2&gt;
&lt;p&gt;Deleting an OVA-based deployment removes it from Fleet lifecycle and also deletes the associated virtual machines from vCenter.&lt;/p&gt;
&lt;h3 id="list-components-deployed-on-vcenter"&gt;List Components Deployed on vCenter&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py list ova-component --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="delete-component-deployed-on-vcenter"&gt;Delete Component Deployed on vCenter&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py delete ova-component --component-id &amp;lt;ova-component-id&amp;gt; --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local --vcenter-username &amp;lt;vcenter-username&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The script will prompt for the required passwords. Once confirmed, the OVA component will be removed from Fleet lifecycle and its associated VMs deleted from vCenter.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2-vcf-management-services-vsp-components"&gt;2. VCF Management Services (VSP) Components&lt;/h2&gt;
&lt;p&gt;Deleting a VSP-based deployment removes it from Fleet lifecycle and also deletes the associated deployment from VCF Services Runtime.&lt;/p&gt;
&lt;h3 id="list-components-deployed-on-vcf-services-runtime"&gt;List Components Deployed on VCF Services Runtime&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py list vsp-component --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="delete-component-deployed-on-vcf-services-runtime"&gt;Delete Component Deployed on VCF Services Runtime&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py delete vsp-component --component-id &amp;lt;vsp-component-id&amp;gt; --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-vcf-automation"&gt;3. VCF Automation&lt;/h2&gt;
&lt;p&gt;VCF Automation is a multi-component deployment consisting of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VCF Automation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migration Service Engine&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VCF Automation VCF Services Runtime&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; You must remove VCF Automation and the Migration Service Engine &lt;strong&gt;before&lt;/strong&gt; you remove the VCF Automation VCF Services Runtime. Follow the order below.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Destructive operation:&lt;/strong&gt; For VCF Automation 9.1, this sequence completely removes the solution. Continue only for permanent removal or a fresh deployment without restoration. It is not supported for VCF Automation upgrade-failure cleanup. Run the entire VCF Automation 9.1 cleanup sequence in this section as the &lt;strong&gt;root&lt;/strong&gt; user inside the &lt;strong&gt;SDDC Manager&lt;/strong&gt; virtual machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="step-1-remove-vcf-automation-and-migration-service-engine"&gt;Step 1: Remove VCF Automation and Migration Service Engine&lt;/h3&gt;
&lt;h4 id="list-components-deployed-on-vcf-services-runtime-1"&gt;List Components Deployed on VCF Services Runtime&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py list vsp-component --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="delete-component-deployed-on-the-vcf-automation-vcf-services-runtime"&gt;Delete Component Deployed on the VCF Automation VCF Services Runtime&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py delete vsp-component --component-id &amp;lt;vsp-component-id&amp;gt; --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local --vcfa-vcf-services-runtime-fqdn &amp;lt;vcfa-vcf-services-runtime-fqdn&amp;gt; --vcfa-vcf-services-runtime-username &amp;lt;vcfa-vcf-services-runtime-username&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the delete command for both the VCF Automation component and the Migration Service Engine component before proceeding to Step 2.&lt;/p&gt;
&lt;h3 id="step-2-remove-the-vcf-automation-vcf-services-runtime"&gt;Step 2: Remove the VCF Automation VCF Services Runtime&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; Deleting a VCF Services Runtime requires this script to be executed as the &lt;strong&gt;root&lt;/strong&gt; user inside the &lt;strong&gt;SDDC Manager&lt;/strong&gt; virtual machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="list-vcf-services-runtime"&gt;List VCF Services Runtime&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py list vsp-cluster --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="delete-vcf-services-runtime"&gt;Delete VCF Services Runtime&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python cleanup_component.py delete vsp-cluster --component-id &amp;lt;vsp-cluster-id&amp;gt; --fleet-fqdn &amp;lt;fleet-lcm-fqdn&amp;gt; --vcf-services-runtime-fqdn &amp;lt;vcf-services-runtime-fqdn&amp;gt; --vcf-services-runtime-username admin@local --vcenter-username &amp;lt;vcenter-username&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;cleanup_component.py&lt;/code&gt; script is a handy workaround for the missing &amp;ldquo;Delete&amp;rdquo; option in VCF Operations 9.1. The key things to remember:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Back up and verify&lt;/strong&gt; any critical component data before running delete operations; do not assume this cleanup can be reversed with a snapshot or restored deployment.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;OVA components&lt;/strong&gt;, deletion also removes VMs from vCenter.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;VSP components&lt;/strong&gt;, deletion also removes the deployment from VCF Services Runtime.&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;VCF Automation 9.1&lt;/strong&gt;, cleanup means full removal: do not use it for a failed upgrade or a restore, and use a fresh deployment only when the documented scenario permits it.&lt;/li&gt;
&lt;li&gt;Run the entire &lt;strong&gt;VCF Automation 9.1&lt;/strong&gt; cleanup sequence as &lt;strong&gt;root&lt;/strong&gt; inside the SDDC Manager VM. Delete VCF Automation and Migration Service Engine &lt;strong&gt;first&lt;/strong&gt;, then delete the VCF Services Runtime.&lt;/li&gt;
&lt;li&gt;Always verify the script checksum before running it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After removing components, also check Fleet password management for leftover or expired password accounts. I covered that remediation in &lt;a href="https://cosmin.us/fixing-expired-password-sync-in-vcf-9-1-fleet-management/"&gt;Fixing Expired Password Sync in VCF 9.1 Fleet Management&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the official script download and additional details, refer to &lt;a href="https://knowledge.broadcom.com/external/article/441333"&gt;Broadcom KB article 441333&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope this helps!&lt;/p&gt;</content:encoded></item></channel></rss>