Skip to content

Commit 7005c71

Browse files
minhsuanleeSam Lee
andauthored
[Az.Migrate] To Azure Local - additional validations (#28183)
Co-authored-by: Sam Lee <samlee3@microsoft.com>
1 parent 84274b2 commit 7005c71

File tree

56 files changed

+620
-436
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+620
-436
lines changed

src/Migrate/Migrate.Autorest/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ directive:
323323
- from: Microsoft.OffAzure/stable/2020-01-01/migrate.json
324324
where:
325325
verb: Get
326-
subject: ^HyperV(Cluster|Host|Job|OperationsStatus)$
326+
subject: ^HyperV(Job|OperationsStatus)$
327327
remove: true
328328
- from: Microsoft.OffAzure/stable/2020-01-01/migrate.json
329329
where:
@@ -477,6 +477,11 @@ directive:
477477
verb: Get$
478478
subject: ^VCenter$
479479
hide: true
480+
- from: Microsoft.OffAzure/stable/2020-01-01/migrate.json
481+
where:
482+
verb: Get$
483+
subject: ^HyperV(Cluster|Host)$
484+
hide: true
480485
- where:
481486
verb: New$|Update$
482487
variant: ^(Update|Create)(?!.*?Expanded)

src/Migrate/Migrate.Autorest/custom/Helper/CommonHelper.ps1 renamed to src/Migrate/Migrate.Autorest/custom/Helper/AzLocalCommonHelper.ps1

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function CheckStorageModuleDependency {
3737
}
3838
}
3939

