AksHciNcCompanion.psm1
Import-Module AksHci $script:HostVNetNicName = "SDN_VNET" $script:clsuterGroupName = "clustergroup" $script:MocConfig = $null $script:MocGroup = $null enum AksHciNcResourceType { NetworkInterface LoadBalancer VirtualNetwork } function Invoke-WebRequestWithRetries { param( [System.Collections.IDictionary] $Headers, [string] $ContentType, [Microsoft.PowerShell.Commands.WebRequestMethod] $Method, [System.Uri] $Uri, [object] $Body, [Switch] $DisableKeepAlive, [Switch] $UseBasicParsing, [Parameter(mandatory=$false)] [bool] $shouldRetry = $true ) $params = @{ 'Headers'=$headers; 'ContentType'=$content; 'Method'=$method; 'uri'=$uri; 'ErrorAction'='Stop'; } if($Body -ne $null) { $params.Add('Body', $Body) } if($DisableKeepAlive.IsPresent) { $params.Add('DisableKeepAlive', $true) } if($UseBasicParsing.IsPresent) { $params.Add('UseBasicParsing', $true) } if ($script:DefaultCredParaSet -eq $true) { $params.Add('UseDefaultCredentials', $true) } elseif($script:NetworkControllerCred -ne [System.Management.Automation.PSCredential]::Empty) { $params.Add('Credential', $script:NetworkControllerCred) } $retryIntervalInSeconds = 30 $maxRetry = 6 $retryCounter = 0 do { try { $result = $null $result = Invoke-WebRequest @params break } catch { if($_.Exception.Response.StatusCode.value__ -eq 404) { #Dont retry on Not Found break } $retryCounter++ if($retryCounter -le $maxRetry) { Start-Sleep -Seconds $retryIntervalInSeconds } else { # last retry still fails, so throw the exception throw $_ } } } while ($shouldRetry -and ($retryCounter -le $maxRetry)) return $result } function Initialize-AksHciNcCompanion { $winFeatures = @("RSAT-NetworkController") foreach ($feature in $winFeatures) { Write-Verbose "Check install state of $feature" if ((Get-WindowsFeature -Name $feature).InstallState -ne "Installed") { Write-Verbose "Installing $feature" Add-WindowsFeature -Name $feature -IncludeAllSubFeature -IncludeManagementTools } } } function Get-NCResource { param ( [parameter(Mandatory=$true)] [string] $Uri ) $result = Invoke-WebRequestWithRetries -Uri $Uri -DisableKeepAlive -UseBasicParsing -Method "Get" if(-not $result) { return $null } $toplevel = convertfrom-json $result.Content if ($toplevel.value -eq $null) { $jsonOut = $toplevel } else { $jsonOut = $toplevel.value } return $jsonOut } function Get-NCNic { param ( [parameter(Mandatory=$true)] [string] $resourceId ) Write-Verbose "Fetching nic $resourceId from NC" $mocConfig = Get-MocConfigCache $ncRestEndPoint = $mocConfig["networkControllerFqdnOrIpAddress"] $uri = "https://$ncRestEndPoint/networking/v1/networkinterfaces/$resourceId" $nic = Get-NCResource -Uri $uri if ($nic -eq $null) { $nics = (Invoke-WebRequest -Uri "https://$ncRestEndPoint/networking/v1/networkinterfaces/" -UseBasicParsing).content | ConvertFrom-Json $nic = $nics.value | Where-Object {$_.resourceMetadata.resourceName -eq "$resourceId"} } if ($nic -eq $null) { Write-Warning "Nic with resource id $resourceId not found in NC($ncRestEndPoint)" } return $nic } function Get-NCNicInstanceId { param ( [parameter(Mandatory=$true)] [string] $resourceId ) $nic = Get-NCNic -resourceId $resourceId return $nic.instanceId } function Get-MocConfigCache { if ($null -eq $script:MocConfig) { $script:MocConfig = Get-MocConfig } return $script:MocConfig } function Get-MocGroupCache { if ($null -eq $script:MocGroup) { $script:MocGroup = Get-MocGroup -location MocLocation } return $script:MocGroup } function Clear-MocCache { $script:MocConfig = $null $script:MocGroup = $null } function GetClusterGroup { return $script:clsuterGroupName } function ValidateState { $config = Get-AksHciConfig $aksHciConfig = $config["AksHci"] if ($aksHciConfig["installState"] -ne [InstallState]::Installed) { Write-Error("UnsupportedConfiguration: AKS-HCI is not installed") -ErrorAction Stop } $mocConfig = Get-MocConfigCache if (-not $mocConfig["UseNetworkController"]) { Write-Error("UnsupportedConfiguration: SDN intergration is not present") -ErrorAction Stop } } function CleanupMoc { param ( [parameter(Mandatory=$true)] [string] $nicName ) Remove-MocNetworkInterface -name $nicName -group $(GetClusterGroup) -ErrorAction SilentlyContinue } function CleanupHost { param ( [parameter(Mandatory=$true)] [string] $nicName ) $mocConfig = Get-MocConfigCache $vswitchName = $mocConfig["vswitchName"] $nic = Get-VMNetworkAdapter -ManagementOS -Name $nicName -SwitchName $vswitchName -ErrorAction SilentlyContinue if ($nic -eq $null) { return } Remove-VMNetworkAdapter -ManagementOS -Name $nicName -SwitchName $vswitchName -ErrorAction Stop } function CreateHostVNic { param ( [parameter(Mandatory=$true)] [string] $name, [parameter(Mandatory=$true)] [string] $mac, [parameter(Mandatory=$true)] [string] $ipAddress, [parameter(Mandatory=$true)] [string] $prefix, [parameter(Mandatory=$true)] [string] $vswitchName ) Write-Verbose "Creating a new host vnic $name, MAC $mac, IP $ipAddress/$prefix on host $(hostname)" $nic = Get-VMNetworkAdapter -ManagementOS -Name $name -SwitchName $vswitchName -ErrorAction SilentlyContinue if ($nic -ne $null -and $nic.MacAddress -eq $mac) { Write-Verbose "Reusing existing VNIC " } else { CleanupHost -nicName $name Start-Sleep 5 $nic = Add-VMNetworkAdapter -ManagementOS -Name $name -SwitchName $vswitchName -StaticMacAddress $mac -ErrorAction stop Start-Sleep 30 } $ifIndex = (Get-NetAdapter -Name "*$name*").ifIndex $nic = Get-NetIPAddress -IPAddress $ipAddress -ErrorAction SilentlyContinue if ($nic -ne $null) { if ($nic.InterfaceIndex -ne $ifIndex) { Write-Error "Fatal error, Cannot connect host, $ipAddress is already present on another interface on the host" -ErrorAction Stop } return } Remove-NetIPAddress -InterfaceIndex $ifIndex -Confirm:$false -ErrorAction SilentlyContinue | Out-Null New-NetIPAddress -PrefixLength $prefix -IPAddress $ipAddress -InterfaceIndex $ifIndex -ErrorAction Stop | Out-Null } function CreateMocNic { param ( [parameter(Mandatory=$true)] [string] $nicName ) $mocConfig = Get-MocConfigCache $vnetName = $mocConfig["vnetName"] $location = $mocConfig["cloudLocation"] $retry = $true while($retry) { try { New-MocNetworkInterface -name $nicName -virtualNetworkName $vnetName -group $(GetClusterGroup) -ErrorAction Stop break } catch { $e = $_ $retry = $e.Exception.Message.Contains("PrivateIPAddressInUse") -eq $true if (-not $retry) { Write-Warning "Failed to create Nic in Moc, Error $_" } else { Write-Verbose "IPAddress conflict, retry nic creation" throw } } } } function Get-MocNic { param ( [parameter(Mandatory=$true)] [string] $nicName ) Write-Verbose "Fetching nic $nicName from MOC" $vnetMocNic = Get-MocNetworkInterface -name $nicName -group $(GetClusterGroup) -ErrorAction SilentlyContinue if ($vnetMocNic -eq $null) { Write-Verbose "Creating new nic $nicName in MOC" CreateMocNic -nicName $nicName } return Get-MocNetworkInterface -name $nicName -group $(GetClusterGroup) -ErrorAction SilentlyContinue } function SetPortProfile { param ( [parameter(Mandatory=$true)] [string] $nicName, [parameter(Mandatory=$true)] [string] $profileId ) Write-Verbose "Setting port profile for $nicName on $(hostName), ProfileId $profileId" $vmNic = Get-VMNetworkAdapter -Name $nicName -ManagementOS -ErrorAction Stop $FeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" $CurrentFeature = Get-VMSwitchExtensionPortFeature -FeatureId $FeatureId -VMNetworkAdapter $vmNic if ($CurrentFeature -eq $null) { $Feature = Get-VMSystemSwitchExtensionPortFeature -FeatureId $FeatureId $Feature.SettingData.ProfileId = "{$profileId}" $Feature.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}" $Feature.SettingData.CdnLabelString = "TestCdn" $Feature.SettingData.CdnLabelId = 1111 $Feature.SettingData.ProfileName = "Testprofile" $Feature.SettingData.VendorId = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}" $Feature.SettingData.VendorName = "NetworkController" $Feature.SettingData.ProfileData = 1 Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $Feature -VMNetworkAdapter $vmNic } else { $CurrentFeature.SettingData.ProfileId = "{$profileId}" $CurrentFeature.SettingData.ProfileData = 1 Set-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $CurrentFeature -VMNetworkAdapter $vmNic } Write-Verbose "Successfully set port profile for $nicName on $(hostName)" } function Remove-PortProfile { param ( [parameter(Mandatory=$true)] [string] $nicName ) Write-Verbose "Removing port profile on $nicName" $vmNic = Get-VMNetworkAdapter -Name $nicName -ManagementOS -ErrorAction SilentlyContinue if ($vmNic -eq $null) { return } $FeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" $CurrentFeature = Get-VMSwitchExtensionPortFeature -FeatureId $FeatureId -VMNetworkAdapter $vmNic if ($CurrentFeature -eq $null) { return } Remove-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $CurrentFeature -VMNetworkAdapterName $vmNic } function Connect-AksHciSdnVnet { ValidateState Write-Verbose "Connecting host $(hostname) to the Aks-HCI control plane virtual network" $mocNic = Get-MocNic -nicName $script:HostVNetNicName $ncNic = Get-NCNic -resourceId $script:HostVNetNicName if ($ncNic -eq $null) { Write-Error "Failed to create a VNIC" -ErrorAction Stop } $vswitchName = (Get-MocConfigCache)["vswitchName"] $prefix = $mocNic.properties.ipConfigurations[0].properties.prefixlength $ip = $mocNic.properties.ipConfigurations[0].properties.privateIPAddress CreateHostVNic -name $script:HostVNetNicName -mac $ncNic.properties.privateMacAddress -vswitchName $vswitchName -ipAddress $ip -prefix $prefix SetPortProfile -nicName $script:HostVNetNicName -profileId $ncNic.instanceId } function Disconnect-AksHciSdnVnet { param([switch] $RetainResources) ValidateState Write-Verbose "Disconnecting host $(hostname) from the Aks-HCI control plane virtual network" if ($RetainResources.IsPresent) { Remove-PortProfile -nicName $script:HostVNetNicName return } CleanupHost -nicName $script:HostVNetNicName CleanupMoc -nicName $script:HostVNetNicName } function Remove-AksHciNetworkControllerResources { param( [Parameter(Mandatory = $true, ParameterSetName = 'All')] [switch] $All, [Parameter(Mandatory = $true, ParameterSetName = 'Leaked')] [switch] $Leaked, [Parameter(Mandatory = $true, ParameterSetName = 'All')] [string] $NCRestEndPoint, [switch] $Force ) Initialize-AksHciNcCompanion Clear-MocCache $mocConfig = Get-MocConfigCache if ([string]::IsNullOrWhiteSpace($NCRestEndPoint)) { if ($mocConfig["installState"] -ne [InstallState]::Installed) { throw "Moc is not installed and no NCRestEndPoint was provided" } $NCRestEndPoint = $mocConfig["networkControllerFqdnOrIpAddress"] } # Check that the $NCRestEndPoint is correct. If it is, the test will populate the uri variable $uri = "https://$NCRestEndPoint" if (-not (Test-NetworkControllerFqdnOrIpAddress $uri)) { throw "Cannot connect to Network Controller $NCRestEndPoint" } if ($Leaked.IsPresent) { # Check if MocGroup is configured if ((Get-MocGroupCache).Length -eq 0) { throw "No MocGroup found, cannot find resources in Moc to compare to NetworkController" } if ($mocConfig["installState"] -ne [InstallState]::Installed) { throw "AksHci is not in Installed state, cannot access Moc to compare to NetworkController" } Remove-AksHciNcResourcesLeaked -ConnectionUri $uri -Force:$Force } elseif ($All.IsPresent) { if ($mocConfig["installState"] -ne [InstallState]::NotInstalled) { throw "AksHci is not in NotInstalled state, cannot delete all NC resources" } Remove-AksHciNcResourcesAll -ConnectionUri $uri -Force:$Force } } function Get-MocResourceName { param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [AksHciNcResourceType] $Type ) # Get all the moc groups $mocGroup = Get-MocGroupCache # Return an array of string with the group names $mocGroup = $mocGroup | Select-Object -ExpandProperty name $mocResources = @() switch ($Type) { ([AksHciNcResourceType]::NetworkInterface) { foreach ($group in $mocGroup) { $mocGroupResource = Get-MocNetworkInterface -group $group -ErrorAction Stop # Extract only the name property for each resource in the group and save it $mocGroupResource = $mocGroupResource | Select-Object -ExpandProperty name $mocResources += $mocGroupResource } } ([AksHciNcResourceType]::LoadBalancer) { foreach ($group in $mocGroup) { $mocGroupResource = Get-MocLoadBalancer -group $group -ErrorAction Stop # Extract only the name property for each resource in the group and save it $mocGroupResource = $mocGroupResource | Select-Object -ExpandProperty name $mocResources += $mocGroupResource } } ([AksHciNcResourceType]::VirtualNetwork) { foreach ($group in $mocGroup) { $mocGroupResource = Get-MocVirtualNetwork -group $group -ErrorAction Stop # Extract only the name property for each resource in the group and save it $mocGroupResource = $mocGroupResource | Select-Object -ExpandProperty name $mocResources += $mocGroupResource } } Default { $mocResources = @() } } return $mocResources } function Get-AksHciNcResourceNameAndId { param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [AksHciNcResourceType] $Type, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ConnectionUri ) # Query all Nc resources from the rest api switch ($Type) { ([AksHciNcResourceType]::NetworkInterface) { $ncResponce = Get-NetworkControllerNetworkInterface -ConnectionUri $ConnectionUri } ([AksHciNcResourceType]::LoadBalancer) { $ncResponce = Get-NetworkControllerLoadBalancer -ConnectionUri $ConnectionUri } ([AksHciNcResourceType]::VirtualNetwork) { $ncResponce = Get-NetworkControllerVirtualNetwork -ConnectionUri $ConnectionUri } Default { $ncResponce = $null } } # Remove entries that don't have ResourceMetadata $ncResponce = $ncResponce | Where-Object -Property ResourceMetadata -ne nil # Re-format object to extract ResourceId, ResourceMetadata.Client, ResourceMetadata.ResourceName $ncResponce = $ncResponce | Select-Object ResourceId, @{N="Client";E={$_.ResourceMetadata.Client}}, @{N="ResourceName";E={$_.ResourceMetadata.ResourceName}} # Only select the AksHci Client Objects $ncResponce = $ncResponce | Where-Object -Property Client -eq "AksHci" return $ncResponce } function Remove-NCResource { param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [AksHciNcResourceType] $Type, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ConnectionUri, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ResourceId ) switch ($Type) { ([AksHciNcResourceType]::NetworkInterface) { Remove-NetworkControllerNetworkInterface -ConnectionUri $uri -ResourceId $ResourceId -ErrorAction SilentlyContinue -Force } ([AksHciNcResourceType]::LoadBalancer) { Remove-NetworkControllerLoadBalancer -ConnectionUri $uri -ResourceId $ResourceId -ErrorAction SilentlyContinue -Force } ([AksHciNcResourceType]::VirtualNetwork) { Remove-NetworkControllerVirtualNetwork -ConnectionUri $uri -ResourceId $ResourceId -ErrorAction SilentlyContinue -Force } Default { Write-Error "Network Controller Resource type unknown, cannot delete" } } } function Remove-AksHciNcResourcesLeaked { param( [switch] $Force, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $ConnectionUri ) # go over each resource type and compare Moc to NC foreach ($resType in [AksHciNcResourceType].GetEnumValues()) { $mocResources = Get-MocResourceName -Type $resType $ncResources = Get-AksHciNcResourceNameAndId -ConnectionUri $ConnectionUri -Type $resType if ($mocResources.Length -eq 0) { Write-Error "No $resType resources found in Moc, cannot compare with NetworkController" continue } # Compare the objects $diff = Compare-Object -ReferenceObject $mocResources -DifferenceObject ($ncResources | Select-Object -ExpandProperty ResourceName) # NetworkController resources not found in Moc $ncOnly = $diff | Where-Object -Property SideIndicator -eq "=>" | Select-Object -ExpandProperty InputObject if ($ncOnly.Length -gt 0) { $ncOnlyResourceName = $ncOnly # Expand ncOnly from ResourceName to include ResourceId. This may be a slow operation, for each resource in $ncOnly, # it will search through $ncNetworkInterfaces to find the full object $ncOnly = $ncOnly | ForEach-Object { $ncResources | Where-Object -Property ResourceName -eq $_ } # Prompt user to delete $decision = 1 if (!$Force.IsPresent) { $title = "Delete NetworkController$($resType) Resources" $question = "Are you sure you want to delete the following resources:`n$($ncOnlyResourceName -join "`n")" $choices = @('&Yes', '&No', '&Suspend') $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1) } # Delete the Network Controller resources if ($decision -eq 0 -or $Force.IsPresent) { foreach ($n in $ncOnly) { Remove-NCResource -ConnectionUri $ConnectionUri -Type $resType -ResourceId $n.ResourceId } } # Suspend, exit immediatly elseif ($decision -eq 2) { return } } else { Write-Host "No Leaked NetworkController$($resType) resources found" } } } function Remove-AksHciNcResourcesAll { param( [switch] $Force, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ConnectionUri ) foreach ($resType in [AksHciNcResourceType].GetEnumValues()) { $ncResources = Get-AksHciNcResourceNameAndId -ConnectionUri $ConnectionUri -Type $resType # Prompt user to delete $decision = 1 if (!$Force.IsPresent -and $ncResources.Length -ne 0) { $title = "Delete NetworkController$($resType) Resources" $question = "Are you sure you want to delete the following resources:`n$(($ncResources | Select-Object -ExpandProperty ResourceName) -join "`n")" $choices = @('&Yes', '&No', '&Suspend') $decision = $Host.UI.PromptForChoice($title, $question, $choices, 1) } # Delete the Network Controller resources if ($decision -eq 0 -or $Force.IsPresent) { foreach ($n in $ncResources) { Remove-NCResource -ConnectionUri $ConnectionUri -Type $resType -ResourceId $n.ResourceId } } # Suspend, exit immediatly elseif ($decision -eq 2) { return } } } function Test-AksHciNetworkControllerConfig { # By default, we will use the values in Moc to test NC # If 1 parameter is manually set, all parameters must be supplied and moc will not be used [CmdletBinding(DefaultParameterSetName = 'Moc')] param( [Parameter(Mandatory = $true, ParameterSetName = 'Manual')] [ValidateNotNullOrEmpty()] [string] $networkControllerFqdnOrIpAddress, [Parameter(Mandatory = $true, ParameterSetName = 'Manual')] [ValidateNotNullOrEmpty()] [string] $networkControllerLbSubnetRef, [Parameter(Mandatory = $true, ParameterSetName = 'Manual')] [ValidateNotNullOrEmpty()] [string] $networkControllerLnetRef, [Parameter(Mandatory = $true, ParameterSetName = 'Manual')] [ValidateNotNullOrEmpty()] [VipPoolSettings] $vipPool ) # ----- Setup ----- $useMoc = $PSCmdlet.ParameterSetName -eq "Moc" $ret = $true Clear-MocCache # Read all values from Moc if ($useMoc) { $mocConfig = Get-MocConfigCache # Check that Moc has been initialized if ($mocConfig["installState"] -ne [InstallState]::Installed) { Write-Error "Moc is not in an installed state. Cannot read NetworkController config in Moc" $ret = $false # Cannot continue any more tests without Moc return $ret } # Get networkControllerFqdnOrIpAddress $networkControllerFqdnOrIpAddress = $mocConfig["networkControllerFqdnOrIpAddress"] # Get networkControllerLbSubnetRef $networkControllerLbSubnetRef = $mocConfig["networkControllerLbSubnetRef"] # Get networkControllerLnetRef $networkControllerLnetRef = $mocConfig["networkControllerLnetRef"] # Get vipPool $vipPoolDefaultName = $mocConfig["defaultvippoolname"] $vipPoolDefault = Get-MocVipPool -location MocLocation -name $vipPoolDefaultName $vipPool = [VipPoolSettings]::new($vipPoolDefault.name, $vipPoolDefault.properties.startIp, $vipPoolDefault.properties.endIp) } # ----- Tests ----- # Check networkControllerFqdnOrIpAddress Write-Verbose "Check networkControllerFqdnOrIpAddress" $uri = "https://$networkControllerFqdnOrIpAddress" $result = Test-NetworkControllerFqdnOrIpAddress $uri if (-not $result) { Write-Error "Cannot connect to NetworkController with the networkControllerFqdnOrIpAddress $networkControllerFqdnOrIpAddress" $ret = $false # Cannot test any more without the Network Controller Uri return $ret } # Check networkControllerLnetRef Write-Verbose "Check networkControllerLnetRef" $result = Test-NetworkControllerReference $uri $networkControllerLnetRef if (-not $result) { Write-Error "networkControllerLnetRef ($networkControllerLnetRef) cannot be found in the Network Controller" $ret = $false } # Check networkControllerLbSubnetRef Write-Verbose "Check networkControllerLbSubnetRef" $lbSubnetWebResult = $null $result = Test-NetworkControllerReference $uri $networkControllerLbSubnetRef ([ref]$lbSubnetWebResult) if (-not $result) { Write-Error "networkControllerLbSubnetRef ($networkControllerLbSubnetRef) cannot be found in the Network Controller" $ret = $false } # Check the vipPool -- uses previous networkControllerLbSubnetRef result Write-Verbose "Check vippool setting" if ($null -ne $lbSubnetWebResult) { $result = Test-NetworkControllerDefaultVipPool ($lbSubnetWebResult.Content) $vipPool if (-not $result) { Write-Error "AksHci Vippool ip range is not within the NetworkController Vippool range" $ret = $false } } else { Write-Warning "Skipping Vippool Test, lb Subnet Ref not found in Network Controller" } return $ret } function Test-NetworkControllerFqdnOrIpAddress([string]$ConnectionUri) { try { $result = Invoke-WebRequest -Uri "$ConnectionUri/networking/discovery" } catch { $result = $null } if ($null -eq $result) { return $false } return $result.StatusCode -eq 200 } function Test-NetworkControllerReference([string]$ConnectionUri, [string]$subRef, [ref]$webResult) { $uri = "$ConnectionUri/networking/v1$subRef" $result = Invoke-WebRequest -Uri $uri if ($null -eq $result -or $result.StatusCode -ne 200) { return $false } # set the webResult if it was passed if ($null -ne $webResult) { $webResult.Value = $result } return $true } function Test-NetworkControllerDefaultVipPool([string]$lbSubnetContent, [VipPoolSettings]$mocVipPool) { $ncVippool = (ConvertFrom-Json -InputObject $lbSubnetContent).Properties.ipPools.Properties if ([string]::IsNullOrWhiteSpace($ncVippool)) { return $false } # check that the IP addresses are in the following order # NCVippoolStart -> MocVippoolStart -> MocVippoolEnd -> NCVippoolEnd return ( [AKSHCI.IPUtilities]::ValidateRange($ncVippool.startIpAddress, $vipPool.VipPoolStart) -and [AKSHCI.IPUtilities]::ValidateRange($vipPool.VipPoolStart, $vipPool.VipPoolEnd) -and [AKSHCI.IPUtilities]::ValidateRange($vipPool.VipPoolEnd, $ncVippool.endIpAddress) ) } |