CloudAccount/CloudAccount.psm1

using module '../Common/Result'
Import-Module -Name @(Join-Path  $PSScriptRoot .. | Join-Path -ChildPath Util | Join-Path -ChildPath Util)
function Get-RMCloudAccountsForCurrentProject {
    param(
        [string] $AccountType
    )

    $LoginStatus = Test-UserLoggedIn
    if ($LoginStatus.ReturnCode -eq [RMReturn]::ERROR) {
        return $LoginStatus
    }

    $CurrentProjectId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly

    $PageIndex = 0
    $HeartBeatingCloudAccounts = @{}
    $NonHeartBeatingCloudAccounts = @{}
    do {
        $Response = Get-RMCloudAccountInternal -OrganizationId $CurrentProjectId -AccountType $AccountType -PageNumber $PageIndex
        foreach ($ResponseContent in $Response.content) {
            if ([bool]($ResponseContent.PSObject.Properties.name -match "appliance") -and $ResponseContent.appliance.heartbeat_status) {
                $HeartBeatingCloudAccounts.Add($ResponseContent.name, $ResponseContent)
            } else {
                $NonHeartBeatingCloudAccounts.Add($ResponseContent.name, $ResponseContent)
            }
        }
        $PageIndex++
    } while ($PageIndex -lt $Response.page.totalPages)

    return $HeartBeatingCloudAccounts, $NonHeartBeatingCloudAccounts
}

