Migration/vSphere/vSphereUtil.psm1
using module './RiverMeadow.VSphereVMTag' Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Common ` | Join-Path -ChildPath Wrappers | Join-Path -ChildPath Wrappers) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Util ` | Join-Path -ChildPath Util) function Get-RMVSphereTagCategory { param( [System.Object] $TargetInventory ) $TagCategories = @() $TagCategoryAsHashtable = @{} foreach ($TagCategory in $TargetInventory.attributes.vsphere.tag_categories) { $RMTagCategory = [RMVSphereTagCategory]::new($TagCategory.name, $TagCategory.identifier) foreach ($Tag in $TagCategory.tags) { $RMTag = $RMTagCategory.AddTag($Tag.name, $Tag.identifier) if ($TagCategoryAsHashtable.ContainsKey($TagCategory.name)) { $TagCategoryAsHashtable[$TagCategory.name] += $RMTag } else { $TagCategoryAsHashtable.Add($TagCategory.name, @($RMTag)) } } $TagCategories += $RMTagCategory } return $TagCategories, $TagCategoryAsHashtable } function Get-RMTagOption { param( [RMVSphereTagCategory[]] $TagCategory ) $TagOptions = @() foreach ($Category in $TagCategory) { foreach ($Tag in $Category.Tags) { $TagOption = $Tag.Name + "[" + $Category.CategoryName + "]" $TagOptions += $TagOption } } return $TagOptions } function Get-RMVMTag { param( [System.Object] $TargetInventory ) $TagCategories, $TagCategoryAsHashtable = Get-RMVSphereTagCategory -TargetInventory $TargetInventory $TagOptions = Get-RMTagOption -TagCategory $TagCategories while ($true) { $VMTags = Read-RMToken -UserMessage "Enter one or more VM tags separated by commas" -Options $TagOptions ` -DefaultValue "None" -ParameterName "VM tags" -Separator "," if ([string]::IsNullOrWhiteSpace($VMTags)) { return @{} } $CompareResults = Compare-Object -ReferenceObject $TagOptions -DifferenceObject $VMTags -IncludeEqual $InputObjects = Get-RMInputObjectBySideIndicator -CompareResult $CompareResults -SideIndicator "==" if ($InputObjects.Count -ne $VMTags.Count) { Write-RMError -Message "One or more VM tags does not belong to the given list of VM tags, please try again." } else { return (Get-RMSelectedVMTag -VMTag $VMTags -TagCategory $TagCategoryAsHashtable) } } } function Get-RMSelectedVMTag { param( [string[]] $VMTag, [hashtable] $TagCategory ) $SelectedVMTag = @{} foreach ($Tag in $VMTag) { $TagName = $Tag.Substring(0, $Tag.LastIndexOf("[")) $CategoryName = $Tag.Substring($Tag.LastIndexOf("[") + 1, $Tag.LastIndexOf("]") - ($Tag.LastIndexOf("[") + 1)) $RMTags = $TagCategory[$CategoryName] foreach ($RMTag in $RMTags) { if ($RMTag.name -ine $TagName) { continue } if ($SelectedVMTag.ContainsKey($CategoryName)) { $SelectedVMTag[$CategoryName] += $RMTag } else { $Tags = @($RMTag) $SelectedVMTag.Add($CategoryName, $Tags) } } } return $SelectedVMTag } function Get-RMSelectedVMTagByRMVSphereTag { param( [RMVSphereTag[]] $InputTag, [System.Object] $TargetInventory ) $SelectedVMTag = @{} $TagCategories, $TagCategoryAsHashtable = Get-RMVSphereTagCategory -TargetInventory $TargetInventory foreach ($RMVSphereTag in $InputTag) { if ($null -eq $RMVSphereTag) { continue } $CategoryName = $RMVSphereTag.RMVSphereTagCategory.GetCategoryName() $RMTags = $TagCategoryAsHashtable[$CategoryName] foreach ($RMTag in $RMTags) { if ($RMTag.GetTagName() -ne $RMVSphereTag.GetTagName()) { continue } if ($SelectedVMTag.ContainsKey($CategoryName)) { $SelectedVMTag[$CategoryName] += $RMTag } else { $SelectedVMTag.Add($CategoryName, @($RMTag)) } } } return $SelectedVMTag } function Get-RMStoragePolicy { param( [System.Object] $TargetInventory, [System.Object] $Source, [string[]] $SelectedDiskIndex, [bool] $IsInteractive ) $DiskCnt = 0 $SelectedStorageProfileIds = @{} $SelectedStorageProfileNames = @{} $StoragePolicyOptions = Get-RMStoragePolicyOption -TargetInventory $TargetInventory foreach ($DiskIndex in $SelectedDiskIndex) { if ($IsInteractive) { $Disk = $Source.attributes.storage.vm_disks[$DiskIndex] $Size = $Disk.size_kb/(1024*1024) $Size = [math]::round($Size, 2) $StoragePolicyName = Read-RMString -UserMessage "Enter storage policy name for disk of size $Size GiB" ` -Options $StoragePolicyOptions.keys -DefaultValue "None" -ParameterName "Storage policy name" -IsRequired $false if (![string]::IsNullOrWhiteSpace($StoragePolicyName)) { $SelectedStorageProfileIds.Add($Disk.label, $StoragePolicyOptions[$StoragePolicyName]) $SelectedStorageProfileNames.Add($Disk.label, $StoragePolicyName) } } else { #TODO: Add non-interactive case functionality } $DiskCnt ++ } return $SelectedStorageProfileIds, $SelectedStorageProfileNames } function Get-RMStoragePolicyOption { param( [System.Object] $TargetInventory ) $StoragePolicyOptions = @{} # Storage profiles are not datacenter specific and live at the vCenter level and applies to # all the datacenters; though ME's target inventory puts it under the datacenter JSON block, # so if a vCenter has multiple datacenters then the storage profiles under each datacenter # will be the same, hence we are just picking up the storage profiles from the first datacenter. foreach ($StorageProfile in $TargetInventory.attributes.vsphere.datacenters[0].storage_profiles) { # User will be providing the storage profile name and hence using it as the key # so that we can send both the UUID and the name to FE. # Storage profile names are unique in given vCenter $StoragePolicyOptions.Add($StorageProfile.name, $StorageProfile.uuid) } return $StoragePolicyOptions } function Get-RMStorageProfileIdByStoragePolicyName { param ( [hashtable] $StoragePolicyNamePerDiskLabel, [System.Object] $TargetInventory ) $ProfileId = @{} if ($null -eq $StoragePolicyNamePerDiskLabel -or $StoragePolicyNamePerDiskLabel.Keys.Count -eq 0) { return $ProfileId } $PolicyNameToUUIDMapping = Get-RMStoragePolicyOption -TargetInventory $TargetInventory foreach ($DiskLabel in $StoragePolicyNamePerDiskLabel.Keys) { $StoragePolicyName = $StoragePolicyNamePerDiskLabel[$DiskLabel].Trim() if ($PolicyNameToUUIDMapping.ContainsKey($StoragePolicyName)) { $ProfileId.Add($DiskLabel, $PolicyNameToUUIDMapping[$StoragePolicyName]) } } return $ProfileId } function Get-RMDiskProvisioningTypeForVMBasedSource { param( [System.Object] $Source, [string[]] $DiskProvisioningType, [string[]] $SelectedDiskIndex, [hashtable] $SelectedStorageProfileName, [bool] $IsInteractive ) if ($Source.collection_type -ine "vm") { throw "Get-RMDiskProvisioningTypeForVMBasedSource is supported for VM based sources only" } $ProvisioningTypes = "thick-lazy-zeroed", "thick-eager-zeroed", "thin" $DiskWithProvisioningTypeCnt = 0 $ResultProvisioningTypes = @() for ($Index = 0; $Index -lt $Source.attributes.storage.vm_disks.Count; $Index++) { if ($SelectedDiskIndex -notcontains $Index) { $ResultProvisioningTypes += $null continue } $Disk = $Source.attributes.storage.vm_disks[$Index] if ($null -ne $SelectedStorageProfileName -and $SelectedStorageProfileName.ContainsKey($Disk.label)) { $ResultProvisioningTypes += $null continue } if ($IsInteractive) { $Size = $Disk.size_kb/(1024*1024) $Size = [math]::round($Size, 2) $ResultProvisioningTypes += Read-RMString -UserMessage "Enter disk provisioning type for disk of size $Size GiB" ` -Options $ProvisioningTypes -DefaultValue "thin" -ParameterName "Disk provisioning type" -IsRequired $false } else { if ($null -ne $DiskProvisioningType -and $DiskWithProvisioningTypeCnt -lt $DiskProvisioningType.Count) { $ResultProvisioningTypes += $DiskProvisioningType[$DiskWithProvisioningTypeCnt].Trim() $DiskWithProvisioningTypeCnt ++ } else { $ResultProvisioningTypes += "thin" } } } return $ResultProvisioningTypes } function Get-RMDatastoreByVMBasedSource { param( [System.Object] $Source, [string[]] $TargetDatastores, [string[]] $SelectedDiskIndex, [bool] $IsInteractive ) if (!$IsInteractive) { Throw "The function Get-RMDatastoreBySource does not support non-interactive case" } if ($TargetDatastores.Count -eq 0) { Throw "No datastores were found, migration cannot be started." } if ($Source.collection_type -ine "vm") { Throw "Get-RMDatastoreByVMBasedSource is supported for VM based sources only" } $Datastores = @() for ($Index = 0; $Index -lt $Source.attributes.storage.vm_disks.Count; $Index++) { if ($SelectedDiskIndex -contains $Index) { $Disk = $Source.attributes.storage.vm_disks[$Index] $Size = $Disk.size_kb/(1024*1024) $Size = [math]::round($Size, 2) $Datastores += Read-RMString -UserMessage "Enter the datastore name for disk of size $Size GiB" ` -Options $TargetDatastores -DefaultValue $TargetDatastores[0] -ParameterName "Datastore name" -IsRequired $false } else { $Datastores += "" } } return $Datastores } function Get-RMStoragePolicyNameByTargetInventory { param( [System.Object] $TargetInventory ) $StoragePolicyNames = @() # Read the comment above for loop in method Get-RMStoragePolicyOption as to why first datacenter # is being used foreach ($StorageProfile in $TargetInventory.attributes.vsphere.datacenters[0].storage_profiles) { $StoragePolicyNames += $StorageProfile.name } return $StoragePolicyNames } function Confirm-RMStoragePolicy { param( [System.Object] $TargetInventory, [string[]] $StoragePolicyName ) $StoragePolicyNames = Get-RMStoragePolicyNameByTargetInventory -TargetInventory $TargetInventory $ValidPolicyNames = @() $InvalidPolicyNames = @() foreach ($PolicyName in $StoragePolicyName) { if ([string]::IsNullOrWhiteSpace($PolicyName) -or $PolicyName -ieq "none") { continue } if ($StoragePolicyNames -contains $PolicyName) { $ValidPolicyNames += $PolicyName } else { $InvalidPolicyNames += $PolicyName } } return $ValidPolicyNames, $InvalidPolicyNames } function Get-RMValidDiskProvisioningType { param( [string[]] $DiskProvisioningType ) $DiskProvisioningTypes = @() foreach ($ProvisioningType in $DiskProvisioningType) { if ([string]::IsNullOrWhiteSpace($ProvisioningType) -or $ProvisioningType -ieq "none") { continue } $DiskProvisioningTypes += $ProvisioningType } return $DiskProvisioningTypes } function Get-RMDiskLabelToStoragePolicyMapping { param( [string[]] $StoragePolicyName, [hashtable] $UserParameter ) if ($null -eq $StoragePolicyName -or $StoragePolicyName.Count -eq 0) { return $null } $DiskLabelToStoragePolicyMapping = @{} $SelectedDiskLabel = $UserParameter["SelectedDiskLabel"] for ($Index = 0; $Index -lt $SelectedDiskLabel.Count; $Index++) { # The storage policy names provided by the user are treated positionally to selected disk labels if ([string]::IsNullOrWhiteSpace($StoragePolicyName[$Index]) -or ` $StoragePolicyName[$Index] -ieq "none") { continue } $DiskLabelToStoragePolicyMapping.Add($SelectedDiskLabel[$Index], $StoragePolicyName[$Index]) } return $DiskLabelToStoragePolicyMapping } function Read-RMResourcePoolName { param ( [System.Object] $DatacenterObject, [string] $ClusterName ) $ReadValue = Read-RMBoolean -UserMessage "Do you want to create resource pool" -DefaultValue "false" if ($ReadValue) { $ResourcePoolName = Read-RMString -UserMessage "Enter resource pool name" -DefaultValue "None" ` -ParameterName "Resource pool name" -IsRequired $false } else { $ResourcePools = Get-RMVMResourcePoolname -DatacenterObject $DatacenterObject -ClusterName $ClusterName if ($null -ne $ResourcePools -and $ResourcePools.Count -gt 0) { $ResourcePoolName = Read-RMString -UserMessage "Enter resource pool name" -DefaultValue "None" ` -Options $ResourcePools -ParameterName "Resource pool name" -IsRequired $false } } return $ResourcePoolName } function Read-RMFolderName { param ( [System.Object] $TargetInventory, [string] $DatacenterName ) $ReadValue = Read-RMBoolean -UserMessage "Do you want to create VM folder" -DefaultValue "false" if ($ReadValue) { $FolderName = Read-RMString -UserMessage "Enter the VM folder path using '/' as the path separator" -DefaultValue "None" ` -ParameterName "Folder name" -IsRequired $false } else { $VMFolders = Get-RMVMFolderName -TargetInventory $TargetInventory -DatacenterName $DatacenterName $FolderName = Read-RMVMFolderString -UserMessage "Enter the VM folder path using '/' as the path separator" -VMFolders $VMFolders -DefaultValue "None" } return $FolderName } function Get-RMVMFolderName { param ( [System.Object] $TargetInventory, [string] $DatacenterName ) $VMFolders = @() foreach ($Datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($DatacenterName -ieq $Datacenter.name) { foreach ($Folder in $Datacenter.vm_folder.folders) { $VMFolders += Get-RMPath -Folder $Folder } } } return $VMFolders } function Get-RMFolderNameByDatacenter { param( [System.Object] $DatacenterObject ) $VMFolders = @() foreach ($Folder in $DatacenterObject.vm_folder.folders) { $VMFolders += Get-RMPath -Folder $Folder } return $VMFolders } function Get-RMPath { param( [System.Object] $Folder, [array] $Paths ) $Paths += $Folder.path if ($null -ne $Folder.folders) { foreach ($F in $Folder.folders) { $Paths = Get-RMPath -Folder $F -Paths $Paths } } return $Paths } function Get-RMVMResourcePoolname { param ( [System.Object] $DatacenterObject, [string] $ClusterName ) $ResourcePool = @() foreach($Cluster in $DatacenterObject.clusters) { if ($ClusterName -ieq $Cluster.name) { $ResourcePool = Get-RMResourcePoolPath -ResourcePool $Cluster.resource_pools } } return $ResourcePool } function Get-RMResourcePoolPath { param ( [System.Object] $ResourcePool, [array] $Paths ) $Paths += $ResourcePool.path if ($null -ne $ResourcePool.resource_pools) { foreach ($R in $ResourcePool.resource_pools) { $Paths = Get-RMResourcePoolPath -ResourcePool $R -Paths $Paths } } return $Paths } function Get-ClusterAndDatacenterObject { param( [system.object] $SourceInventory, [string] $DatacenterName ) $ClusterObject = @{} $DatacenterObject = @{} foreach ($ob in $SourceInventory.properties.datacenters) { if ($DatacenterName -ieq $ob.name) { $DatacenterObject = $ob $ClusterObject = $ob.clusters break } } return $ClusterObject, $DatacenterObject } function Get-RMVMBasedAppliance { param ( [System.Object] $CloudAccountObject ) $HeartBeatingVMBasedAppliance= @{} $NonHeartBeatingVMBasedAppliance = @{} foreach($CloudAccount in $CloudAccountObject) { $Appliance = $CloudAccount.Values.appliance if ("rivermeadow_standalone" -ne $CloudAccount.Values.type) { if ($Appliance.vm_level_migration_enabled) { if ($Appliance.heartbeat_status) { $HeartBeatingVMBasedAppliance += $CloudAccount } else { $NonHeartBeatingVMBasedAppliance += $CloudAccount } } } else { if ($Appliance.cloud_configuration.vsphere.vm_level_migrations_enabled) { if ($Appliance.heartbeat_status) { $HeartBeatingVMBasedAppliance += $CloudAccount } else { $NonHeartBeatingVMBasedAppliance += $CloudAccount } } } } return $HeartBeatingVMBasedAppliance, $NonHeartBeatingVMBasedAppliance } |