templates/run.ps1
# Input bindings are passed in via param block. param($Timer) # Get the current universal time in the default string format. $currentUTCtime = (Get-Date).ToUniversalTime() # The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled. if ($Timer.IsPastDue) { Write-Host "PowerShell timer is running late!" } # Write an information log with the current time. Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime" # Write to the Azure Functions log stream. Write-Host "PowerShell HTTP trigger function processed a request." $AzContext = Get-AzContext $KeyVaultName = $env:APPSETTING_KEYVAULT_NAME $SubscriptionId = $AzContext.Subscription.Id $AVSResourceGroupName = $env:APPSETTING_AVS_RESOURCE_GROUP $AVSPrivateCloudName = $env:APPSETTING_AVS_CLOUD_NAME $CBSEndpoint = $env:CBS_ENDPOINT $CBSUsername = Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name "PureCloudBlockStoreUsername" -AsPlainText $CBSPassword = (Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name "PureCloudBlockStorePassword").SecretValue function Connect-CBSArray { param ( [String] $KeyVaultName ) $CBSArrays = @() Import-Module -Name PureStoragePowerShellSDK2 $Secrets = Get-AzKeyVaultSecret -VaultName $KeyVaultName | where-object {$_.Name -like "*-$($KeyVaultName)-username"} foreach ($Secret in $Secrets) { $ArrayName = ($Secret.name -Split "-$($KeyVaultName)-username")[0] $CBSUsername = Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name $Secret.Name -AsPlainText #TODO: Password we got here is plain text. Any security concern? $CBSPassword = Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name "$($ArrayName)-$($KeyVaultName)-password" -AsPlainText $SecureCBSPassword = ConvertTo-SecureString -String $CBSPassword -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList ($CBSUsername, $SecureCBSPassword) # If the string matches the format like "172-168-1-0", the array ip addressed was processed because secret name does not allow "." if ($ArrayName -match "^\d+-\d+-\d+-\d+$") { $ArrayName = $ArrayName.Replace("-", ".") } # TODO: How do we deal with the array failed to connect? $Array = Connect-Pfa2Array -EndPoint $ArrayName -Credential $Credential -IgnoreCertificateError $CBSArrays += $Array } return $CBSArrays } function Get-AVSvCenterEndpoint { param ( [Hashtable] $AuthHeader, [String] $SubscriptionId, [String] $AvsResourceGroupName, [String] $AvsPrivateCloudName ) $RestUri = "https://management.azure.com/subscriptions/$($subscriptionId)/resourceGroups/$($avsResourceGroupName)/providers/Microsoft.AVS/privateClouds/$($avsPrivateCloudName)?api-version=2022-05-01" $Response = Invoke-RestMethod -Uri $restUri -Method Get -Headers $authHeader $VcsaEndpoint = $response.properties.endpoints.vcsa $VcsaIPAddress = [System.Uri]::new($vcsaEndpoint).Host return $vcsaIPAddress } function Get-AVSvCenterCredential { param ( [Hashtable] $AuthHeader, [String] $SubscriptionId, [String] $AvsResourceGroupName, [String] $AvsPrivateCloudName ) $RestUri = "https://management.azure.com/subscriptions/$($subscriptionId)/resourceGroups/$($avsResourceGroupName)/providers/Microsoft.AVS/privateClouds/$($avsPrivateCloudName)/listAdminCredentials?api-version=2022-05-01" $Response = Invoke-RestMethod -Uri $restUri -Method Post -Headers $AuthHeader return $Response } function Connect-AVSvCenter { param ( [String] $AVSvCenterEndpoint, [String] $AVSvCenterUsername, [SecureString] $AVSvCenterPassword ) Set-PowerCLIConfiguration -InvalidCertificateAction:Ignore -Confirm:$false $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList ($AVSvCenterUsername, $AVSvCenterPassword) Connect-VIserver -server $AVSvCenterEndpoint -Credential $Credential } function Get-AzureAuthHeader { param ( $AzContext ) $AzProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile $ProfileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($AzProfile) $Token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId) $AuthHeader = @{ 'Content-Type'='application/json' 'Authorization'='Bearer ' + $token.AccessToken } return $AuthHeader } function Refresh-PCBSCluster { param ( [String] $AvsResourceGroupName, [String] $AvsPrivateCloudName, $CBSArrays ) $Clusters = Get-Cluster $ArrayIscsiAddressMap = @{} foreach ($CBSArray in $CBSArrays) { $EthList = (Get-Pfa2NetworkInterface -Array $CBSArray | Where-Object {$_.services -eq "iscsi"} | Where-Object {$_.enabled -eq $true} | Where-Object {$null -ne $_.Eth.address}).Eth $ISCSIAddressList = @() foreach ($Eth in $EthList) { $ISCSIAddressList += $eth.address } $ArrayIscsiAddressMap[$CBSArray] = $iSCSIAddressList } foreach ($Cluster in $Clusters) { # Build cluster only when there is a matched iscsi address foreach ($Array in $ArrayIscsiAddressMap.Keys) { Write-Host "iscsi $($ArrayIscsiAddressMap[$Array])" $MatchedISCSIAddress = $Cluster | Get-VMHost | Get-VMHostHba -Type iScsi | Get-IScsiHbaTarget | Where-Object {($_.Type -eq "Static") -and ($ArrayIscsiAddressMap[$Array] -contains $_.Address)} $ArrayName = (Get-Pfa2Array -Array $Array).Name if ($MatchedISCSIAddress) { Write-Host "Connection between CBS $ArrayName and cluster $($Cluster.Name) is found. Matched iSCSI address is $MatchedISCSIAddress. Start building cluster..." Build-PCBSCluster -ClusterName $Cluster.Name -AVSCloudName $AVSPrivateCloudName -AVSResourceGroup $AVSResourceGroupName -PureCloudBlockStoreConnection $Array } else { Write-Host "Connection between CBS $ArrayName and cluster $($Cluster.Name) is not found. Skip the array for the cluster" } } } } $CBSArrays = Connect-CBSArray -KeyVaultName $KeyVaultName $AuthHeader = Get-AzureAuthHeader -AzContext $AzContext $AVSvCenterCredential = Get-AVSvCenterCredential -AuthHeader $AuthHeader -SubscriptionId $SubscriptionId -AVSResourceGroupName $AVSResourceGroupName -AVSPrivateCloudName $AVSPrivateCloudName $AVSvCenterEndpoint = Get-AVSvCenterEndpoint -AuthHeader $AuthHeader -SubscriptionId $SubscriptionId -AVSResourceGroupName $AVSResourceGroupName -AVSPrivateCloudName $AVSPrivateCloudName Connect-AVSvCenter -AVSvCenterEndpoint $AVSvCenterEndpoint -AVSvCenterUsername $AVSvCenterCredential.vCenterUsername -AVSvCenterPassword $(ConvertTo-SecureString $AVSvCenterCredential.vCenterPassword -AsPlainText -Force) Write-Host "Start to build cluster..." Refresh-PCBSCluster -AvsPrivateCloudName $AVSPrivateCloudName -AvsResourceGroupName $AVSResourceGroupName -CBSArrays $CBSArrays Write-Host "Build cluster is done!" |