PowerVCF v2.0 - Using VMware Cloud Builder with Public APIs

For those that follow my blog posts you will be aware that I’m involved with the development of PowerVCF a collection of PowerShell cmdlets created to expose the Public APIs of VMware Cloud Foundation. Whilst working on PowerVCF v2.0 I started to take a look at the Public APIs for VMware Cloud Builder, I’ve been heavily involved with the development team for a number of years now and knew there were both Public and Private APIs but just never had the time to dig deeper.

First thing to note is that the Public APIs for VMware Cloud Builder are actually documented within the Public APIs for VMware Cloud Foundation here. From within the documentation refer to the section named 2.3. SDDCs (Management Domain), there is support for the following API calls:

  • GET /v1/sddcs - Retrieve all SDDCs
  • POST /v1/sddcs - Create SDDC
  • GET /v1/sddcs/{id} - Retrieve a SDDC
  • PATCH /v1/sddcs/{id} - Retry failed SDDC creation
  • GET /v1/sddcs/validations - Get all SDDC specification validations
  • POST /v1/sddcs/validations - Validate SDDC specification before creation
  • GET /v1/sddcs/validations/{id} - Get SDDC specification validation status by ID
  • DELETE /v1/sddcs/validations/{id} - Cancel SDDC specification validation
  • PATCH /v1/sddcs/validations/{id} - Retry SDDC validation

Based on these APIs, I built a number of new PowerVCF cmdlets as follows:

  • Get-CloudBuilderSDDC
  • Start-CloudBuilderSDDC
  • Restart-CloudBuilderSDDC
  • Get-CloudBuilderSDDCValidation
  • Start-CloudBuilderSDDCValidation
  • Stop-CloudBuilderSDDCValidation
  • Restart-CloudBuilderSDDCValidation

Next I needed to work on building a valid JSON spec to be used both during the validation and deployment phases, sounds like a simple task based on the fact that VMware Cloud Builder already takes the Deployment Parameters Workbook and converts it into a JSON file through the utility called JsonGenerator however not quite so. The biggest challenge here is that in VMware Cloud Foundation 4.0 the User Interface still uses the Private APIs which means there are a number of differences between the JSON elements used for the Private API versus the Public API so just taking and reusing the JSON file was not possible. A couple of examples include:

  • "VLANId" versus "vlanId"
  • "dvsId" versus "dvsName"
  • "niocSpec" versus "niocSpecs"

After walking through and doing a comparison section by section I finally had what I hoped to be a working JSON and was ready to perform end to end testing using the new PowerVCF cmdlets and the JSON spec. For the working JSON sample, see the bottom of this post.

I will now cover the process of using the new PowerVCF cmdlets to drive the deployment of a VMware Cloud Foundation 4.0 Management Domain.

Assumption: You have already installed or imported PowerVCF on your system.

Performing Validations using PowerVCF v2.0

The following procedure demonstrates the process of using PowerVCF to perform the validation of the JSON spec and target environment using VMware Cloud Builder.

Procedure

1. Before performing any operations on VMware Cloud Builder using PowerVCF you must enter the credentials, the PowerVCF cmdlet Connect-CloudBuilder takes these credentials and stores them as a base64 string which is then used for each subsequent cmdlet. Enter the following syntax.

Connect-CloudBuilder -fqdn sfo-cb01.sfo.rainpole.io -username admin -password VMw@re1!

2. Taking a copy of the sample JSON file from the bottom of this post, copy and paste into an editor (I use Notepad++), make changes as they correspond to your environment and save the file. I'm using sfo-managementDomain.json for the purpose of this blog post and saving it to the root of my E: Drive.

3. Next we want trigger the validation process, this is achieved using the Start-CloudBuilderSDDCValidation cmdlet and passing it the json file we created in the previous step. Enter the following syntax.

Start-CloudBuilderSDDCValidation -json E:\sfo-managementDomain.json

Here we can see the output of the Start-CloudBuilderSDDCValidation cmdlet, the task has a unique ID which can be used with the Get-CloudBuilderSDDCValidation cmdlet to get updates on the validation process.

