install_utils.ps1
Function Get-ZertoOVAFile { param ( [Parameter(Mandatory=$true, HelpMessage = "MyZerto Token")] [string]$MyZertoToken ) process { $LocalFolderPath = Get-Location try { Write-Host "Getting Zerto download links" $ZertoUrlsJson = Get-ZertoDownloadLinksFromMyZerto -Token $MyZertoToken Write-Host "Parsing download links for file names" $OvaPresignedUrl = $ZertoUrlsJson.data.files.ova_file $OvaSignaturePresignedUrl = $ZertoUrlsJson.data.files.ova_signature $OvaFileName = Get-FileNameFromDownloadLink -Url $OvaPresignedUrl $OvaSignatureFileName = Get-FileNameFromDownloadLink -Url $OvaSignaturePresignedUrl $OvaFilePath = Join-Path -Path "$LocalFolderPath" -ChildPath "$OvaFileName" $OvaSignatureFilePath = Join-Path -Path "$LocalFolderPath" -ChildPath "$OvaSignatureFileName" Write-Host "Downloading OVA file $OvaFileName, this process might take a while, please wait ..." Download-File -FileUrl $OvaPresignedUrl -LocalFilePath $OvaFilePath Write-Host "Downloading OVA signature file $OvaSignatureFileName" Download-File -FileUrl $OvaSignaturePresignedUrl -LocalFilePath $OvaSignatureFilePath } catch { Write-Error "Failed download Zerto OVA file, exception = $_" -ErrorAction Stop } if ((Validate-FileBySignature -FilePath $OvaFilePath -SignatureFilePath $OvaSignatureFilePath) -ne $true){ Write-Error "OVA or signature file validation failed." -ErrorAction Stop } return $OvaFilePath } } Function Get-ZertoDownloadLinksFromMyZerto { param ( [Parameter(Mandatory=$true, HelpMessage = "My Zerto Zoken")] [string]$Token ) Process{ Write-Host "Starting $($MyInvocation.MyCommand)" try { $Url = "https://www.zerto.com/myzerto/wp-json/services/zerto/s3-ova?key=" + $Token $Response = Invoke-WebRequest -Uri $Url -SkipCertificateCheck -ErrorAction Stop -TimeoutSec 1800 | ConvertFrom-Json } catch { $ErrorMessage = $_ if ($ErrorMessage -match "invalid_key") { Write-Error "Failed to retrieve download files for the ZVM Appliance, invalid token" -ErrorAction Stop } else { Write-Host $ErrorMessage Write-Error "Failed to retrieve download files for the ZVM Appliance" -ErrorAction Stop } } Write-Host "Download JSON file with URLs completed successfully" return $Response } } Function Download-File { param ( [Parameter(Mandatory=$true, HelpMessage = "file url to download from")] [string]$FileUrl, [Parameter(Mandatory=$true, HelpMessage = "local file path")] [string]$LocalFilePath ) Process { Write-Host "Starting $($MyInvocation.MyCommand)" if (Test-Path "$LocalFilePath"){ Write-Host "$LocalFilePath already exists. Skipping download" return } try { $start_time = Get-Date Invoke-WebRequest $FileUrl -OutFile $LocalFilePath -ErrorAction Stop -TimeoutSec 10800 -Resume -SkipCertificateCheck } catch { Write-Error "Failed download $FileUrl, exception = $_" -ErrorAction Stop } Write-Host "Zerto download was completed successfully, duration: $((Get-Date).Subtract($start_time).TotalSeconds) second(s)" } } Function Get-FileNameFromDownloadLink { param ( [Parameter(Mandatory=$true, HelpMessage = "file url to download from")] [string] $Url ) Process { try { $uri = New-Object System.Uri($url) $FileName = [System.IO.Path]::GetFileName($uri.LocalPath) return $FileName } catch { throw "Failed getting file name from $Url, exception = $_" } } } Function Deploy-Vm { param( [Parameter(Mandatory=$true, HelpMessage = "Path for the OVA file")] [ValidateNotNullOrEmpty()][string] $OvaPath, [Parameter(Mandatory=$true, HelpMessage = "Host Name")] [ValidateNotNullOrEmpty()][string] $VMHostName, [Parameter(Mandatory=$true, HelpMessage = "Datastore Name")] [ValidateNotNullOrEmpty()][string] $DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Zvm IP address")] [ValidateNotNullOrEmpty()][string] $ZVMLIp, [Parameter(Mandatory=$true, HelpMessage="Network name for ZVML")] [ValidateNotNullOrEmpty()][string] $NetworkName, [Parameter(Mandatory = $true, HelpMessage = "SubnetMask address")] [ValidateNotNullOrEmpty()][string] $SubnetMask, [Parameter(Mandatory = $true, HelpMessage = "Default gateway")] [ValidateNotNullOrEmpty()][string] $DefaultGateway, [Parameter(Mandatory = $true, HelpMessage = "DNS server address")] [ValidateNotNullOrEmpty()][string] $DNS, [Parameter(Mandatory = $true, HelpMessage = "Azure Tenant Id, Globally unique identifier, found in Azure portal")] [ValidateNotNullOrEmpty()][string] $AzureTenantId, [Parameter(Mandatory = $true, HelpMessage = "Azure Client ID - Application ID, found in Azure portal")] [ValidateNotNullOrEmpty()][string] $AzureClientID, [Parameter(Mandatory = $true, HelpMessage = "Enables authentication to Azure Active Directory using a client secret")] [ValidateNotNullOrEmpty()][SecureString] $AvsClientSecret, [Parameter(Mandatory = $true, HelpMessage = "The ID of the target subscription")] [ValidateNotNullOrEmpty()][string] $AvsSubscriptionId, [Parameter(Mandatory = $true, HelpMessage = "AVS resources that are all in the same AVS Region")] [ValidateNotNullOrEmpty()][string] $AvsResourceGroup, [Parameter(Mandatory = $true, HelpMessage = "Private cloud name")] [ValidateNotNullOrEmpty()][string] $AvsCloudName, [Parameter(Mandatory=$true, HelpMessage= "Configure ovf Properties")] [bool]$ConfigureOvfProperties ) Process { try { Write-Host "Starting $($MyInvocation.MyCommand)" $ovfConfig = Set-OvfProperties -ConfigureOvfProperties $ConfigureOvfProperties -OvaPath $OvaPath -ZVMLIp $ZVMLIp -NetworkName $NetworkName -SubnetMask $SubnetMask -DefaultGateway $DefaultGateway -DNS $DNS $datastore = Get-Datastore -Name $DatastoreName $host = Get-VMHost -Name $VMHostName Write-Host "The deployment process might take a while, please wait ..." $start_time = Get-Date Import-VApp -Source $OvaPath -OvfConfiguration $ovfConfig -Name $ZVM_VM_NAME -VMHost $host -Datastore $datastore -ErrorAction stop | Out-Null Write-Host "$ZVM_VM_NAME was deployed succesfully, duration: $((Get-Date).Subtract($start_time).TotalSeconds) second(s)" if ($ConfigureOvfProperties -eq $true) { Set-Platform-OvfProperties -AzureTenantId $AzureTenantId -AzureClientID $AzureClientID -AvsClientSecret $AvsClientSecret -AvsSubscriptionId $AvsSubscriptionId -AvsResourceGroup $AvsResourceGroup -AvsCloudName $AvsCloudName } } catch { Write-Error "Failed to deploy $ZVM_VM_NAME ZVML, exception = $_" -ErrorAction Stop } } } Function Set-Platform-OvfProperties{ param( [Parameter(Mandatory = $true, HelpMessage = "Azure Tenant Id, Globally unique identifier, found in Azure portal")] [ValidateNotNullOrEmpty()][string] $AzureTenantId, [Parameter(Mandatory = $true, HelpMessage = "Azure Client ID - Application ID, found in Azure portal")] [ValidateNotNullOrEmpty()][string] $AzureClientID, [Parameter(Mandatory = $true, HelpMessage = "Enables authentication to Azure Active Directory using a client secret")] [ValidateNotNullOrEmpty()][SecureString] $AvsClientSecret, [Parameter(Mandatory = $true, HelpMessage = "The ID of the target subscription")] [ValidateNotNullOrEmpty()][string] $AvsSubscriptionId, [Parameter(Mandatory = $true, HelpMessage = "AVS resources that are all in the same AVS Region")] [ValidateNotNullOrEmpty()][string] $AvsResourceGroup, [Parameter(Mandatory = $true, HelpMessage = "Private cloud name")] [ValidateNotNullOrEmpty()][string] $AvsCloudName ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." try { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($ZVM -eq $null) { Write-Error "$ZVM_VM_NAME doesn't exists" -ErrorAction Stop } else { $vappProperties = $ZVM.ExtensionData.Config.VAppConfig.Property # Create a new Update spec based on the # of OVF properties to update $spec = New-Object VMware.Vim.VirtualMachineConfigSpec $spec.vAppConfig = New-Object VMware.Vim.VmConfigSpec $propertySpec = New-Object VMware.Vim.VAppPropertySpec[](10) #Starting from, the last property Key of VM. Otherwise, we will override existing properties $array = $vappProperties | Sort-Object -Property Key -Descending $propertyKey = $array[0].Key + 1 # AVS properties $AzureTenantIdProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $AzureTenantId -PropertyId "AzureTenantId" -PropertyType "string" $propertySpec+=($AzureTenantIdProperty) $AzureClientIDProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $AzureClientID -PropertyId "AzureClientID" -PropertyType "string" $propertySpec+=($AzureClientIDProperty) # TODO: Pavlo, is this working? $AvsClientSecretProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue (ConvertFrom-SecureString -SecureString $AvsClientSecret -AsPlainText) -PropertyId "AvsClientSecret" -PropertyType "password" $propertySpec+=($AvsClientSecretProperty) $AvsSubscriptionIdProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $AvsSubscriptionId -PropertyId "AvsSubscriptionId" -PropertyType "string" $propertySpec+=($AvsSubscriptionIdProperty) $AvsAvsResourceGroupProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $AvsResourceGroup -PropertyId "AvsResourceGroup" -PropertyType "string" $propertySpec+=($AvsAvsResourceGroupProperty) $AvsCloudNameProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $AvsCloudName -PropertyId "AvsCloudName" -PropertyType "string" $propertySpec+=($AvsCloudNameProperty) Write-Host "Added AVS properties to ZVM" #VC Properties $ZertoUserWithDomain = "$ZERTO_USER_NAME@$DOMAIN" $VcUserProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $ZertoUserWithDomain -PropertyId "VcUsername" -PropertyType "string" $propertySpec+=($VcUserProperty) $VcPasswordProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $PersistentSecrets.ZertoPassword -PropertyId "VcPassword" -PropertyType "password" $propertySpec+=($VcPasswordProperty) $VcIpProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $VC_ADDRESS -PropertyId "VcIp" -PropertyType "string" $propertySpec+=($VcIpProperty) Write-Host "Added VC properties to ZVM" #ZVM Properties $ZertoAdminProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue $PersistentSecrets.ZertoAdminPassword -PropertyId "ZertoAdminPassword" -PropertyType "password" $propertySpec+=($ZertoAdminProperty) #This is needed to force ZVM to start password configuration API on a first run $DeploymentTypeProperty = Create-OvfProperty ([ref]$propertyKey) -PropertyValue "DeploymentScript" -PropertyId "DeploymentType" -PropertyType "string" $propertySpec+=($DeploymentTypeProperty) $spec.VAppConfig.Property = $propertySpec # Reconfiguring VM with a new properties $task = $ZVM.ExtensionData.ReconfigVM_Task($spec) $task1 = Get-Task -Id ("Task-$($task.value)") $task1 | Wait-Task } } catch { throw "Failed to add dynamic properties for Zero VM. Exception = $_" } } } Function Create-OvfProperty { #TODO: Pavlo test if ref works param( [Parameter(Mandatory=$true, HelpMessage = "Ovf property Key, should be unique")] [ref] [int] $PropertyKey, [Parameter(Mandatory=$true, HelpMessage = "Ovf property Value")] [string] $PropertyValue, [Parameter(Mandatory=$true, HelpMessage = "Ovf property Id")] [string] $PropertyId, [Parameter(Mandatory=$true, HelpMessage = "Ovf property Type")] [string] $PropertyType ) Process { Write-Host "Starting $($MyInvocation.MyCommand)... $($PropertyId)" $property = New-Object VMware.Vim.VAppPropertySpec $property.Operation = "add" $property.Info = New-Object VMware.Vim.VAppPropertyInfo $property.Info.Key = $PropertyKey.Value $property.Info.value = $PropertyValue $property.Info.Id = $PropertyId $property.Info.type = $PropertyType $PropertyKey.Value++ return $property } } Function Set-OvfProperties{ param( [Parameter(Mandatory=$false, HelpMessage= "Configure ovf Properties")] [bool]$ConfigureOvfProperties, [Parameter(Mandatory=$true, HelpMessage = "Path for the OVA file")] [string] $OvaPath, [Parameter(Mandatory = $true, HelpMessage = "Zvm IP address")] [ValidateNotNullOrEmpty()][string] $ZVMLIp, [Parameter(Mandatory=$true, HelpMessage="Network device for ZVML")] [ValidateNotNullOrEmpty()][string] $NetworkName, [Parameter(Mandatory = $true, HelpMessage = "SubnetMask address")] [ValidateNotNullOrEmpty()][string] $SubnetMask, [Parameter(Mandatory = $true, HelpMessage = "Default gateway")] [ValidateNotNullOrEmpty()][string] $DefaultGateway, [Parameter(Mandatory = $true, HelpMessage = "DNS server address")] [ValidateNotNullOrEmpty()][string] $DNS ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." try{ $ovfConfig = Get-OvfConfiguration -Ovf $OvaPath -ErrorAction stop Write-Host "The ovf configuration was fetched successfully for $ovaPath, ConfigureOvfProperties=$ConfigureOvfProperties" $ovfConfig.NetworkMapping.Vlan_244_6_5_new.Value = $NetworkName if ($ConfigureOvfProperties -eq $true) { $ovfConfig.net.ipAddress.Value = $ZVMLIp $ovfConfig.net.gateway.Value = $DefaultGateway $ovfConfig.net.netmask.Value = $SubnetMask $ovfConfig.net.dns.Value = $DNS } return $ovfConfig } catch{ throw "Failed to set ovf properties for $ovfPath, exception = $_" } } } |