Skip to content

Commit a6bab55

Browse files
authored
Add NAT Rule Only VM Check (#144)
* add validation check for mixed lb and as membership * add nat rule only vm check
1 parent f6c3095 commit a6bab55

File tree

4 files changed

+411
-41
lines changed

4 files changed

+411
-41
lines changed

AzureBasicLoadBalancerUpgrade/module/AzureBasicLoadBalancerUpgrade/AzureBasicLoadBalancerUpgrade.psd1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
RootModule = 'AzureBasicLoadBalancerUpgrade'
1313

1414
# Version number of this module.
15-
ModuleVersion = '2.4.24'
15+
ModuleVersion = '2.5.0'
1616

1717
# Supported PSEditions
1818
# CompatiblePSEditions = @()
@@ -107,7 +107,7 @@
107107
# IconUri = ''
108108

109109
# ReleaseNotes of this module
110-
ReleaseNotes = 'Added validation check for VM mixed LB backend pool and availability set membership.'
110+
ReleaseNotes = 'Add check for NAT Rule member VMs outside backend pools on external LBs.'
111111

112112
# Prerelease string of this module
113113
# Prerelease = 'beta'

AzureBasicLoadBalancerUpgrade/module/AzureBasicLoadBalancerUpgrade/modules/ValidateScenario/ValidateScenario.psm1

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,31 @@ function _GetScenarioBackendType {
7979
return $backendType
8080
}
8181

82+
function _GetBackendMemberNicAndVM {
83+
param(
84+
[Parameter(Mandatory = $true)]
85+
$backendIpConfigurationId
86+
)
87+
88+
$nic = Get-AzNetworkInterface -ResourceId ($backendIpConfigurationId -split '/ipconfigurations/')[0]
89+
90+
If (!$nic.VirtualMachineText) {
91+
log -ErrorAction Stop -Severity 'Error' -Message "[Test-SupportedMigrationScenario] Load balancer '$($BasicLoadBalancer.Name)' backend pool member network interface '$($nic.id)' does not have an associated Virtual Machine. Backend pool members must be either a VMSS NIC or a NIC attached to a VM!"
92+
return
93+
}
94+
Else {
95+
# add VM resources to array for later validation
96+
try {
97+
$vm = Get-AzVM -ResourceId $nic.VirtualMachine.id -ErrorAction Stop
98+
}
99+
catch {
100+
log -terminateOnError -Severity 'Error' -Message "[Test-SupportedMigrationScenario] Error getting VM from NIC '$($nic.id)'. Error: $($_.Exception.Message)"
101+
}
102+
103+
return $vm,$nic
104+
}
105+
}
106+
82107
Function Test-SupportedMigrationScenario {
83108
[CmdletBinding()]
84109
param (
@@ -406,29 +431,65 @@ Function Test-SupportedMigrationScenario {
406431
# create array of VMs associated with the load balancer for following checks and verify that NICs are associated to VMs
407432
$basicLBVMs = @()
408433
$basicLBVMNics = @()
434+
$backendPoolVMs = @()
435+
$natRuleOnlyVMs = @()
409436
foreach ($backendAddressPool in $BasicLoadBalancer.BackendAddressPools) {
410437
foreach ($backendIpConfiguration in $backendAddressPool.BackendIpConfigurations) {
411-
$nic = Get-AzNetworkInterface -ResourceId ($backendIpConfiguration.Id -split '/ipconfigurations/')[0]
412-
413-
If (!$nic.VirtualMachineText) {
414-
log -ErrorAction Stop -Severity 'Error' -Message "[Test-SupportedMigrationScenario] Load balancer '$($BasicLoadBalancer.Name)' backend pool member network interface '$($nic.id)' does not have an associated Virtual Machine. Backend pool members must be either a VMSS NIC or a NIC attached to a VM!"
415-
return
438+
$vm,$nic = _GetBackendMemberNicAndVM -backendIpConfigurationId $backendIpConfiguration.Id
439+
440+
$basicLBVMs += $vm
441+
$backendPoolVMs += $vm
442+
$basicLBVMNics += $nic
443+
}
444+
}
445+
## add VMs associcated directly to inbound NAT rules
446+
foreach ($natRule in $BasicLoadBalancer.InboundNatRules) {
447+
foreach ($natRuleBackendIpConfiguration in $natRule.BackendIpConfiguration) {
448+
$vm,$nic = _GetBackendMemberNicAndVM -backendIpConfigurationId $natRuleBackendIpConfiguration.Id
449+
450+
If ($vm.id -notin $backendPoolVMs.id) {
451+
$natRuleOnlyVMs += $vm
416452
}
417-
Else {
418-
# add VM resources to array for later validation
419-
try {
420-
$basicLBVMs += Get-AzVM -ResourceId $nic.VirtualMachine.id -ErrorAction Stop
421-
}
422-
catch {
423-
log -terminateOnError -Severity 'Error' -Message "[Test-SupportedMigrationScenario] Error getting VM from NIC '$($nic.id)'. Error: $($_.Exception.Message)"
424-
}
425453

426-
# add VM nics to array for later validation
427-
$basicLBVMNics += $nic
454+
$basicLBVMs += $vm
455+
$basicLBVMNics += $nic
456+
}
457+
}
458+
459+
# check if LB backend VMs does not have public IPs
460+
log -Message "[Test-SupportedMigrationScenario] Checking if backend VMs have public IPs..."
461+
$AnyVMsHavePublicIP = $false
462+
$AllVMsHavePublicIPs = $true
463+
ForEach ($VM in $basicLBVMs) {
464+
$VMHasPublicIP = $false
465+
:vmNICs ForEach ($nicId in $VM.NetworkProfile.NetworkInterfaces.Id) {
466+
$nicConfig = Get-AzResource -Id $nicId | Get-AzNetworkInterface
467+
ForEach ($ipConfig in $nicConfig.ipConfigurations) {
468+
If ($ipConfig.PublicIPAddress.Id) {
469+
$AnyVMsHavePublicIP = $true
470+
$VMHasPublicIP = $true
471+
472+
break :vmNICs
473+
}
428474
}
429475
}
476+
If (!$VMHasPublicIP) {
477+
$AllVMsHavePublicIPs = $false
478+
}
430479
}
431480

481+
# check that all NAT Rule associated VMs are also in backend pools for external LBs
482+
log -Message "[Test-SupportedMigrationScenario] Checking that all NAT Rule associated VMs are also in backend pools for external LBs or have Public IPs"
483+
If ($scenario.ExternalOrInternal -eq 'External' -and $natRuleOnlyVMs -and !$AllVMsHavePublicIPs) {
484+
485+
$message = "[Test-SupportedMigrationScenario] The following VMs are associated with Inbound NAT Rules but not in the backend pool of the Basic Load Balancer: '$($natRuleOnlyVMs.Id -join ', ')' and not all VMs have Public IP addresses. All NAT Rule associated VMs must have public IPs associated or be in the backend pool of the Basic Load Balancer to have outbound network connectivity post-migration. Either add Public IPs to all VMs or re-run with the -Force parameter and configure outbound connectivity post-migration."
486+
log -Message $message -Severity 'Error' -terminateOnError:$(!$force)
487+
488+
if ($force) {
489+
log -Message "[Test-SupportedMigrationScenario] -Force or -ValidateOnly parameter was used, so continuing with migration validation"
490+
}
491+
}
492+
432493
# check if load balancer backend pool contains VMs which are part of another LBs backend pools
433494
log -Message "[Test-SupportedMigrationScenario] Checking if backend pools contain members which are members of another load balancer's backend pools..."
434495

@@ -464,28 +525,6 @@ Function Test-SupportedMigrationScenario {
464525
log -Message "[Test-SupportedMigrationScenario] All VM load balancer associations are with the Basic LB(s) to be migrated." -Severity Information
465526
}
466527

467-
# check if internal LB backend VMs does not have public IPs
468-
log -Message "[Test-SupportedMigrationScenario] Checking if backend VMs have public IPs..."
469-
$AnyVMsHavePublicIP = $false
470-
$AllVMsHavePublicIPs = $true
471-
ForEach ($VM in $basicLBVMs) {
472-
$VMHasPublicIP = $false
473-
:vmNICs ForEach ($nicId in $VM.NetworkProfile.NetworkInterfaces.Id) {
474-
$nicConfig = Get-AzResource -Id $nicId | Get-AzNetworkInterface
475-
ForEach ($ipConfig in $nicConfig.ipConfigurations) {
476-
If ($ipConfig.PublicIPAddress.Id) {
477-
$AnyVMsHavePublicIP = $true
478-
$VMHasPublicIP = $true
479-
480-
break :vmNICs
481-
}
482-
}
483-
}
484-
If (!$VMHasPublicIP) {
485-
$AllVMsHavePublicIPs = $false
486-
}
487-
}
488-
489528
# check if some backend VMs have ILIPs but not others
490529
If ($AnyVMsHavePublicIP -and !$AllVMsHavePublicIPs -and $Scenario.ExternalOrInternal -eq 'External') {
491530
$message = "[Test-SupportedMigrationScenario] Some but not all load balanced VMs have instance-level Public IP addresses and the load balancer is external. It is not supported to create an Outbound rule on a LB when any backend VM has a PIP; therefore, VMs which do not have PIPs will loose outbound internet connecticity post-migration."
@@ -580,7 +619,7 @@ Function Test-SupportedMigrationScenario {
580619
}
581620

582621
# check if backend VMs are part of an Availability Set and if there are other members of the same availability set which are not part of the load balancer backend pool or inbound nat pools
583-
log -Message "[Test-SupportedMigrationScenario] Checking if backend VMs are part of an Availability Set and if there are other members of the same availability set which are not part of the load balancer backend pool..."
622+
log -Message "[Test-SupportedMigrationScenario] Checking if backend VMs are part of an Availability Set and if there are other members of the same availability set which are not part of the load balancer backend pool, NAT pool, or associated with NAT Rules..."
584623
$availabilitySetVMs = @()
585624
$availabilitySetReference = $basicLBVMs | Where-Object { $_.AvailabilitySetReference -ne $null } | Select-Object -ExpandProperty AvailabilitySetReference
586625

@@ -590,7 +629,7 @@ Function Test-SupportedMigrationScenario {
590629
$extraAvailabilitySetVMs = $availabilitySetVMs | Where-Object { $_ -notin $basicLBVMs.Id } | Sort-Object | Get-Unique
591630

592631
If ($extraAvailabilitySetVMs) {
593-
$message = "[Test-SupportedMigrationScenario] VMs ('$($extraAvailabilitySetVMs -join ';')') are part of an Availability Set and there are other members of the same Availability Set which are part of the load balancer backend pools. This is not supported for migration. To work around this, create a new backend pool on the basic LB which is not associated with a load balancing rule and add the extra VMs to it temporarily, then retry migration."
632+
$message = "[Test-SupportedMigrationScenario] VMs ('$($extraAvailabilitySetVMs -join ';')') belong(s) to an Availability Set and there are other members of the same Availability Set which are part of the load balancer backend pools, NAT pools, or associated with NAT Rules. This is not supported for migration. To work around this, create a new backend pool on the basic LB which is not associated with a load balancing rule and add the extra VMs to it temporarily, then retry migration."
594633
log -Message $message -Severity 'Error' -terminateOnError
595634
}
596635
Else {
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
targetScope = 'subscription'
2+
param location string
3+
param resourceGroupName string
4+
param randomGuid string = newGuid()
5+
6+
// Resource Group
7+
module rg '../modules/Microsoft.Resources/resourceGroups/deploy.bicep' = {
8+
name: '${resourceGroupName}-${location}'
9+
params: {
10+
name: resourceGroupName
11+
location: location
12+
}
13+
}
14+
15+
// vnet
16+
module virtualNetworks '../modules/Microsoft.Network/virtualNetworks/deploy.bicep' = {
17+
name: '${uniqueString(deployment().name)}-virtualNetworks'
18+
scope: resourceGroup(resourceGroupName)
19+
params: {
20+
// Required parameters
21+
location: location
22+
addressPrefixes: [
23+
'10.0.0.0/16'
24+
]
25+
name: 'vnet-01'
26+
subnets: [
27+
{
28+
name: 'subnet-01'
29+
addressPrefix: '10.0.1.0/24'
30+
}
31+
]
32+
}
33+
dependsOn: [
34+
rg
35+
]
36+
}
37+
38+
module publicIp01 '../modules/Microsoft.Network/publicIPAddresses/deploy.bicep' = {
39+
name: 'pip-01'
40+
params: {
41+
name: 'pip-01'
42+
location: location
43+
publicIPAddressVersion: 'IPv4'
44+
skuTier: 'Regional'
45+
skuName: 'Basic'
46+
publicIPAllocationMethod: 'Dynamic'
47+
}
48+
scope: resourceGroup(resourceGroupName)
49+
dependsOn: [
50+
rg
51+
]
52+
}
53+
54+
// basic lb
55+
module loadbalancer '../modules/Microsoft.Network/loadBalancers_custom/deploy.bicep' = {
56+
name: 'lb-basic01'
57+
scope: resourceGroup(resourceGroupName)
58+
params: {
59+
name: 'lb-basic-01'
60+
location: location
61+
frontendIPConfigurations: [
62+
{
63+
name: 'fe-01'
64+
publicIPAddressId: publicIp01.outputs.resourceId
65+
}
66+
]
67+
backendAddressPools: []
68+
inboundNatRules: [
69+
{
70+
name: 'nat-01'
71+
frontendIPConfigurationName: 'fe-01'
72+
frontendPort: 81
73+
backendPort: 81
74+
protocol: 'Tcp'
75+
}
76+
]
77+
loadBalancerSku: 'Basic'
78+
loadBalancingRules: [
79+
]
80+
probes: [
81+
{
82+
intervalInSeconds: 5
83+
name: 'probe-01'
84+
numberOfProbes: 2
85+
port: '80'
86+
protocol: 'Tcp'
87+
}
88+
]
89+
}
90+
dependsOn: [
91+
rg
92+
]
93+
}
94+
95+
module storageAccounts '../modules/Microsoft.Storage/storageAccounts/deploy.bicep' = {
96+
name: 'bootdiag-storage-01'
97+
scope: resourceGroup(resourceGroupName)
98+
params: {
99+
name: 'bootdiag${uniqueString(deployment().name)}'
100+
location: location
101+
storageAccountSku: 'Standard_LRS'
102+
storageAccountKind: 'StorageV2'
103+
supportsHttpsTrafficOnly: true
104+
}
105+
dependsOn: [
106+
rg
107+
]
108+
}
109+
110+
module availabilitySet '../modules/Microsoft.Compute/availabilitySets/deploy.bicep' = {
111+
scope: resourceGroup(resourceGroupName)
112+
name: 'as-01'
113+
params: {
114+
location: location
115+
name: 'as-01'
116+
}
117+
dependsOn: [
118+
rg
119+
]
120+
}
121+
122+
module vm '../modules/Microsoft.Compute/virtualMachines_custom/deploy.bicep' = {
123+
scope: resourceGroup(resourceGroupName)
124+
name: 'vm-01'
125+
params: {
126+
name: 'vm-01'
127+
adminUsername: 'admin-vm'
128+
adminPassword: '${uniqueString(randomGuid)}rpP@340'
129+
availabilitySetResourceId: availabilitySet.outputs.resourceId
130+
location: location
131+
imageReference: {
132+
offer: 'WindowsServer'
133+
publisher: 'MicrosoftWindowsServer'
134+
sku: '2022-Datacenter'
135+
version: 'latest'
136+
}
137+
nicConfigurations: [
138+
{
139+
location: location
140+
ipConfigurations: [
141+
{
142+
name: 'ipconfig1'
143+
subnetResourceId: virtualNetworks.outputs.subnetResourceIds[0]
144+
loadBalancerInboundNatRules: [
145+
{
146+
id: '${loadbalancer.outputs.resourceId}/inboundNatRules/nat-01'
147+
}
148+
]
149+
}
150+
]
151+
nicSuffix: 'nic'
152+
}
153+
]
154+
osDisk: {
155+
createOption: 'fromImage'
156+
diskSizeGB: '128'
157+
managedDisk: {
158+
storageAccountType: 'Standard_LRS'
159+
}
160+
}
161+
osType: 'Windows'
162+
vmSize: 'Standard_DS1_v2'
163+
}
164+
}

0 commit comments

Comments
 (0)