We can also log into the VMware Cloud Builder user interface where we also see the validation workflow in progress.

4. Now using the Get-CloudBuilderSDDCValidation cmdlet and the unique ID shown during the triggering of the validation workflow we can check the status using the following syntax.

Get-CloudBuilderSDDCValidation -id 9f13aac9-3d9c-43f1-b41a-d152d418b4b6

We can see based on the executionStatus the validation has COMPLETED, we can verify this further through the VMware Cloud Builder user interface.

When looking at status of the validation using the VMware Cloud Builder user interface you will see that there are a number of validations performed, each with their own status.

5. We can view the same level of detail using the PowerVCF cmdlet by simply adding ConvertTo-Json to the command as follows:

Get-CloudBuilderSDDCValidation -id 9f13aac9-3d9c-43f1-b41a-d152d418b4b6 | ConvertTo-Json

Once your audit has finished and has the COMPLETED status we can move on to trigger the actual deployment.

Performing Deployment using PowerVCF 2.0

Now we have the json spec and the infrastructure validated we are ready trigger the actual deployment.

Procedure

1. Using the PowerVCF cmdlet Connect-CloudBuilder connect to the VMware Cloud Builder appliance using the following syntax.

Connect-CloudBuilder -fqdn sfo-cb01.sfo.rainpole.io -username admin -password VMw@re1!

2. Using the Start-CloudBuilderSDDC cmdlet and passing it the json file we start the deployment workflow using the following syntax.

Start-CloudBuilderSDDC -json E:\sfo-managementDomain.json

Here we can see the output of the Start-CloudBuilderSDDC cmdlet, the task has a unique ID which can be used with the Get-CloudBuilderSDDC cmdlet to get updates on the validation process.

And again we can see the status of the deployment by logging into the VMware Cloud Builder user interface.

3. Now using the Get-CloudBuilderSDDC cmdlet and the unique ID shown during the trigger of the workflow we can check the status using the following syntax.

Get-CloudBuilderSDDC -id d5b175e1-a966-4845-85c3-43e98e616267

After some time, we can see based on the status the deployment has COMPLETED_WITH_SUCCESS, we can verify this further through the VMware Cloud Builder user interface.

And there you have it, using the new VMware Cloud Builder cmdlets released with PowerVCF 2.0 it's now possible to script the automation of the validation and deployment of a VMware Cloud Foundation 4.0 Management Domain.

Hope you have found this post useful, if you have comments then please feel free to get in touch.

Sample JSON File