function Get-RMCloudAccountByName {
    param(
        [string] $CloudAccountName,
        [string] $AccountType,
        [bool] $VMBasedAppliancesOnly
    )
    $HeartBeatingCloudAccounts, $NonHeartBeatingCloudAccounts = Get-RMCloudAccountsForCurrentProject -AccountType $AccountType
    if ($VMBasedAppliancesOnly) {
        $HeartBeatingCloudAccounts, $NonHeartBeatingCloudAccounts, $OtherCloudAccounts = `
            Get-RMVMBasedCloudAccount -HeartBeatingCloudAccount $HeartBeatingCloudAccounts `
                -NonHeartBeatingCloudAccount $NonHeartBeatingCloudAccounts
        if ($OtherCloudAccounts.Keys -contains $CloudAccountName) {                
            return $null, "The TargetCloud '$CloudAccountName' does not support VM-based migrations"
        }
    }
    if($NonHeartBeatingCloudAccounts.Keys -contains $CloudAccountName) {
        return $null, "The TargetCloud '$CloudAccountName' is not ready for use, please provide a different target cloud"
    }

    if ($HeartBeatingCloudAccounts.Keys -notcontains $CloudAccountName) {
        Throw [System.Management.Automation.ItemNotFoundException]::new(`
            "Invalid target cloud name '$CloudAccountName'")
    }

    return $HeartBeatingCloudAccounts[$CloudAccountName], $null
}

function Get-CachedCloudAttribute {
    param(
        [System.Object] $CloudAccount
    )

    $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly
    $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly

    $Headers = @{
        Accept = "application/rm+json"
        "X-Auth-Token" = $RMLoginResult.token
    }

    $Params = @{
        Method = "Get"
        Uri = $Uri + "/cloudaccounts/" + $CloudAccount.id + "/cachedattributes"
        Headers = $Headers
    }

    return Invoke-RMRestMethod -Params $Params
}

function Get-CloudAttributesSummary {
    param(
        [System.Object] $CloudAccount
    )
    $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly
    $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly

    $Headers = @{
        Accept = "application/rm+json"
        "X-Auth-Token" = $RMLoginResult.token
    }

    $Params = @{
        Method = "Get"
        Uri = $Uri + "/cloudaccounts/" + $CloudAccount.id + "/attributes?summary=true"
        Headers = $Headers
    }

    return Invoke-RMRestMethod -Params $Params
}

function Get-RMCloudAccountInternal {
    param(
        [string] $OrganizationId,
        [string] $AccountType,
        [int] $PageNumber
    )

    $RMLoginResult = Get-Variable -Name "RMContext-UserLogin"
    $Uri = Get-Variable -Name "RMContext-ReactorURI"

    $Headers = @{
        Accept = "application/rm+json"
        "X-Auth-Token" = $RMLoginResult.Value.token
    }

    $Params = @{
        Method = "Get"
        Uri = $Uri.Value + "/organizations/" + $OrganizationId + "/cloudaccounts?type=" + $AccountType + "&size=25&page=" + $PageNumber + "&sort=created_at%2Cdesc"
        Headers = $Headers
    }
    return Invoke-RMRestMethod -Params $Params
}

function Read-RMCloudAccount {
    param(
        [string] $UserMessage,
        [string] $AccountType,
        [bool] $VMBasedAppliancesOnly
    )

    $HeartBeatingCloudAccounts, $NonHeartBeatingCloudAccounts = Get-RMCloudAccountsForCurrentProject -AccountType $AccountType
    # OtherCloudAccounts contains both non-VMbased cloud accounts (used only for validation)
    $OtherCloudAccounts = @{}
    if ($VMBasedAppliancesOnly) {
        $HeartBeatingCloudAccounts, $NonHeartBeatingCloudAccounts, $OtherCloudAccounts = `
            Get-RMVMBasedCloudAccount -HeartBeatingCloudAccount $HeartBeatingCloudAccounts `
                -NonHeartBeatingCloudAccount $NonHeartBeatingCloudAccounts
    }
    
    while ($true) {
        $CloudAccountName = ""
        if (0 -eq $HeartBeatingCloudAccounts.Keys.Count) {
            $CloudAccountName = Read-Host $UserMessage
        } elseif (1 -eq $HeartBeatingCloudAccounts.Keys.Count) {
            $CloudAccountName = $HeartBeatingCloudAccounts.Keys[0]
            $UserPrompt = $UserMessage + " [" + $CloudAccountName + "]"
            $ReadValue = Read-Host $UserPrompt
            if ("" -ne $ReadValue) {
                $CloudAccountName = $ReadValue
            }
        } else {
            $CloudAccountNames = $HeartBeatingCloudAccounts.Keys -join ","
            $UserPrompt = $UserMessage + " (" + $CloudAccountNames + ")"
            $CloudAccountName = Read-Host $UserPrompt
        }
        
        if ([string]::IsNullOrWhiteSpace($CloudAccountName)) {
            Write-RMError -Message "Target cloud is required"
            continue
        }

        if ($VMBasedAppliancesOnly -and $OtherCloudAccounts.Keys -contains $CloudAccountName) {
            Write-RMError -Message "The target cloud '$CloudAccountName' does not support VM-based migrations"
            continue
        }

        if($NonHeartBeatingCloudAccounts.Keys -contains $CloudAccountName) {
            Write-RMError -Message "The target cloud '$CloudAccountName' is not ready for use, please enter a different target cloud"
            continue
        }

        if ($HeartBeatingCloudAccounts.Keys -notcontains $CloudAccountName) {
            Write-RMError -Message "Invalid target cloud name"
            continue
        }
    
        return $HeartBeatingCloudAccounts[$CloudAccountName]
    }
}

function Get-RMVMBasedCloudAccount {
    param(
        [hashtable] $HeartBeatingCloudAccount,
        [hashtable] $NonHeartBeatingCloudAccount
    )
    $VMBasedHeartBeatingCloudAccount = @{}
    $VMBasedNonHeartBeatingCloudAccount = @{}
    $OtherCloudAccounts = @{}
    foreach ($CloudAccount in $HeartBeatingCloudAccount.Values) {
        if($CloudAccount.appliance.cloud_configuration.vsphere.vm_level_migrations_enabled) {
            $VMBasedHeartBeatingCloudAccount.Add($CloudAccount.name, $CloudAccount)
        } else {
            $OtherCloudAccounts.Add($CloudAccount.name, $CloudAccount)
        }
    }

    foreach ($CloudAccount in $NonHeartBeatingCloudAccount.Values) {
        if (-not([bool]($CloudAccount.PSObject.Properties.name -match "appliance") -and `
                $null -ne $CloudAccount.appliance -and `
                [bool]($CloudAccount.appliance.PSObject.Properties.name -match "cloud_configuration") -and `
                $null -ne $CloudAccount.appliance.cloud_configuration -and `
                [bool]($CloudAccount.appliance.cloud_configuration.PSObject.Properties.name -match "vsphere") -and `
                $null -ne $CloudAccount.appliance.cloud_configuration.vsphere) -or
                $CloudAccount.appliance.cloud_configuration.vsphere.vm_level_migrations_enabled) {
            $VMBasedNonHeartBeatingCloudAccount.Add($CloudAccount.name, $CloudAccount)
        } else {
            $OtherCloudAccounts.Add($CloudAccount.name, $CloudAccount)
        }
    }

    return $VMBasedHeartBeatingCloudAccount, $VMBasedNonHeartBeatingCloudAccount, $OtherCloudAccounts
}
Export-ModuleMember -Function Get-RMCloudAccountsForCurrentProject, Get-RMCloudAccountByName, `
    Get-CachedCloudAttribute, Get-CloudAttributesSummary, Read-RMCloudAccount, Get-RMVMBasedCloudAccountBySource