The main issue this API will solve is preserving the UUID of the vApp once moved.
Today, move and clone vApp create an entirely new vApp at the target, changing the UUID of the vApp.
vCAV and other monitoring tools rely on the vApp UUID for tracking purposes. This normally wouldn't be an issue for such tools, but since they will be moving from one PVDC to another for NSX migration, the solution needs to preserve UUIDs of vApps. The scope of the move is contained within one vCenter, at least across clusters.
How-to-Use
The API is under /api/vdc/{vdcId}/action/moveVApp
The vdcId is of the target VDC where the vApp should be moved.
The payload is of type MoveVAppParams
The only vApp Section type allowed in the NetworkConfigSection which is used to define the form of any vApp Networks desired at the target VDC in the process of moving
Every VM in the vApp must be accounted for in the payload as a SourcedCompositionItem, or a BadRequestException will be thrown.
Below is an example of a payload moving a vApp with the following config:
vApp (ID: ec6e2254-63b1-49f3-9c53-2f63e071509f) has two VMs (ID: 7b5dd00d-0f93-47a5-b29c-dbc4815bd377 and b757f667-148c-4a53-b428-1179bf77a6e5)
Each storage profile specified for the VMs is the target VDC's "Any" profile
Specifying a new vApp Network called Cluster1-Ext that is attached to an OrgVDC Network (specified as ParentNetwork in the payload) at the target VDC
Each VM is connected to Cluster1-Ext
POST https://vcd-lab.local/api/vdc/ec6e2254-63b1-49f3-9c53-2f63e071509f/action/moveVApp
Content-Type:application/vnd.vmware.vcloud.MoveVAppParams+xml
Accept:application/*+xml;version=36.0
<?xml version="1.0"?>
<root:MoveVAppParams xmlns:root="http://www.vmware.com/vcloud/v1.5" xmlns:ns7="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ns8="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:ns9="http://www.vmware.com/schema/ovf">
<root:Source href="https://vcd-lab.local/api/vApp/vapp-ec6e2254-63b1-49f3-9c53-2f63e071509f"/>
<root:NetworkConfigSection>
<ns7:Info>The configuration parameters for logical networks</ns7:Info>
<root:NetworkConfig networkName="Cluster1-Ext">
<root:Description/>
<root:Configuration>
<root:IpScopes>
<root:IpScope>
<root:IsInherited>true</root:IsInherited>
<root:Gateway>1.1.1.1</root:Gateway>
<root:SubnetPrefixLength>24</root:SubnetPrefixLength>
<root:Dns1/>
<root:Dns2/>
<root:DnsSuffix/>
<root:IsEnabled>true</root:IsEnabled>
</root:IpScope>
</root:IpScopes>
<root:ParentNetwork href="https://vcd-lab.local/api/admin/network/3f0a78d7-a843-4493-aabf-dd752ffee223" id="urn:vcloud:network:3f0a78d7-a843-4493-aabf-dd752ffee223" name="Cluster1-Ext"/>
<root:FenceMode>bridged</root:FenceMode>
<root:AdvancedNetworkingEnabled>true</root:AdvancedNetworkingEnabled>
</root:Configuration>
<root:IsDeployed>false</root:IsDeployed>
</root:NetworkConfig>
</root:NetworkConfigSection>
<root:SourcedItem>
<root:Source href="https://vcd-lab.local/api/vApp/vm-7b5dd00d-0f93-47a5-b29c-dbc4815bd377"/>
<root:InstantiationParams>
<root:NetworkConnectionSection>
<ns7:Info>Network Connection Section</ns7:Info>
<root:PrimaryNetworkConnectionIndex>0</root:PrimaryNetworkConnectionIndex>
<root:NetworkConnection network="Cluster1-Ext">
<root:NetworkConnectionIndex>0</root:NetworkConnectionIndex>
<root:IsConnected>true</root:IsConnected>
<root:MACAddress>00:50:56:01:00:00</root:MACAddress>
<root:IpAddressAllocationMode>POOL</root:IpAddressAllocationMode>
<root:NetworkAdapterType>FLEXIBLE</root:NetworkAdapterType>
</root:NetworkConnection>
</root:NetworkConnectionSection>
</root:InstantiationParams>
<root:StorageProfile href="https://vcd-lab.local/api/vdcStorageProfile/7e662275-3f73-4b42-b05d-fd1df0ba9fc6"/>
</root:SourcedItem>
<root:SourcedItem>
<root:Source href="https://vcd-lab.local/api/vApp/vm-b757f667-148c-4a53-b428-1179bf77a6e5"/>
<root:InstantiationParams>
<root:NetworkConnectionSection>
<ns7:Info>Network Connection Section</ns7:Info>
<root:PrimaryNetworkConnectionIndex>0</root:PrimaryNetworkConnectionIndex>
<root:NetworkConnection network="Cluster1-Ext">
<root:NetworkConnectionIndex>0</root:NetworkConnectionIndex>
<root:IsConnected>true</root:IsConnected>
<root:MACAddress>00:50:56:01:00:01</root:MACAddress>
<root:IpAddressAllocationMode>POOL</root:IpAddressAllocationMode>
<root:NetworkAdapterType>FLEXIBLE</root:NetworkAdapterType>
</root:NetworkConnection>
</root:NetworkConnectionSection>
</root:InstantiationParams>
<root:StorageProfile href="https://vcd-lab.local/api/vdcStorageProfile/7e662275-3f73-4b42-b05d-fd1df0ba9fc6"/>
</root:SourcedItem>
</root:MoveVAppParams>
There are also cases where a VM's disk span multiple storage policies (if overrideVmDefault is true for the disk). Providing a payload like the one above will fail because the disks' storage profiles will be of the source VDC.
To properly invoke Move vApp, a Disk Section must be provided in the SourcedItem that specifies the storage profiles of each disk (profiles must be of the target VDC).
An easy way to fetch the body is to do a GET on either the VM in question or vApp containing the VM and copying the DiskSection of the VmSpecSection (which is a further subsection of InstantiationParams), only modifying the storage profiles and setting Modified = true in VmSpecSection's attribute.
Below is an example of such a payload
POST https://vcd-lab.local/api/vdc/ec6e2254-63b1-49f3-9c53-2f63e071509f/action/moveVApp
Content-Type:application/vnd.vmware.vcloud.MoveVAppParams+xml
Accept:application/*+xml;version=36.0
<?xml version="1.0"?>
<root:MoveVAppParams xmlns:root="http://www.vmware.com/vcloud/v1.5" xmlns:ns7="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ns8="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:ns9="http://www.vmware.com/schema/ovf">
<root:Source href="https://vcd-lab.local/api/vApp/vapp-82a999b2-295f-4f63-843d-74a4732d82e1"/>
<root:NetworkConfigSection>
<ns7:Info>The configuration parameters for logical networks</ns7:Info>
<root:NetworkConfig networkName="Cluster1-Ext">
<root:Description/>
<root:Configuration>
<root:IpScopes>
<root:IpScope>
<root:IsInherited>true</root:IsInherited>
<root:Gateway>1.1.1.1</root:Gateway>
<root:SubnetPrefixLength>24</root:SubnetPrefixLength>
<root:Dns1/>
<root:Dns2/>
<root:DnsSuffix/>
<root:IsEnabled>true</root:IsEnabled>
</root:IpScope>
</root:IpScopes>
<root:ParentNetwork href="https://vcd-lab.local/api/admin/network/3f0a78d7-a843-4493-aabf-dd752ffee223" id="urn:vcloud:network:3f0a78d7-a843-4493-aabf-dd752ffee223" name="Cluster1-Ext"/>
<root:FenceMode>bridged</root:FenceMode>
<root:AdvancedNetworkingEnabled>true</root:AdvancedNetworkingEnabled>
</root:Configuration>
<root:IsDeployed>false</root:IsDeployed>
</root:NetworkConfig>
</root:NetworkConfigSection>
<root:SourcedItem>
<root:Source href="https://vcd-lab.local/api/vApp/vm-5661a002-04a6-47d5-bc32-7d506210376e"/>
<root:InstantiationParams>
<root:VmSpecSection Modified="true">
<ns7:Info/>
<root:DiskSection>
<root:DiskSettings>
<root:DiskId>3001</root:DiskId>
<root:SizeMb>4</root:SizeMb>
<root:UnitNumber>1</root:UnitNumber>
<root:BusNumber>0</root:BusNumber>
<root:AdapterType>1</root:AdapterType>
<root:ThinProvisioned>false</root:ThinProvisioned>
<root:StorageProfile href="https://vcd-lab.local/api/vdcStorageProfile/7e662275-3f73-4b42-b05d-fd1df0ba9fc6" id="urn:vcloud:vdcstorageProfile:7e662275-3f73-4b42-b05d-fd1df0ba9fc6" name="*" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>
<root:overrideVmDefault>true</root:overrideVmDefault>
<root:iops>0</root:iops>
<root:VirtualQuantityUnit>byte</root:VirtualQuantityUnit>
<root:resizable>true</root:resizable>
<root:encrypted>false</root:encrypted>
</root:DiskSettings>
<root:DiskSettings>
<root:DiskId>3002</root:DiskId>
<root:SizeMb>4</root:SizeMb>
<root:UnitNumber>0</root:UnitNumber>
<root:BusNumber>1</root:BusNumber>
<root:AdapterType>1</root:AdapterType>
<root:ThinProvisioned>false</root:ThinProvisioned>
<root:StorageProfile href="https://vcd-lab.local/api/vdcStorageProfile/7e662275-3f73-4b42-b05d-fd1df0ba9fc6" id="urn:vcloud:vdcstorageProfile:7e662275-3f73-4b42-b05d-fd1df0ba9fc6" name="*" type="application/vnd.vmware.vcloud.vdcStorageProfile+xml"/>
<root:overrideVmDefault>true</root:overrideVmDefault>
<root:iops>0</root:iops>
<root:VirtualQuantityUnit>byte</root:VirtualQuantityUnit>
<root:resizable>true</root:resizable>
<root:encrypted>false</root:encrypted>
</root:DiskSettings>
</root:DiskSection>
<root:HardwareVersion href="https://vcd-lab.local/api/vdc/c85266ae-b7f0-4a6e-86c8-44acfcd89378/hwv/vmx-09" type="application/vnd.vmware.vcloud.virtualHardwareVersion+xml">vmx-09</root:HardwareVersion>
</root:VmSpecSection>
</root:InstantiationParams>
<root:StorageProfile href="https://vcd-lab.local/api/vdcStorageProfile/7e662275-3f73-4b42-b05d-fd1df0ba9fc6"/>
</root:SourcedItem>
</root:MoveVAppParams>
That's it.