{
        "excludedComponents": [ "NSX-V" ],
	"dvSwitchVersion": "7.0.0",
	"skipEsxThumbprintValidation": true,
	"managementPoolName": "sfo-m01-np01",
	"sddcManagerSpec": {
		"secondUserCredentials": {
			"username": "vcf",
			"password": "VMw@re1!"
		},
		"ipAddress": "172.20.11.59",
		"netmask": "255.255.255.0",
		"hostname": "sfo-vcf01",
		"rootUserCredentials": {
			"username": "root",
			"password": "VMw@re1!"
		},
		"restApiCredentials": {
			"username": "admin",
			"password": "VMw@re1!"
		}
	},
	"sddcId": "sfo-m01",
	"ceipEnabled": true,
	"esxLicense": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
	"taskName": "workflowconfig/workflowspec-ems.json",
	"ntpServers": [ "ntp.sfo.rainpole.io" ],
	"dnsSpec": {
		"subdomain": "sfo.rainpole.io",
		"domain": "sfo.rainpole.io",
		"nameserver": "172.20.11.4",
		"secondaryNameserver": "172.20.11.5"
	},
	"networkSpecs": [{
			"subnet": "172.20.11.0/24",
			"vlanId": "3061",
			"mtu": "1500",
			"networkType": "MANAGEMENT",
            "gateway": "172.20.11.1",
            "portGroupKey": "sfo-m01-cl01-vds01-pg-mgmt",
			"association": "sfo-m01-dc01"
		},
		{
			"subnet": "172.20.13.0/24",
			"includeIpAddressRanges": [ {"startIpAddress": "172.20.13.101", "endIpAddress": "172.20.13.104" } ],
			"vlanId": "3063",
			"mtu": "9000",
			"networkType": "VSAN",
            "gateway": "172.20.13.253",
            "portGroupKey": "sfo-m01-cl01-vds01-pg-vsan",
			"association": "sfo-m01-dc01"
		},
		{
			"subnet": "172.20.12.0/24",
			"includeIpAddressRanges": [ {"startIpAddress": "172.20.12.101", "endIpAddress": "172.20.12.104" } ],
			"vlanId": "3062",
			"mtu": "9000",
			"networkType": "VMOTION",
            "gateway": "172.20.12.253",
            "portGroupKey": "sfo-m01-cl01-vds01-pg-vmotion",
			"association": "sfo-m01-dc01"
		},
		{
			"networkType": "UPLINK01",
			"subnet": "172.27.24.0/24",
			"gateway": "172.27.24.253",
			"vlanId": "3284",
			"mtu": "9000",
			"portGroupKey": "sfo-m01-cl01-vds01-pg-uplink01",
			"association": "sfo-m01-dc01"
		},
		{
			"networkType": "UPLINK02",
			"subnet": "172.27.25.0/24",
			"gateway": "172.27.25.253",
			"vlanId": "3285",
			"mtu": "9000",
			"portGroupKey": "sfo-m01-cl01-vds01-pg-uplink02",
			"association": "sfo-m01-dc01"
		},
		{
			"networkType": "REGION_SPECIFIC",
			"subnet": "192.168.31.0/24",
			"gateway": "192.168.31.1",
			"mtu": "9000",
			"vlanId": "0",
			"association": "sfo-m01-dc01"
		},
		{
			"networkType": "X_REGION",
			"subnet": "192.168.11.0/24",
			"gateway": "192.168.11.1",
			"mtu": "9000",
			"vlanId": "0",
			"association": "sfo-m01-dc01"
		},
		{
			"networkType": "NSXT_EDGE_TEP",
			"subnet": "172.20.15.0/24",
			"mtu": "9000",
			"gateway": "172.20.15.253",
			"vlanId": "3065",
			"association": "sfo-m01-dc01"
		}
	],
	"nsxtSpec": {
		"nsxtManagerSize": "medium",
        "nsxtManagers": [
            {
                "hostname": "sfo-m01-nsx01a",
                "ip": "172.20.11.66"
            },
            {
                "hostname": "sfo-m01-nsx01b",
                "ip": "172.20.11.67"
            },
            {
                "hostname": "sfo-m01-nsx01c",
                "ip": "172.20.11.68"
            }
          ],
        "rootNsxtManagerPassword": "VMw@re1!VMw@re1!",
        "nsxtAdminPassword": "VMw@re1!VMw@re1!",
        "nsxtAuditPassword": "VMw@re1!VMw@re1!",
        "rootLoginEnabledForNsxtManager": "true",
        "sshEnabledForNsxtManager": "true",
		"overLayTransportZone": {
			"zoneName": "sfo-m01-tz-overlay01",
            "networkName": "sfo-m01-cl01-nvds01-pg-edge"
		},
		"vlanTransportZone": {
			"zoneName": "sfo-m01-tz-vlan01",
            "networkName": "netName-vlan"
		},
		"vip": "172.20.11.65",
		"vipFqdn": "sfo-m01-nsx01",
		"nsxtLicense": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
		"transportVlanId": 3064,
		"nsxtEdgeSpec": {
			"edgeClusterName": "sfo-m01-ec01",
            "edgeRootPassword": "VMw@re1!VMw@re1!",
            "edgeAdminPassword": "VMw@re1!VMw@re1!",
            "edgeAuditPassword": "VMw@re1!VMw@re1!",
			"edgeFormFactor": "MEDIUM",
			"tier0ServicesHighAvailability": "ACTIVE_ACTIVE",
			"asn": 65003,
			"edgeServicesSpecs": {
				"tier0GatewayName": "sfo-m01-ec01-t0-gw01",
				"tier1GatewayName": "sfo-m01-ec01-t1-gw01"
			},
			"edgeNodeSpecs": [{
					"edgeNodeName": "sfo-m01-en01",
					"edgeNodeHostname": "sfo-m01-en01.sfo.rainpole.io",
					"managementCidr": "172.20.11.69/24",
					"edgeVtep1Cidr": "172.20.15.2/24",
					"edgeVtep2Cidr": "172.20.15.3/24",
					"interfaces": [{
							"name": "uplink-edge1-tor1",
							"interfaceCidr": "172.27.24.2/24"
						},
						{
							"name": "uplink-edge1-tor2",
							"interfaceCidr": "172.27.25.3/24"
						}
					]
				},
				{
					"edgeNodeName": "sfo-m01-en02",
					"edgeNodeHostname": "sfo-m01-en02.sfo.rainpole.io",
					"managementCidr": "172.20.11.70/24",
					"edgeVtep1Cidr": "172.20.15.4/24",
					"edgeVtep2Cidr": "172.20.15.5/24",
					"interfaces": [{
							"name": "uplink-edge2-tor1",
							"interfaceCidr": "172.27.24.3/24"
						},
						{
							"name": "uplink-edge2-tor2",
							"interfaceCidr": "172.27.25.2/24"
						}
					]
				}
			],
			"bgpNeighbours": [{
					"neighbourIp": "172.27.24.1",
					"autonomousSystem": 65001,
					"password": "VMw@re1!"
				},
				{
					"neighbourIp": "172.27.25.1",
					"autonomousSystem": 65001,
					"password": "VMw@re1!"
				}
			]
		},
		"logicalSegments": [{
				"name": "sfo-m01-seg01",
				"networkType": "REGION_SPECIFIC"
			},
			{
				"name": "xreg-m01-seg01",
				"networkType": "X_REGION"
			}
		]
	},
	"vsanSpec": {
		"vsanName": "vsan-1",
        "licenseFile": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
        "vsanDedup": "false",
		"datastoreName": "sfo-m01-cl01-ds-vsan01"
	},
	"dvsSpecs": [{
		"mtu": 9000,
		"niocSpecs": [{
				"trafficType": "VSAN",
				"value": "HIGH"
			},
			{
				"trafficType": "VMOTION",
				"value": "LOW"
			},
			{
				"trafficType": "VDP",
				"value": "LOW"
			},
			{
				"trafficType": "VIRTUALMACHINE",
				"value": "HIGH"
			},
			{
				"trafficType": "MANAGEMENT",
				"value": "NORMAL"
			},
			{
				"trafficType": "NFS",
				"value": "LOW"
			},
			{
				"trafficType": "HBR",
				"value": "LOW"
			},
			{
				"trafficType": "FAULTTOLERANCE",
				"value": "LOW"
			},
			{
				"trafficType": "ISCSI",
				"value": "LOW"
			}
		],
		"dvsName": "sfo-m01-cl01-vds01",
		"vmnics": [
			"vmnic0",
			"vmnic1"
		],
		"networks": [
			"MANAGEMENT",
			"VSAN",
			"VMOTION",
			"UPLINK01",
            "UPLINK02",
            "NSXT_EDGE_TEP"
		]
	}],
	"clusterSpec": {
        "vmFolders": {
            "MANAGEMENT": "sfo-m01-fd-mgmt",
            "NETWORKING": "sfo-m01-fd-nsx",
            "EDGENODES": "sfo-m01-fd-edge"
        },
		"clusterName": "sfo-m01-cl01",
		"clusterEvcMode": "",
		"resourcePoolSpecs": [{
				"cpuSharesLevel": "high",
				"cpuSharesValue": 0,
				"name": "sfo-m01-cl01-rp-sddc-mgmt",
				"memorySharesValue": 0,
				"cpuReservationPercentage": 0,
				"memoryLimit": -1,
				"memoryReservationPercentage": 0,
				"cpuReservationExpandable": true,
				"memoryReservationExpandable": true,
				"memorySharesLevel": "normal",
				"cpuLimit": -1,
				"type": "management"
			},
			{
				"cpuSharesLevel": "high",
				"cpuSharesValue": 0,
				"name": "sfo-m01-cl01-rp-sddc-edge",
				"memorySharesValue": 0,
				"cpuReservationPercentage": 0,
				"memoryLimit": -1,
				"memoryReservationPercentage": 0,
				"cpuReservationExpandable": true,
				"memoryReservationExpandable": true,
				"memorySharesLevel": "normal",
				"cpuLimit": -1,
				"type": "network"
			},
			{
				"cpuSharesLevel": "normal",
				"cpuSharesValue": 0,
				"name": "sfo-m01-cl01-rp-user-edge",
				"memorySharesValue": 0,
				"cpuReservationPercentage": 0,
				"memoryLimit": -1,
				"memoryReservationPercentage": 0,
				"cpuReservationExpandable": true,
				"memoryReservationExpandable": true,
				"memorySharesLevel": "normal",
				"cpuLimit": -1,
				"type": "compute"
			},
			{
				"name": "sfo-m01-cl01-rp-user-vm",
				"type": "compute",
				"cpuReservationPercentage": 0,
				"cpuLimit": -1,
				"cpuReservationExpandable": true,
				"cpuSharesLevel": "normal",
				"cpuSharesValue": 0,
				"memoryReservationPercentage": 0,
				"memoryLimit": -1,
				"memoryReservationExpandable": true,
				"memorySharesLevel": "normal",
				"memorySharesValue": 0
			}
		]
	},
	"pscSpecs": [{
		"pscId": "psc-1",
		"vcenterId": "vcenter-1",
		"pscSsoSpec": {
			"ssoSiteName": "sfo-m01",
			"ssoDomainPassword": "VMw@re1!",
			"ssoDomain": "vsphere.local",
			"isJoinSsoDomain": false
		},
		"adminUserSsoPassword": "VMw@re1!"
	}],
	"vcenterSpec": {
		"vcenterIp": "172.20.11.62",
		"vcenterHostname": "sfo-m01-vc01",
		"vcenterId": "vcenter-1",
		"licenseFile": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
		"rootVcenterPassword": "VMw@re1!",
		"vmSize": "small"
	},
	"hostSpecs": [{
			"credentials": {
				"username": "root",
				"password": "VMw@re1!"
			},
			"ipAddressPrivate": {
				"subnet": "255.255.255.0",
				"cidr": "172.20.11.0/24",
				"ipAddress": "172.20.11.101",
				"gateway": "172.20.11.1"
			},
			"hostname": "sfo01-m01-esx01",
			"vSwitch": "vSwitch0",
			"serverId": "host-0",
			"association": "sfo-m01-dc01"
		},
		{
			"credentials": {
				"username": "root",
				"password": "VMw@re1!"
			},
			"ipAddressPrivate": {
				"subnet": "255.255.255.0",
				"cidr": "172.20.11.0/24",
				"ipAddress": "172.20.11.102",
				"gateway": "172.20.11.1"
			},
			"hostname": "sfo01-m01-esx02",
			"vSwitch": "vSwitch0",
			"serverId": "host-1",
			"association": "sfo-m01-dc01"
		},
		{
			"credentials": {
				"username": "root",
				"password": "VMw@re1!"
			},
			"ipAddressPrivate": {
				"subnet": "255.255.255.0",
				"cidr": "172.20.11.0/24",
				"ipAddress": "172.20.11.103",
				"gateway": "172.20.11.1"
			},
			"hostname": "sfo01-m01-esx03",
			"vSwitch": "vSwitch0",
			"serverId": "host-2",
			"association": "sfo-m01-dc01"
		},
		{
			"credentials": {
				"username": "root",
				"password": "VMw@re1!"
			},
			"ipAddressPrivate": {
				"subnet": "255.255.255.0",
				"cidr": "172.20.11.0/24",
				"ipAddress": "172.20.11.104",
				"gateway": "172.20.11.1"
			},
			"hostname": "sfo01-m01-esx04",
			"vSwitch": "vSwitch0",
			"serverId": "host-3",
			"association": "sfo-m01-dc01"
		}
	]
}

If you would like to learn more about VMware Cloud Foundation or PowerVCF, check out these links:

Posts in this Series