Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ https://learn.microsoft.com/powershell/module/az.connectedkubernetes/new-azconne

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
Justification='Kubernetes is a recognised term', Scope='Function', Target='New-AzConnectedKubernetes')]
[CmdletBinding()]
param()

function New-AzConnectedKubernetes {
Expand Down Expand Up @@ -270,10 +271,13 @@ function New-AzConnectedKubernetes {
${GatewayResourceId}
)

# Write-Debug "Outside of process"

process {
. "$PSScriptRoot/helpers/HelmHelper.ps1"
. "$PSScriptRoot/helpers/ConfigDPHelper.ps1"
. "$PSScriptRoot/helpers/AZCloudMetadataHelper.ps1"
Write-Debug "Debug: Inside of process"
if($AzureHybridBenefit){
if(!$AcceptEULA){
$legalTermPath = Join-Path $PSScriptRoot -ChildPath "LegalTerm.txt"
Expand Down Expand Up @@ -409,7 +413,11 @@ function New-AzConnectedKubernetes {
$ConfigmapRgName = $Configmap.data.AZURE_RESOURCE_GROUP
$ConfigmapClusterName = $Configmap.data.AZURE_RESOURCE_NAME
try {
$ExistConnectedKubernetes = Get-AzConnectedKubernetes -ResourceGroupName $ConfigmapRgName -ClusterName $ConfigmapClusterName @CommonPSBoundParameters
$ExistConnectedKubernetes = Get-AzConnectedKubernetes `
-ResourceGroupName $ConfigmapRgName `
-ClusterName $ConfigmapClusterName `
@CommonPSBoundParameters `
-ErrorAction 'silentlycontinue'

if (($ResourceGroupName -eq $ConfigmapRgName) -and ($ClusterName -eq $ConfigmapClusterName)) {
# This performs a re-PUT of an existing connected cluster which should really be done using
Expand All @@ -423,7 +431,8 @@ function New-AzConnectedKubernetes {
return
} catch {
# This is attempting to delete Azure Arc resources that are orphaned.
helm delete azure-arc --namespace $ReleaseNamespace --kubeconfig $KubeConfig --kube-context $KubeContext
# We are catching and ignoring any messages here.
$null = helm delete azure-arc --ignore-not-found --namespace $ReleaseNamespace --kubeconfig $KubeConfig --kube-context $KubeContext
}
}

Expand Down Expand Up @@ -667,16 +676,35 @@ function New-AzConnectedKubernetes {
$configDpinfo = Get-ConfigDPEndpoint -location $Location -Cloud $cloudMetadata
$configDPEndpoint = $configDpInfo.configDPEndpoint
$adResourceId = $configDpInfo.adResourceId
Invoke-ConfigDPHealthCheck -configDPEndpoint $configDPEndpoint -Resource $adResourceId

# If the health check fails (not 200 response), an exception is thrown
# so we can ignore the output.
$null = Invoke-ConfigDPHealthCheck -configDPEndpoint $configDPEndpoint -Resource $adResourceId

# This call does the "pure ARM" update of the ARM objects.
Write-Debug "Writing Connected Kubernetes ARM objects."
$PSBoundParameters.Add('AgentPublicKeyCertificate', $AgentPublicKey)

# We sometimes see the AgentPublicKeyCertificate present with value $null.
# If this is the case, update rather than adding.
if ($PSBoundParameters.ContainsKey('AgentPublicKeyCertificate')) {
$PSBoundParameters['AgentPublicKeyCertificate'] = $AgentPublicKey
} else {
$PSBoundParameters.Add('AgentPublicKeyCertificate', $AgentPublicKey)
}
$Response = Az.ConnectedKubernetes.internal\New-AzConnectedKubernetes @PSBoundParameters

# Retrieving Helm chart OCI (Open Container Initiative) Artifact location
Write-Debug "Retrieving Helm chart OCI (Open Container Initiative) Artifact location."
$helmValuesDp = Get-HelmValues -configDPEndpoint $configDPEndpoint -releaseTrain $ReleaseTrain -requestBody $Response
Write-Debug "PUT response: $Response"
$ResponseStr = "$Response"
$helmValuesDp = Get-HelmValues `
-configDPEndpoint $configDPEndpoint `
-releaseTrain $ReleaseTrain `
-requestBody $ResponseStr `
-Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
-Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

Write-Debug "helmValuesDp: $helmValuesDp"
Write-Debug "OCI Artifact location: ${helmValuesDp.repositoryPath}."

# Allow a custom OCI registry to be set via environment variables.
Expand All @@ -690,16 +718,17 @@ function New-AzConnectedKubernetes {
# USERPROFILE
#
$registryPath = if ($env:HELMREGISTRY) { $env:HELMREGISTRY } else { $helmValuesDp.repositoryPath }
# !!PDS: Why do these not get logged?
Write-Debug "RegistryPath: ${registryPath}."

$helmContentValues = $helmValuesDp["helmValuesContent"]
Write-Debug "Helm values: ${helmContentValues}."
$helmValuesContent = $helmValuesDp.helmValuesContent
Write-Debug "Helm values: ${helmValuesContent}."

foreach ($key in $helmContentValues.Keys) {
if ($key -in @("global.httpsProxy", "global.httpProxy", "global.noProxy", "global.proxyCert")) {
foreach ($field in $helmValuesContent.PSObject.Properties) {
if ($field.Name -in @("global.httpsProxy", "global.httpProxy", "global.noProxy", "global.proxyCert")) {
continue
}
$options += " --set $Key=$($helmContentValues[$Key])"
$options += " --set $($field.Name)=$($field.Value)"
}

# !!PDS: Is there any telemetry in Powershell cmdlets?
Expand All @@ -719,9 +748,9 @@ function New-AzConnectedKubernetes {
# !!PDS Aren't we supposed to read the helm config from the Cluster Config DP?
# !!PDS: I think we might have done above, but why are we setting many options?
$TenantId = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext.Tenant.Id
Write-Debug $options -ErrorAction Continue
try {
helm upgrade `
--debug `
--install azure-arc `
$ChartPath `
--namespace $ReleaseInstallNamespace `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ https://learn.microsoft.com/powershell/module/az.connectedkubernetes/new-azconne
Justification='Kubernetes is a recognised term', Scope='Function', Target='New-AzConnectedKubernetes')]
param()

function New-AzConnectedKubernetes {
function Set-AzConnectedKubernetes {
[OutputType([Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Models.Api20240701Preview.IConnectedCluster])]
[CmdletBinding(DefaultParameterSetName='CreateExpanded', PositionalBinding=$false, SupportsShouldProcess, ConfirmImpact='Medium')]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,11 @@ function Get-AZCloudMetadataResourceId {
# Search the $armMetadata hash for the entry where the "name" parameter matches
# $cloud and then find the login endpoint, from which we can discern the
# appropriate "cloud based domain ending".
return $cloudMetadata.authentication.audiences[0]
Write-Debug -Message "cloudMetaData in: $($cloudMetaData | ConvertTo-Json -Depth 10)."
return $cloudMetadata.ResourceManagerUrl
}

Function Get-AzCloudMetadata {
param (
[string]$ApiVersion = "2022-09-01"
)

# This is a known endpoint.
$MetadataEndpoint = "https://management.azure.com/metadata/endpoints?api-version=$ApiVersion"

try {
$Response = Invoke-RestMethod -Uri $MetadataEndpoint -Method Get -StatusCodeVariable StatusCode

if ($StatusCode -ne 200) {
$Msg = "ARM metadata endpoint '$MetadataEndpoint' returned status code $($StatusCode)."
throw $Msg
}
}
catch {
$Msg = "Failed to request ARM metadata $MetadataEndpoint."
Write-Error "$Msg Please ensure you have network connection. Error: $_"
}

Comment on lines -18 to -37
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removing this block?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it is replaced by the code below.

# The current cloud in use is set by the user so query it and then we can use
# it to index into the ARM Metadata.
$context = $null
Expand All @@ -47,10 +28,15 @@ Function Get-AzCloudMetadata {
}
$cloudName = $context.Environment.Name

# Search the $armMetadata hash for the entry where the "name" parameter matches
# $cloud and then find the login endpoint, from which we can discern the
# appropriate "cloud based domain ending".
$cloud = $Response | Where-Object { $_.name -eq $cloudName }
try {
# $Response = Invoke-RestMethod -Uri $MetadataEndpoint -Method Get -StatusCodeVariable StatusCode
$cloud = Get-AzureEnvironment -Name $cloudName
}
catch {
Write-Error "Failed to request ARM metadata. Error: $_"
}
Write-Debug -Message "cloudMetaData out: $($cloud | ConvertTo-Json -Depth 10)."

return $cloud
}

Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,16 @@ function Invoke-ConfigDPHealthCheck {
$apiVersion = "2024-07-01-preview"
$chartLocationUrlSegment = "azure-arc-k8sagents/healthCheck?api-version=$apiVersion"
$chartLocationUrl = "$configDPEndpoint/$chartLocationUrlSegment"
$uriParameters = @{}
$uriParameters = [ordered]@{}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ordered?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to be able to test and without "ordered" you cannot be sure what order the resulting URI string will have the parameters in.

$headers = @{}
# Check if key AZURE_ACCESS_TOKEN exists in environment variables
if ($env:AZURE_ACCESS_TOKEN) {
$headers = @{"Authorization"="Bearer $($env['AZURE_ACCESS_TOKEN'])"}
}

# Sending request with retries
# $r = Invoke-RestMethodWithRetries -method 'post' -url $chartLocationUrl -headers $headers -faultType $consts.Get_HelmRegistery_Path_Fault_Type -summary 'Error while performing DP health check' -uriParameters $uriParameters -resource $resource
Invoke-RestMethodWithUriParameters -Method 'post' -Uri $chartLocationUrl -Headers $headers -UriParameters $uriParameters -MaximumRetryCount 5 -RetryIntervalSec 3 -StatusCodeVariable statusCode
if ($statusCode -eq 200) {
Write-Output "Health check for DP is successful."
return $true
}
else {
if ($statusCode -ne 200) {
throw "Error while performing DP health check, StatusCode: ${statusCode}"
}
}
Expand All @@ -53,23 +48,28 @@ function Get-ConfigDPEndpoint {
# $ReleaseTrain = $result.ReleaseTrain
# }

# It is currently not clear what information might appear here in the future
# so the check of "arcConfigEndpoint" is left is a best guess!".
# Get the values or endpoints required for retrieving the Helm registry URL.
if ($cloudMetadata.dataplaneEndpoints -and $cloudMetadata.dataplaneEndpoints.arcConfigEndpoint) {
$ConfigDpEndpoint = $armMetadata.dataplaneEndpoints.arcConfigEndpoint
if ($null -ne $cloudMetadata.ArcConfigEndpoint) {
$ConfigDpEndpoint = $cloudMetadata.ArcConfigEndpoint
}
else {
Write-Debug "'arcConfigEndpoint' doesn't exist under 'dataplaneEndpoints' in the ARM metadata."
Write-Debug "'ArcConfigEndpoint' doesn't exist in the ARM cloud metadata."
}

# Get the default config dataplane endpoint.
if (-not $ConfigDpEndpoint) {
if ($null -eq $ConfigDpEndpoint) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, is $null -eq a standard way?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invoke-ScriptAnalyzer prefers this way around. Not totally sure why but I do know in "C" that this was preferred incase you mistyped if (field == NULL) as if (field = NULL) - both compile but if (NULL = field) will not!

$ConfigDpEndpoint = Get-ConfigDpDefaultEndpoint -Location $Location -CloudMetadata $cloudMetadata
}
$ADResourceId = Get-AZCloudMetadataResourceId -CloudMetadata $cloudMetadata
# !!PDS: This appears to be unused.
# $ADResourceId = Get-AZCloudMetadataResourceId -CloudMetadata $cloudMetadata
$ADResourceId = $null

return @{ ConfigDpEndpoint = $ConfigDpEndpoint; ReleaseTrain = $ReleaseTrain; ADResourceId = $ADResourceId }
}

# !!PDS: What? Looks like there is a function to do this? Perhaps because we did not hide it?
function Get-ConfigDpDefaultEndpoint {
param (
[Parameter(Mandatory=$true)]
Expand All @@ -78,10 +78,13 @@ function Get-ConfigDpDefaultEndpoint {
[PSCustomObject]$cloudMetadata
)

# Search the $armMetadata hash for the entry where the "name" parameter matches
# $cloud and then find the login endpoint, from which we can discern the
# appropriate "cloud based domain ending".
$cloudBasedDomain = ($cloudMetadata.authentication.loginEndpoint -split "\.")[2]
# The DP endpoint uses the same final URL portion as the AAD authority. But
# we also need to trim the trailing "/".
$cloudBasedDomain = ($cloudMetadata.ActiveDirectoryAuthority -split "\.")[2]

# Remove optional trailing "/" from $cloudBasedDomain
$cloudBasedDomain = $cloudBasedDomain.TrimEnd('/')

$configDpEndpoint = "https://${location}.dp.kubernetesconfiguration.azure.${cloudBasedDomain}"
return $configDpEndpoint
}
Expand All @@ -91,7 +94,7 @@ function Invoke-RestMethodWithUriParameters {
[String]$method,
[String]$uri,
[Hashtable]$headers,
[Hashtable]$uriParameters,
[System.Collections.Specialized.OrderedDictionary]$uriParameters,
[String]$requestBody,
[Int]$maximumRetryCount,
[Int]$retryIntervalSec,
Expand All @@ -100,21 +103,33 @@ function Invoke-RestMethodWithUriParameters {

# Add URI parameters to end of URL if there are any.
$uriParametersArray = @()
foreach ($Key in $hash.Keys) {
$uriParametersArray.Add("$($Key)=$($UriParameters[$Key])")
$uriParametersString = $uriParametersArray -join '&'
$uri = "$url?$uriParametersString"
if ($uriParameters.count -gt 0) {
# Create an array by joining hash index and value using '='
$uriParametersArray = $uriParameters.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" }
$uriParametersString = $uriParametersArray -join "&"
$uri = $uri + "?" + $uriParametersString
# Write-Error "URI: >$uri<"
}

# if ($uriParameters.count -gt 0) {
# # Create an array by joining hash index and value using '=' and join them using '&'
# $uriParametersArray = $uriParameters.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" } | ForEach-Object { $_ -join '=' } | ForEach-Object { $_ -join '&' }
# }
Write-Debug "Issue REST request to ${uri} with method ${method} and headers ${headers} and body ${requestBody}"
$rsp = Invoke-RestMethod -Method $method -Uri $uri -Headers $headers -Body $requestBody -ContentType "application/json" -MaximumRetryCount $maximumRetryCount -RetryIntervalSec $retryintervalSec -StatusCodeVariable statusCode
$rsp = Invoke-RestMethod `
-Method $method `
-Uri $uri `
-Headers $headers `
-Body $requestBody `
-ContentType "application/json" `
-MaximumRetryCount $maximumRetryCount `
-RetryIntervalSec $retryintervalSec `
-StatusCodeVariable statusCode `
-Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
-Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

Write-Debug "Response: $($rsp | ConvertTo-Json -Depth 10)"

Set-Variable -Name "${statusCodeVariable}" -Value $statusCode -Scope script
if ($statusCode -ne 200) {
throw "health check failed, StatusCode: ${statusCode}."
}
return $rsp
}
Loading