40-
function GetHCIClusterARGQuery {
40+
function GetARGQueryForArcResourceBridge {
4141
[Microsoft.Azure.PowerShell.Cmdlets.Migrate.DoNotExportAttribute()]
4242
param(
4343
[Parameter(Mandatory)]
@@ -282,25 +282,37 @@ function ValidateReplication {
282282
throw $VmReplicationValidationMessages.VmPoweredOff
283283
}
284284

285+
# Hyper-V scenario checks
285286
if ($MigrationType -eq $AzLocalInstanceTypes.HyperVToAzLocal) {
287+
# Hyper-V VMs with 'otherguestfamily' OS type and missing OS name could also mean Hyper-V Integration Services are not running
286288
if ([string]::IsNullOrEmpty($Machine.OperatingSystemDetailOSType) -or
287-
($Machine.OperatingSystemDetailOSType -eq $OsType.OtherGuestFamily -and [string]::IsNullOrEmpty($Machine.GuestOSDetailOsname))) {
288-
throw $VmReplicationValidationMessages.OsTypeNotFound
289+
($Machine.OperatingSystemDetailOSType -eq $OsTypes.OtherGuestFamily -and [string]::IsNullOrEmpty($Machine.GuestOSDetailOsname)))
290+
{
291+
throw $VmReplicationValidationMessages.HyperVIntegrationServicesNotRunning
289292
}
290293

291-
if ($Machine.ClusterId -and $Machine.HighAvailability -eq $HighAvailability.NO) {
294+
# Hyper-V VMs should be highly available
295+
if (![string]::IsNullOrEmpty($Machine.ClusterId) -and $Machine.HighAvailability -eq $HighAvailability.NO) {
292296
throw $VmReplicationValidationMessages.VmNotHighlyAvailable
293297
}
294298
}
295299

300+
# VMware scenario checks
296301
if ($MigrationType -eq $AzLocalInstanceTypes.VMwareToAzLocal) {
297-
# Once VMware tools are installed, OS type should be available.
302+
# VMware tools should be running to support static ip migration
298303
if ($Machine.VMwareToolsStatus -eq $VMwareToolsStatus.NotRunning) {
299-
throw $VmReplicationValidationMessages.VmWareToolsNotRunning
304+
Write-Warning $VmReplicationValidationMessages.VmWareToolsNotRunning
300305
}
301306

302307
if ($Machine.VMwareToolsStatus -eq $VMwareToolsStatus.NotInstalled) {
303-
throw $VmReplicationValidationMessages.VmWareToolsNotInstalled
308+
Write-Warning $VmReplicationValidationMessages.VmWareToolsNotInstalled
304309
}
305310
}
311+
312+
# Only OS type of windowsguest and linuxguest are supported for Hyper-V and VMware scenarios
313+
if ($Machine.OperatingSystemDetailOSType -ne $OsTypes.WindowsGuest -and
314+
$Machine.OperatingSystemDetailOSType -ne $OsTypes.LinuxGuest)
315+
{
316+
Write-Warning $VmReplicationValidationMessages.OsTypeNotSupported
317+
}
306318
}

src/Migrate/Migrate.Autorest/custom/Helper/AzLocalCommonSettings.ps1

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ $VMwareToolsStatus = @{
101101
NotInstalled = "NotInstalled";
102102
}
103103

104-
$OsType = @{
104+
$OsTypes = @{
105105
LinuxGuest = "linuxguest";
106106
WindowsGuest = "windowsguest";
107107
OtherGuestFamily = "otherguestfamily";
@@ -111,8 +111,14 @@ $VmReplicationValidationMessage = "Replication could not be initiated. Please en
111111
$VmReplicationValidationMessages = @{
112112
VmPoweredOff = "The VM is currently powered off. $VmReplicationValidationMessage";
113113
AlreadyInReplication = "The VM is already in replication. $VmReplicationValidationMessage";
114-
VmWareToolsNotInstalled = "VMware tools not installed on VM. $VmReplicationValidationMessage";
115-
VmWareToolsNotRunning = "VMware tools not running on VM. $VmReplicationValidationMessage";
116114
VmNotHighlyAvailable = "VM not highly available. $VmReplicationValidationMessage";
117-
OsTypeNotFound = "Hyper-V Integration Services not running on VM. $VmReplicationValidationMessage";
115+
HyperVIntegrationServicesNotRunning = "Hyper-V Integration Services are not running on VM. $VmReplicationValidationMessage";
116+
VmWareToolsNotInstalled = "VMware Tools are not installed on the VM. To preserve static IPs during migration, install VMware Tools and wait up to 30 minutes for the system to detect the changes.";
117+
VmWareToolsNotRunning = "VMware Tools are not running on the VM. To preserve static IPs during migration, ensure VMware Tools are running and wait up to 30 minutes for the system to detect the changes.";
118+
OsTypeNotSupported = "The VM OS type could not be identified. For custom Windows or Linux builds, run: `Set-AzMigrateLocalServerReplication -TargetObjectID <ProtectedItemId> -OsType <OsType>` to specify the OS type before migration.";
119+
}
120+
121+
$ArcResourceBridgeValidationMessages = @{
122+
NotRunning = "Arc Resource Bridge is offline. To continue, bring the Arc Resource Bridge online. Wait a few minutes for the status to update and retry.";
123+
NoClusters = "There are no Azure Local clusters found in the selected resource group."
118124
}

src/Migrate/Migrate.Autorest/custom/Initialize-AzMigrateLocalReplicationInfrastructure.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function Initialize-AzMigrateLocalReplicationInfrastructure {
121121

122122
process {
123123
Import-Module $PSScriptRoot\Helper\AzLocalCommonSettings.ps1
124-
Import-Module $PSScriptRoot\Helper\CommonHelper.ps1
124+
Import-Module $PSScriptRoot\Helper\AZLocalCommonHelper.ps1
125125

126126
CheckResourcesModuleDependency
127127
CheckStorageModuleDependency

src/Migrate/Migrate.Autorest/custom/New-AzMigrateLocalServerReplication.ps1

Lines changed: 103 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ function New-AzMigrateLocalServerReplication {
170170

171171
process {
172172
Import-Module $PSScriptRoot\Helper\AzLocalCommonSettings.ps1
173-
Import-Module $PSScriptRoot\Helper\CommonHelper.ps1
173+
Import-Module $PSScriptRoot\Helper\AZLocalCommonHelper.ps1
174174

175175
CheckResourceGraphModuleDependency
176176
CheckResourcesModuleDependency
@@ -200,6 +200,8 @@ function New-AzMigrateLocalServerReplication {
200200

201201
if ($SiteType -eq $SiteTypes.HyperVSites) {
202202
$instanceType = $AzLocalInstanceTypes.HyperVToAzLocal
203+
204+
# Get Hyper-V machine
203205
$machine = InvokeAzMigrateGetCommandWithRetries `
204206
-CommandName 'Az.Migrate.Internal\Get-AzMigrateHyperVMachine' `
205207
-Parameters @{
@@ -209,16 +211,68 @@ function New-AzMigrateLocalServerReplication {
209211
} `
210212
-ErrorMessage "Machine '$MachineName' not found in resource group '$ResourceGroupName' and site '$SiteName'."
211213

214+
# Get Hyper-V site
212215
$siteObject = InvokeAzMigrateGetCommandWithRetries `
213216
-CommandName 'Az.Migrate.Internal\Get-AzMigrateHyperVSite' `
214217
-Parameters @{
215218
'ResourceGroupName' = $ResourceGroupName;
216219
'SiteName' = $SiteName;
217220
} `
218221
-ErrorMessage "Machine site '$SiteName' with Type '$SiteType' not found."
222+
223+
# Get RunAsAccount
224+
if (![string]::IsNullOrEmpty($machine.HostId))
225+
{
226+
# machine is on a single Hyper-V host
227+
$hostIdArray = $machine.HostId.Split("/")
228+
if ($hostIdArray.Length -lt 11) {
229+
throw "Invalid Hyper-V Host ARM ID '$($machine.HostId)'"
230+
}
231+
232+
$hostResourceGroupName = $hostIdArray[4]
233+
$hostSiteName = $hostIdArray[8]
234+
$hostName = $hostIdArray[10]
235+
236+
$hyperVHost = InvokeAzMigrateGetCommandWithRetries `
237+
-CommandName 'Az.Migrate.Internal\Get-AzMigrateHyperVHost' `
238+
-Parameters @{
239+
'ResourceGroupName' = $hostResourceGroupName;
240+
'SiteName' = $hostSiteName;
241+
'HostName' = $hostName;
242+
} `
243+
-ErrorMessage "Hyper-V host '$hostName' not found in resource group '$hostResourceGroupName' and site '$hostSiteName'."
244+
245+
$runAsAccountId = $hyperVHost.RunAsAccountId
246+
}
247+
elseif(![string]::IsNullOrEmpty($machine.ClusterId))
248+
{
249+
# machine is on a Hyper-V cluster
250+
$clusterIdArray = $machine.ClusterId.Split("/")
251+
if ($clusterIdArray.Length -lt 11) {
252+
throw "Invalid Hyper-V Cluster ARM ID '$($machine.ClusterId)'"
253+
}
254+
255+
$clusterResourceGroupName = $clusterIdArray[4]
256+
$clusterSiteName = $clusterIdArray[8]
257+
$clusterName = $clusterIdArray[10]
258+
259+
$hyperVCluster = InvokeAzMigrateGetCommandWithRetries `
260+
-CommandName 'Az.Migrate.Internal\Get-AzMigrateHyperVCluster' `
261+
-Parameters @{
262+
'ResourceGroupName' = $clusterResourceGroupName;
263+
'SiteName' = $clusterSiteName;
264+
'ClusterName' = $clusterName;
265+
} `
266+
-ErrorMessage "Hyper-V cluster '$clusterName' not found in resource group '$clusterResourceGroupName' and site '$clusterSiteName'."
267+
268+
$runAsAccountId = $hyperVCluster.RunAsAccountId
269+
}
219270
}
220-
else {
271+
elseif ($SiteType -eq $SiteTypes.VMwareSites)
272+
{
221273
$instanceType = $AzLocalInstanceTypes.VMwareToAzLocal
274+
275+
# Get VMware machine
222276
$machine = InvokeAzMigrateGetCommandWithRetries `
223277
-CommandName 'Az.Migrate.Internal\Get-AzMigrateMachine' `
224278
-Parameters @{
@@ -228,13 +282,47 @@ function New-AzMigrateLocalServerReplication {
228282
} `
229283
-ErrorMessage "Machine '$MachineName' not found in resource group '$ResourceGroupName' and site '$SiteName'."
230284

285+
# Get VMware site
231286
$siteObject = InvokeAzMigrateGetCommandWithRetries `
232287
-CommandName 'Az.Migrate\Get-AzMigrateSite' `
233288
-Parameters @{
234289
'ResourceGroupName' = $ResourceGroupName;
235290
'SiteName' = $SiteName;
236291
} `
237292
-ErrorMessage "Machine site '$SiteName' with Type '$SiteType' not found."
293+
294+
# Get RunAsAccount
295+
if (![string]::IsNullOrEmpty($machine.VCenterId))
296+
{
297+
# machine is on a single vCenter
298+
$vCenterIdArray = $machine.VCenterId.Split("/")
299+
if ($vCenterIdArray.Length -lt 11) {
300+
throw "Invalid VMware vCenter ARM ID '$($machine.VCenterId)'"
301+
}
302+
303+
$vCenterResourceGroupName = $vCenterIdArray[4]
304+
$vCenterSiteName = $vCenterIdArray[8]
305+
$vCenterName = $vCenterIdArray[10]
306+
307+
$vmwareVCenter = InvokeAzMigrateGetCommandWithRetries `
308+
-CommandName 'Az.Migrate.Internal\Get-AzMigrateVCenter' `
309+
-Parameters @{
310+
'ResourceGroupName' = $vCenterResourceGroupName;
311+
'SiteName' = $vCenterSiteName;
312+
'Name' = $vCenterName;
313+
} `
314+
-ErrorMessage "VMware vCenter '$vCenterName' not found in resource group '$vCenterResourceGroupName' and site '$vCenterSiteName'."
315+
316+
$runAsAccountId = $vmwareVCenter.RunAsAccountId
317+
}
318+
}
319+
else
320+
{
321+
throw "Unsupported site type '$SiteType'. Only Hyper-V and VMware sites are supported."
322+
}
323+
324+
if ([string]::IsNullOrEmpty($runAsAccountId)) {
325+
throw "Unable to determine RunAsAccount for site '$SiteName' from machine '$MachineName'. Please verify your appliance setup."
238326
}
239327

240328
# Validate the VM
@@ -266,6 +354,9 @@ function New-AzMigrateLocalServerReplication {
266354
"Name" = $replicationVaultName
267355
} `
268356
-ErrorMessage "No Replication Vault '$replicationVaultName' found in Resource Group '$ResourceGroupName'. Please verify your Azure Migrate project setup."
357+
if ($replicationVault.Property.ProvisioningState -ne [ProvisioningState]::Succeeded) {
358+
throw "The Replication Vault '$replicationVaultName' is not in a valid state. The provisioning state is '$($replicationVault.Property.ProvisioningState)'. Please verify your Azure Migrate project setup."
359+
}
269360

270361
# Access Discovery Service
271362
$discoverySolutionName = "Servers-Discovery-ServerDiscovery"
@@ -420,38 +511,17 @@ function New-AzMigrateLocalServerReplication {
420511
throw "The replication extension '$replicationExtensionName' is not in a valid state. The provisioning state is '$($replicationExtension.Property.ProvisioningState)'. Re-run the Initialize-AzMigrateLocalReplicationInfrastructure command."
421512
}
422513

423-
# Get Target cluster
514+
# Get ARC Resource Bridge info
424515
$targetClusterId = $targetFabric.Property.CustomProperty.Cluster.ResourceName
425516
$targetClusterIdArray = $targetClusterId.Split("/")
426517
$targetSubscription = $targetClusterIdArray[2]
427-
$hciClusterArgQuery = GetHCIClusterARGQuery -HCIClusterID $targetClusterId
428-
$targetCluster = Az.ResourceGraph\Search-AzGraph -Query $hciClusterArgQuery -Subscription $targetSubscription
429-
if ($null -eq $targetCluster) {
430-
throw "Validate target cluster with id '$targetClusterId' exists. Check ARC resource bridge is running on this cluster."
518+
$arbArgQuery = GetARGQueryForArcResourceBridge -HCIClusterID $targetClusterId
519+
$arbArgResult = Az.ResourceGraph\Search-AzGraph -Query $arbArgQuery -Subscription $targetSubscription
520+
if ($null -eq $arbArgResult) {
521+
throw "$($ArcResourceBridgeValidationMessages.NoClusters). Validate target cluster with id '$targetClusterId' exists."
431522
}
432-
433-
# Get source appliance RunAsAccount
434-
if ($SiteType -eq $SiteTypes.HyperVSites) {
435-
$runAsAccounts = InvokeAzMigrateGetCommandWithRetries `
436-
-CommandName 'Az.Migrate.Internal\Get-AzMigrateHyperVRunAsAccount' `
437-
-Parameters @{
438-
ResourceGroupName = $ResourceGroupName;
439-
SiteName = $SiteName;
440-
} `
441-
-ErrorMessage "No run as account found for site '$SiteName'."
442-
443-
$runAsAccount = $runAsAccounts | Where-Object { $_.CredentialType -eq $RunAsAccountCredentialTypes.HyperVFabric }
444-
}
445-
elseif ($SiteType -eq $SiteTypes.VMwareSites) {
446-
$runAsAccounts = InvokeAzMigrateGetCommandWithRetries `
447-
-CommandName 'Az.Migrate\Get-AzMigrateRunAsAccount' `
448-
-Parameters @{
449-
ResourceGroupName = $ResourceGroupName;
450-
SiteName = $SiteName;
451-
} `
452-
-ErrorMessage "No run as account found for site '$SiteName'."
453-
454-
$runAsAccount = $runAsAccounts | Where-Object { $_.CredentialType -eq $RunAsAccountCredentialTypes.VMwareFabric }
523+
elseif ($arbArgResult.statusOfTheBridge -ne "Running") {
524+
throw "$($ArcResourceBridgeValidationMessages.NotRunning). Make sure the Arc Resource Bridge is online before retrying."
455525
}
456526

457527
# Validate TargetVMName
@@ -480,12 +550,12 @@ function New-AzMigrateLocalServerReplication {
480550
}
481551

482552
$customProperties.InstanceType = $instanceType
483-
$customProperties.CustomLocationRegion = $targetCluster.CustomLocationRegion
553+
$customProperties.CustomLocationRegion = $arbArgResult.CustomLocationRegion
484554
$customProperties.FabricDiscoveryMachineId = $machine.Id
485-
$customProperties.RunAsAccountId = $runAsAccount.Id
555+
$customProperties.RunAsAccountId = $runAsAccountId
486556
$customProperties.SourceFabricAgentName = $sourceDra.Name
487557
$customProperties.StorageContainerId = $TargetStoragePathId
488-
$customProperties.TargetArcClusterCustomLocationId = $targetCluster.CustomLocation
558+
$customProperties.TargetArcClusterCustomLocationId = $arbArgResult.CustomLocation
489559
$customProperties.TargetFabricAgentName = $targetDra.Name
490560
$customProperties.TargetHciClusterId = $targetClusterId
491561
$customProperties.TargetResourceGroupId = $TargetResourceGroupId

src/Migrate/Migrate.Autorest/custom/Set-AzMigrateLocalServerReplication.ps1

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ function Set-AzMigrateLocalServerReplication {
6464
# Specifies the nics on the source server to be included for replication.
6565
${NicToInclude},
6666

67+
[Parameter()]
68+
[ValidateSet("WindowsGuest" , "LinuxGuest")]
69+
[ArgumentCompleter( { "WindowsGuest" , "LinuxGuest" })]
70+
[Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')]
71+
[System.String]
72+
# Specifies the OS type of the VM, either WindowsGuest or LinuxGuest.
73+
${OsType},
74+
6775
[Parameter()]
6876
[Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')]
6977
[Microsoft.Azure.PowerShell.Cmdlets.Migrate.Runtime.DefaultInfo(Script = '(Get-AzContext).Subscription.Id')]
@@ -121,7 +129,7 @@ function Set-AzMigrateLocalServerReplication {
121129

122130
process {
123131
Import-Module $PSScriptRoot\Helper\AzLocalCommonSettings.ps1
124-
Import-Module $PSScriptRoot\Helper\CommonHelper.ps1
132+
Import-Module $PSScriptRoot\Helper\AZLocalCommonHelper.ps1
125133

126134
CheckResourcesModuleDependency
127135

@@ -133,13 +141,15 @@ function Set-AzMigrateLocalServerReplication {
133141
if ($HasIsDynamicMemoryEnabled) {
134142
$isDynamicRamEnabled = [System.Convert]::ToBoolean($IsDynamicMemoryEnabled)
135143
}
144+
$HasOsType = $PSBoundParameters.ContainsKey('OsType')
136145

137146
$null = $PSBoundParameters.Remove('TargetVMCPUCore')
138147
$null = $PSBoundParameters.Remove('IsDynamicMemoryEnabled')
139148
$null = $PSBoundParameters.Remove('DynamicMemoryConfig')
140149
$null = $PSBoundParameters.Remove('TargetVMRam')
141150
$null = $PSBoundParameters.Remove('NicToInclude')
142151
$null = $PSBoundParameters.Remove('TargetObjectID')
152+
$null = $PSBoundParameters.Remove('OsType')
143153
$null = $PSBoundParameters.Remove('WhatIf')
144154
$null = $PSBoundParameters.Remove('Confirm')
145155

@@ -301,6 +311,11 @@ function Set-AzMigrateLocalServerReplication {
301311
}
302312
}
303313

314+
# Update OS type
315+
if ($HasOsType) {
316+
$customPropertiesUpdate.OsType = $OsType
317+
}
318+
304319
$protectedItemPropertiesUpdate = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20240901.ProtectedItemModelPropertiesUpdate]::new()
305320
$protectedItemPropertiesUpdate.CustomProperty = $customPropertiesUpdate
306321

0 commit comments

Comments
 (0)