Skip to content

Commit

Permalink
Add NAT Pool to NAT Rule Upgrade + Fix NAT Rule Migrations (#98)
Browse files Browse the repository at this point in the history
* remove IP conversion warnings

* remove unnecessary update when no NAT pools

* add and fix nat scenarios

* fixed as rg dependency

* renamed backup module

* added nat pool migration function

* support for nat rule only configs

* comment clarity

* nat pool migration with emtpy backend

* nat rule ipconfig migration

* nat pool migration validation and param changes

* release notes

* add param -skipMigrateNATPoolsToNATRules to deploy.ps1

* fix skip nat pool upgrade param pass

* add nat pool param

* rename param skipUpgradeNATPoolsToNATRules

* nat rule count validation, empty nat pools

* docs update
  • Loading branch information
mbrat2005 authored Nov 15, 2023
1 parent 7315fc5 commit c238420
Show file tree
Hide file tree
Showing 35 changed files with 2,121 additions and 350 deletions.
4 changes: 3 additions & 1 deletion AzureBasicLoadBalancerUpgrade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The PowerShell module performs the following functions:
- Migrates Virtual Machine Scale Set and Virtual Machine backend pool members from the Basic Load Balancer to the Standard Load Balancer.
- Creates and associates a network security group with the Virtual Machine Scale Set or Virtual Machine to ensure load balanced traffic reaches backend pool members, following Standard Load Balancer's move to a default-deny network policy.
- Upgrades instance-level Public IP addresses associated with Virtual Machine Scale Set or Virtual Machine instances
- Upgrades Inbound NAT Pools to Inbound NAT Rules for Virtual Machine Scale Set backends. Specify -skipUpgradeNATPoolsToNATRules to skip this upgrade.
- Logs the upgrade operation for easy audit and failure recovery.

>[!WARNING]
Expand Down Expand Up @@ -207,7 +208,8 @@ The script migrates the following from the Basic Load Balancer to the Standard L
- Inbound NAT Rules:
- All user-created NAT rules are migrated to the new Standard Load Balancer
- Inbound NAT Pools:
- All inbound NAT Pools will be migrated to the new Standard Load Balancer
- By default, NAT Pools are upgraded to NAT Rules
- To migrate NAT Pools instead, specify the -skipUpgradeNATPoolsToNATRules parameter when upgrading
- Backend pools:
- All backend pools are migrated to the new Standard Load Balancer
- All Virtual Machine Scale Set and Virtual Machine network interfaces and IP configurations are migrated to the new Standard Load Balancer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
RootModule = 'AzureBasicLoadBalancerUpgrade'

# Version number of this module.
ModuleVersion = '2.3.4'
ModuleVersion = '2.4.0'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down Expand Up @@ -107,7 +107,7 @@
# IconUri = ''

# ReleaseNotes of this module
ReleaseNotes = 'Fix spurious error when calling _HardCopyObject when an IPConfig has no pool membership'
ReleaseNotes = 'Fix NAT Rule backend migration, Add NAT Pool to NAT Rule migration'

# Prerelease string of this module
# Prerelease = ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ function BackendPoolMigrationVM {
$lbBeNicId = ($BackendIpConfiguration.Id -split '/ipConfigurations/')[0]
$ipConfigName = ($BackendIpConfiguration.Id -split '/ipConfigurations/')[1]

# create empty array for this Nic ID if it doesn't exist
If (!$backendPoolNicTable[$lbBeNicId]) {
$backendPoolNicTable[$lbBeNicId] = @(@{ipConfigs = @{} })
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Module manifest for module 'BackupBasicLoadBalancer'
# Module manifest for module 'BackupResources'
#
# Generated by: Victor Santana
#
Expand All @@ -9,7 +9,7 @@
@{

# Script module or binary module file associated with this manifest.
RootModule = 'BackupBasicLoadBalancer'
RootModule = 'BackupResources'

# Version number of this module.
ModuleVersion = '0.1.4'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Load Modules
Import-Module ((Split-Path $PSScriptRoot -Parent) + "/Log/Log.psd1")
Import-Module ((Split-Path $PSScriptRoot -Parent) + "/GetVmssFromBasicLoadBalancer/GetVmssFromBasicLoadBalancer.psd1")

function RestoreLoadBalancer {
[CmdletBinding()]
Expand Down Expand Up @@ -96,16 +97,16 @@ Function BackupVmss {
log -Message "[BackupVmss] Initiating Backup of VMSS to path '$RecoveryBackupPath'"

# Backup VMSS Object
$vmssIds = $BasicLoadBalancer.BackendAddressPools.BackendIpConfigurations.id | Foreach-Object { ($_ -split '/virtualMachines/')[0].ToLower() } | Select-Object -Unique
foreach ($vmssId in $vmssIds) {
$vmsses = GetVmssFromBasicLoadBalancer -BasicLoadBalancer $BasicLoadBalancer
foreach ($vmss in $vmsses) {
$vmssId = $vmss.Id
$message = "[BackupVmss] Attempting to create a file-based backup VMSS with id '$vmssId'"
log -Severity Information -Message $message

$backupDateTime = Get-Date -Format FileDateTime

try {
$ErrorActionPreference = 'Stop'
$vmss = Get-AzResource -ResourceId $vmssId | Get-AzVmss
$outputFileNameVMSS = ('State_VMSS_' + $vmss.Name + "_" + $vmss.ResourceGroupName + "_" + $backupDateTime + ".json")
$outputFilePathVSS = Join-Path -Path $RecoveryBackupPath -ChildPath $outputFileNameVMSS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ function GetVmssFromBasicLoadBalancer {

try {
$ErrorActionPreference = 'Stop'
$vmssId = $BasicLoadBalancer.BackendAddressPools.BackendIpConfigurations.id | Foreach-Object { ($_ -split '/virtualMachines/')[0].ToLower() } | Select-Object -Unique

# check backend pools and nat rules for vmssids
$vmssId = $BasicLoadBalancer.BackendAddressPools.BackendIpConfigurations.id + $BasicLoadBalancer.inboundNatRules.BackendIpConfiguration.id | Foreach-Object {
If (![string]::IsNullOrEmpty($_)) {
($_ -split '/virtualMachines/')[0].ToLower() }
} | Select-Object -Unique

log -Message "[GetVmssFromBasicLoadBalancer] Getting VMSS object '$vmssId' from Azure"
$vmss = Get-AzResource -ResourceId $vmssId | Get-AzVmss
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,17 @@ function InboundNatPoolsMigration {
param (
[Parameter(Mandatory = $True)][Microsoft.Azure.Commands.Network.Models.PSLoadBalancer] $BasicLoadBalancer,
[Parameter(Mandatory = $True)][Microsoft.Azure.Commands.Network.Models.PSLoadBalancer] $StdLoadBalancer,
[Parameter(Mandatory = $True)][Microsoft.Azure.Commands.Compute.Automation.Models.PSVirtualMachineScaleSet] $refVmss
[Parameter(Mandatory = $False)][Microsoft.Azure.Commands.Compute.Automation.Models.PSVirtualMachineScaleSet] $refVmss
)
log -Message "[InboundNatPoolsMigration] Initiating Inbound NAT Pools Migration"

$inboundNatPools = $BasicLoadBalancer.InboundNatPools

If ($inboundNatPools.count -eq 0) {
log -Message "[InboundNatPoolsMigration] Load balancer has no NAT Pools to migrate"
return
}

foreach ($pool in $inboundNatPools) {
log -Message "[InboundNatPoolsMigration] Adding Inbound NAT Pool $($pool.Name) to Standard Load Balancer"
$frontEndIPConfig = Get-AzLoadBalancerFrontendIpConfig -LoadBalancer $StdLoadBalancer -Name ($pool.FrontEndIPConfiguration.Id.split('/')[-1])
Expand Down Expand Up @@ -132,40 +138,49 @@ function InboundNatPoolsMigration {
log 'Warning' $message
}

$vmss = GetVmssFromBasicLoadBalancer -BasicLoadBalancer $BasicLoadBalancer
If ($refVmss) {
log -Message "[InboundNatPoolsMigration] Associating Inbound NAT Pools to VMSS"

_MigrateNetworkInterfaceConfigurations -BasicLoadBalancer $BasicLoadBalancer -StdLoadBalancer $StdLoadBalancer -vmss $vmss -refVmss $refVmss
$vmss = GetVmssFromBasicLoadBalancer -BasicLoadBalancer $BasicLoadBalancer

# Update VMSS on Azure
log -Message "[InboundNatPoolsMigration] Saving VMSS $($vmss.Name)"
try {
$ErrorActionPreference = 'Stop'
_MigrateNetworkInterfaceConfigurations -BasicLoadBalancer $BasicLoadBalancer -StdLoadBalancer $StdLoadBalancer -vmss $vmss -refVmss $refVmss

Update-Vmss -Vmss $vmss
}
catch {
$exceptionType = (($_.Exception.Message -split 'ErrorCode:')[1] -split 'ErrorMessage:')[0].Trim()
if($exceptionType -eq "MaxUnhealthyInstancePercentExceededBeforeRollingUpgrade"){
$message = "[InboundNatPoolsMigration] An error occured when attempting to update VMSS upgrade policy back to $($vmss.UpgradePolicy.Mode). Looks like some instances were not healthy and in orther to change the VMSS upgra policy the majority of instances must be healthy according to the upgrade policy. The module will continue but it will be required to change the VMSS Upgrade Policy manually. `nError message: $_"
log 'Error' $message -terminateOnError
# Update VMSS on Azure
log -Message "[InboundNatPoolsMigration] Saving VMSS $($vmss.Name)"
try {
$ErrorActionPreference = 'Stop'

Update-Vmss -Vmss $vmss
}
else {
$message = "[InboundNatPoolsMigration] An error occured when attempting to update VMSS network config on the new Standard LB backend pool membership. To recover address the following error, and try again specifying the -FailedMigrationRetryFilePath parameter and Basic Load Balancer backup State file located either in this directory or the directory specified with -RecoveryBackupPath. `nError message: $_"
log 'Error' $message -terminateOnError
catch {
$exceptionType = (($_.Exception.Message -split 'ErrorCode:')[1] -split 'ErrorMessage:')[0].Trim()
if($exceptionType -eq "MaxUnhealthyInstancePercentExceededBeforeRollingUpgrade"){
$message = "[InboundNatPoolsMigration] An error occured when attempting to update VMSS upgrade policy back to $($vmss.UpgradePolicy.Mode). Looks like some instances were not healthy and in orther to change the VMSS upgra policy the majority of instances must be healthy according to the upgrade policy. The module will continue but it will be required to change the VMSS Upgrade Policy manually. `nError message: $_"
log 'Error' $message -terminateOnError
}
else {
$message = "[InboundNatPoolsMigration] An error occured when attempting to update VMSS network config on the new Standard LB backend pool membership. To recover address the following error, and try again specifying the -FailedMigrationRetryFilePath parameter and Basic Load Balancer backup State file located either in this directory or the directory specified with -RecoveryBackupPath. `nError message: $_"
log 'Error' $message -terminateOnError
}
}
}

# Update Instances
UpdateVmssInstances -vmss $vmss
# Update Instances
UpdateVmssInstances -vmss $vmss

<#
This will happen in the backend pool migration...
# Restore VMSS Upgrade Policy Mode
#_RestoreUpgradePolicyMode -vmss $vmss -refVmss $refVmss
<#
This will happen in the backend pool migration...
# Restore VMSS Upgrade Policy Mode
#_RestoreUpgradePolicyMode -vmss $vmss -refVmss $refVmss
# Update VMSS on Azure
#Update-Vmss -vmss $vmss
#>

# Update VMSS on Azure
#Update-Vmss -vmss $vmss
#>
log -Message "[InboundNatPoolsMigration] Finished associating Inbound NAT Pools to VMSS"
}
Else {
log -Message "[InboundNatPoolsMigration] No VMSS found associated with Basic Load Balancer (VM or empty backend). Skipping VMSS Inbound NAT Pool association"
}

log -Message "[InboundNatPoolsMigration] Inbound NAT Pools Migration Completed"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#
# Module manifest for module 'Start-AzNATPoolMigration'
#
# Generated by: Matthew Bratschun
#
# Generated on: 3/21/2023
#

@{

# Script module or binary module file associated with this manifest.
RootModule = 'NatPoolToNatRuleMigration'

# Version number of this module.
ModuleVersion = '0.0.0'

# Supported PSEditions
# CompatiblePSEditions = @()

# ID used to uniquely identify this module
GUID = 'ed27ddb0-e430-484e-81b9-1bbeec966b0d'

# Author of this module
Author = 'Matthew Bratschun at FastTrack for Azure'

# Company or vendor of this module
CompanyName = 'Microsoft'

# Copyright statement for this module
Copyright = '(c) 2023 Microsoft. All rights reserved.'

# Description of the functionality provided by this module
Description = 'Migrates an Azure Standard Load Balancer Inbound NAT Pools to Inbound NAT Rules'

# Minimum version of the PowerShell engine required by this module
# PowerShellVersion = ''

# Name of the PowerShell host required by this module
# PowerShellHostName = ''

# Minimum version of the PowerShell host required by this module
# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# ClrVersion = ''

# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()

# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()

# 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 = @('Start-NatPoolToNatRuleMigration')

# 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 = @()

# Variables to export from this module
VariablesToExport = @()

# Aliases 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 aliases to export.
AliasesToExport = @()

# DSC resources to export from this module
# DscResourcesToExport = @()

# List of all modules packaged with this module
# ModuleList = @()

# List of all files packaged with this module
# FileList = @()

# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{

PSData = @{

# Tags applied to this module. These help with module discovery in online galleries.
Tags = 'AzureBasicLoadBalancerUpgrade', 'Azure', 'LoadBalancer', 'Upgrade',
'VMSS', 'Migrate', 'NATPool'

# A URL to the license for this module.
# LicenseUri = ''

# A URL to the main website for this project.
ProjectUri = 'https://github.com/Azure/AzLoadBalancerMigration'

# A URL to an icon representing this module.
# IconUri = ''

# ReleaseNotes of this module
# ReleaseNotes = ''

# Prerelease string of this module
# Prerelease = ''

# Flag to indicate whether the module requires explicit user acceptance for install/update/save
# RequireLicenseAcceptance = $false

# External dependent modules of this module
# ExternalModuleDependencies = @()

} # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module
# HelpInfoURI = ''

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

}

Loading

0 comments on commit c238420

Please sign in to comment.