AksHciSDNHostConnector.psm1
Import-Module AksHci $script:HostVNetNicName = "SDN_VNET" $script:clsuterGroupName = "clustergroup" $script:MocConfig = $null 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 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 ($script:MocConfig -eq $null) { $script:MocConfig = Get-MocConfig } return $script:MocConfig } function GetClusterGroup { return $script:clsuterGroupName } function ValidateState { $config = Get-AksHciConfig $aksHciConfig = $config["AksHci"] if ($aksHciConfig["installState"] -ne "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 } |