Updated function to support Cloud Motion & other HCX Migrations

This commit is contained in:
William Lam
2018-09-24 14:17:39 -07:00
parent 8402e69993
commit ea4ab5f61d
2 changed files with 407 additions and 4 deletions

View File

@@ -12,7 +12,7 @@
RootModule = 'VMware.HCX.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
ModuleVersion = '1.0.1'
# Supported PSEditions
# CompatiblePSEditions = @()
@@ -36,7 +36,7 @@ Description = 'PowerShell Module for Managing Hybrid Cloud Extension (HCX) on VM
PowerShellVersion = '6.0'
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'Connect-HcxServer', 'Get-HcxCloudConfig', 'Connect-HcxVAMI', 'Get-HcxVAMIVCConfig'
FunctionsToExport = 'Connect-HcxServer', 'Get-HcxCloudConfig', 'Get-HcxEndpoint', 'New-HcxMigration', 'Get-HcxMigration', 'Connect-HcxVAMI', 'Get-HcxVCConfig'
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()

View File

@@ -94,6 +94,409 @@ Function Get-HcxCloudConfig {
}
}
Function Get-HcxEndpoint {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/24/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
List all HCX endpoints (onPrem and Cloud)
.DESCRIPTION
This cmdlet lists all HCX endpoints (onPrem and Cloud)
.EXAMPLE
Get-HcxEndpoint -cloudVCConnection $cloudVCConnection
#>
Param (
[Parameter(Mandatory=$true)]$cloudVCConnection
)
If (-Not $global:hcxConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxManager " } Else {
#Cloud HCX Manager
$cloudHCXConnectionURL = $global:hcxConnection.Server + "/cloudConfigs"
if($PSVersionTable.PSEdition -eq "Core") {
$cloudRequests = Invoke-WebRequest -Uri $cloudHCXConnectionURL -Method GET -Headers $global:hcxConnection.headers -UseBasicParsing -SkipCertificateCheck
} else {
$cloudRequests = Invoke-WebRequest -Uri $cloudHCXConnectionURL -Method GET -Headers $global:hcxConnection.headers -UseBasicParsing
}
$cloudData = ($cloudRequests.Content | ConvertFrom-Json).data.items[0]
$hcxInventoryUrl = $global:hcxConnection.Server + "/service/inventory/resourcecontainer/list"
$payload = @{
"cloud" = @{
"local"="true";
"remote"="true";
}
}
$body = $payload | ConvertTo-Json
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $hcxInventoryUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $hcxInventoryUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing
}
if($requests.StatusCode -eq 200) {
$items = ($requests.Content | ConvertFrom-Json).data.items
$results = @()
foreach ($item in $items) {
$tmp = [pscustomobject] @{
SourceResourceName = $item.resourceName;
SourceResourceType = $item.resourceType;
SourceResourceId = $item.resourceId;
SourceEndpointName = $item.endpoint.name;
SourceEndpointType = "VC"
SourceEndpointId = $item.endpoint.endpointId;
RemoteResourceName = $cloudVCConnection.name;
RemoteResourceType = "VC"
RemoteResourceId = $cloudVCConnection.InstanceUuid
RemoteEndpointName = $cloudData.cloudName;
RemoteEndpointType = $cloudData.cloudType;
RemoteEndpointId = $cloudData.endpointId;
}
$results+=$tmp
}
return $results
} else {
Write-Error "Failed to list HCX Connection Resources"
}
}
}
Function New-HcxMigration {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/24/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Initiate a "Bulk" migrations supporting Cold, vMotion, VR or new Cloud Motion
.DESCRIPTION
This cmdlet initiates a "Bulk" migrations supporting Cold, vMotion, VR or new Cloud Motionn
.EXAMPLE
Validate Migration request only
New-HcxMigration -onPremVCConnection $onPremVC -cloudVCConnection $cloudVC `
-MigrationType bulkVMotion `
-VMs @("SJC-CNA-34","SJC-CNA-35","SJC-CNA-36") `
-NetworkMappings @{"SJC-CORP-WORKLOADS"="sddc-cgw-network-1";"SJC-CORP-INTERNAL-1"="sddc-cgw-network-2";"SJC-CORP-INTERNAL-2"="sddc-cgw-network-3"} `
-StartTime "Sep 24 2018 1:30 PM" `
-EndTime "Sep 24 2018 2:30 PM"
.EXAMPLE
Start Migration request
New-HcxMigration -onPremVCConnection $onPremVC -cloudVCConnection $cloudVC `
-MigrationType bulkVMotion `
-VMs @("SJC-CNA-34","SJC-CNA-35","SJC-CNA-36") `
-NetworkMappings @{"SJC-CORP-WORKLOADS"="sddc-cgw-network-1";"SJC-CORP-INTERNAL-1"="sddc-cgw-network-2";"SJC-CORP-INTERNAL-2"="sddc-cgw-network-3"} `
-StartTime "Sep 24 2018 1:30 PM" `
-EndTime "Sep 24 2018 2:30 PM" `
-MigrationType bulkVMotion
#>
Param (
[Parameter(Mandatory=$true)][String[]]$VMs,
[Parameter(Mandatory=$true)][Hashtable]$NetworkMappings,
[Parameter(Mandatory=$true)]$onPremVCConnection,
[Parameter(Mandatory=$true)]$cloudVCConnection,
[Parameter(Mandatory=$true)][String]$StartTime,
[Parameter(Mandatory=$true)][String]$EndTime,
[Parameter(Mandatory=$true)][ValidateSet("Cold","vMotion","VR","bulkVMotion")][String]$MigrationType,
[Parameter(Mandatory=$false)]$ValidateOnly=$true
)
If (-Not $global:hcxConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxManager " } Else {
$hcxEndpointInfo = Get-HcxEndpoint -cloudVCConnection $cloudVCConnection
$inputArray = @()
foreach ($vm in $VMs) {
$vmView = Get-View -Server $onPremVCConnection -ViewType VirtualMachine -Filter @{"name"=$vm}
$cloudResourcePoolName = "Compute-ResourcePool"
$cloudFolderName = "Workloads"
$cloudDatastoreName = "WorkloadDatastore"
$cloudDatacenterName = "SDDC-Datacenter"
$cloudResourcePool = (Get-ResourcePool -Server $cloudVCConnection -Name $cloudResourcePoolName).ExtensionData
$cloudFolder = (Get-Folder -Server $cloudVCConnection -Name $cloudFolderName).ExtensionData
$cloudDatastore = (Get-Datastore -Server $cloudVCConnection -Name $cloudDatastoreName).ExtensionData
$cloudDatacenter = (Get-Datacenter -Server $cloudVCConnection -Name $cloudDatacenterName).ExtensionData
$placementArray = @()
$placement = @{
"containerType"="folder";
"containerId"=$cloudFolder.MoRef.Value;
"containerName"=$cloudFolderName;
}
$placementArray+=$placement
$placement = @{
"containerType"="resourcePool";
"containerId"=$cloudResourcePool.MoRef.Value;
"containerName"=$cloudResourcePoolName;
}
$placementArray+=$placement
$placement = @{
"containerType"="dataCenter";
"containerId"=$cloudDatacenter.MoRef.Value;
"containerName"=$cloudDatacenterName;
}
$placementArray+=$placement
$networkArray = @()
$vmNetworks = $vmView.Network
foreach ($vmNetwork in $vmNetworks) {
if($vmNetwork.Type -eq "Network") {
$sourceNetworkType = "VirtualNetwork"
} else { $sourceNetworkType = $vmNetwork.Type }
$sourceNetworkRef = New-Object VMware.Vim.ManagedObjectReference
$sourceNetworkRef.Type = $vmNetwork.Type
$sourceNetworkRef.Value = $vmNetwork.Value
$sourceNetwork = Get-View -Server $onPremVCConnection $sourceNetworkRef
$sourceNetworkName = $sourceNetwork.Name
$destNetworkName = $NetworkMappings[$sourceNetworkName]
$destNetwork = Get-VDPortGroup -Server $cloudVCConnection -Name $destNetworkName
if($destNetwork.Id -match "DistributedVirtualPortgroup") {
$destNetworkType = "DistributedVirtualPortgroup"
$destNetworkId = ($destNetwork.Id).Replace("DistributedVirtualPortgroup-","")
} else {
$destNetworkType = "Network"
$destNetworkId = ($destNetwork.Id).Replace("Network-","")
}
$tmp = @{
"srcNetworkType" = $sourceNetworkType;
"srcNetworkValue" = $vmNetwork.Value;
"srcNetworkHref" = $vmNetwork.Value;
"srcNetworkName" = $sourceNetworkName;
"destNetworkType" = $destNetworkType;
"destNetworkValue" = $destNetworkId;
"destNetworkHref" = $destNetworkId;
"destNetworkName" = $destNetworkName;
}
$networkArray+=$tmp
}
$input = @{
"input" = @{
"migrationType"=$MigrationType;
"entityDetails" = @{
"entityId"=$vmView.MoRef.Value;
"entityName"=$vm;
}
"source" = @{
"endpointType"=$hcxEndpointInfo.SourceEndpointType;
"endpointId"=$hcxEndpointInfo.SourceEndpointId;
"endpointName"=$hcxEndpointInfo.SourceEndpointName;
"resourceType"=$hcxEndpointInfo.SourceResourceType;
"resourceId"=$hcxEndpointInfo.SourceResourceId;
"resourceName"=$hcxEndpointInfo.SourceResourceName;
}
"destination" = @{
"endpointType"=$hcxEndpointInfo.RemoteEndpointType;
"endpointId"=$hcxEndpointInfo.RemoteEndpointId;
"endpointName"=$hcxEndpointInfo.RemoteEndpointName;
"resourceType"=$hcxEndpointInfo.RemoteResourceType;
"resourceId"=$hcxEndpointInfo.RemoteResourceId;
"resourceName"=$hcxEndpointInfo.RemoteResourceName;
}
"placement" = $placementArray
"storage" = @{
"datastoreId"=$cloudDatastore.Moref.Value;
"datastoreName"=$cloudDatastoreName;
"diskProvisionType"="thin";
}
"networks" = @{
"retainMac" = $true;
"targetNetworks" = $networkArray;
}
"decisionRules" = @{
"removeSnapshots"=$true;
"removeISOs"=$true;
"forcePowerOffVm"=$false;
"upgradeHardware"=$false;
"upgradeVMTools"=$false;
}
"schedule" = @{}
}
}
$inputArray+=$input
}
$spec = @{
"migrations"=$inputArray
}
$body = $spec | ConvertTo-Json -Depth 20
Write-Verbose -Message "Pre-Validation JSON Spec: $body"
$hcxMigrationValiateUrl = $global:hcxConnection.Server+ "/migrations?action=validate"
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $hcxMigrationValiateUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json" -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $hcxMigrationValiateUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json"
}
if($requests.StatusCode -eq 200) {
$validationErrors = ($requests.Content|ConvertFrom-Json).migrations.validationInfo.validationResult.errors
if($validationErrors -ne $null) {
Write-Host -Foreground Red "`nThere were validation errors found for this HCX Migration Spec ..."
foreach ($message in $validationErrors) {
Write-Host -Foreground Yellow "`t" $message.message
}
} else {
Write-Host -Foreground Green "`nHCX Pre-Migration Spec successfully validated"
if($ValidateOnly -eq $false) {
try {
$startDateTime = $StartTime | Get-Date
} catch {
Write-Host -Foreground Red "Invalid input for -StartTime, please check for typos"
exit
}
try {
$endDateTime = $EndTime | Get-Date
} catch {
Write-Host -Foreground Red "Invalid input for -EndTime, please check for typos"
exit
}
$offset = (Get-TimeZone).GetUtcOffset($startDateTime).TotalMinutes
$offset = [int]($offSet.toString().replace("-",""))
$schedule = @{
scheduledFailover = $true;
startYear = $startDateTime.Year;
startMonth = $startDateTime.Month;
startDay = $startDateTime.Day;
startHour = $startDateTime | Get-Date -UFormat %H;
startMinute = $startDateTime | Get-Date -UFormat %M;
endYear = $endDateTime.Year;
endMonth = $endDateTime.Month;
endDay = $endDateTime.Day;
endHour = $endDateTime | Get-Date -UFormat %H;
endMinute = $endDateTime | Get-Date -UFormat %M;
timezoneOffset = $offset;
}
foreach ($migration in $spec.migrations) {
$migration.input.schedule = $schedule
}
$body = $spec | ConvertTo-Json -Depth 8
Write-Verbose -Message "Validated JSON Spec: $body"
$hcxMigrationStartUrl = $global:hcxConnection.Server+ "/migrations?action=start"
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $hcxMigrationStartUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json" -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $hcxMigrationStartUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json"
}
if($requests.StatusCode -eq 200) {
$migrationIds = ($requests.Content | ConvertFrom-Json).migrations.migrationId
Write-Host -ForegroundColor Green "Starting HCX Migration ..."
foreach ($migrationId in $migrationIds) {
Write-Host -ForegroundColor Green "`tMigrationID: $migrationId"
}
} else {
Write-Error "Failed to start HCX Migration"
}
}
}
} else {
Write-Error "Failed to validate HCX Migration spec"
}
}
}
Function Get-HcxMigration {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/24/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
List all HCX Migrations that are in-progress, have completed or failed
.DESCRIPTION
This cmdlet lists ist all HCX Migrations that are in-progress, have completed or failed
.EXAMPLE
List all HCX Migrations
Get-HcxMigration
.EXAMPLE
List all running HCX Migrations
Get-HcxMigration -RunningMigrations
.EXAMPLE
List all HCX Migrations
Get-HcxMigration -MigrationId <MigrationID>
#>
Param (
[Parameter(Mandatory=$false)][String]$MigrationId,
[Switch]$RunningMigrations
)
If (-Not $global:hcxConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxManager " } Else {
$spec = @{}
$body = $spec | ConvertTo-Json
$hcxQueryUrl = $global:hcxConnection.Server + "/migrations?action=query"
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $hcxQueryUrl -Method POST -body $body -Headers $global:hcxConnection.headers -UseBasicParsing -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $hcxQueryUrl -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing
}
$migrations = ($requests.content | ConvertFrom-Json).rows
if($PSBoundParameters.ContainsKey("MigrationId")){
$migrations = $migrations | where { $_.migrationId -eq $MigrationId }
}
if($RunningMigrations){
$migrations = $migrations | where { $_.jobInfo.state -ne "MIGRATE_FAILED" -and $_.jobInfo.state -ne "MIGRATE_CANCELED"-and $_.jobInfo.state -ne "MIGRATED" }
}
$results = @()
foreach ($migration in $migrations) {
$tmp = [pscustomobject] @{
ID = $migration.migrationId;
VM = $migration.migrationInfo.entityDetails.entityName;
State = $migration.jobInfo.state;
Progress = ($migration.migrationInfo.progressDetails.progressPercentage).toString() + " %";
DataCopied = ([math]::round($migration.migrationInfo.progressDetails.diskCopyBytes/1Gb, 2)).toString() + " GB";
Message = $migration.migrationInfo.message;
InitiatedBy = $migration.jobInfo.username;
CreateDate = $migration.jobInfo.creationDate;
LastUpdated = $migration.jobInfo.lastUpdated;
}
$results+=$tmp
}
$results
}
}
Function Connect-HcxVAMI {
<#
.NOTES
@@ -136,7 +539,7 @@ Function Connect-HcxVAMI {
$global:hcxVAMIConnection
}
Function Get-HcxVAMIVCConfig {
Function Get-HcxVCConfig {
<#
.NOTES
===========================================================================
@@ -152,7 +555,7 @@ Function Get-HcxVAMIVCConfig {
.DESCRIPTION
This cmdlet returns the onPrem vCenter Server registered with HCX Manager
.EXAMPLE
Get-HcxVAMIVCConfig
Get-HcxVCConfig
#>
If (-Not $global:hcxVAMIConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxVAMI " } Else {
$vcConfigUrl = $global:hcxVAMIConnection.Server + "/api/admin/global/config/vcenter"