Util/MigrationUtil.psm1

Import-Module -Name @(Join-Path $PSScriptRoot Util)

function Get-RMMigrationByIdAndStatus {
    param(
        [string] $MigrationId,
        [bool] $StatusOnly = $false
    )

    $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 + "/migrations/" + $MigrationId + "?status_only=$StatusOnly"
        Headers = $Headers
        ContentType = "application/json"
    }

    return Invoke-RMRestMethod -Params $Params
}

function Get-RMMigrationListBySourceId {
    param (
        [string] $OrganizationId,
        [string] $SourceId
    )
    $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 + "/migrations?source=$SourceId"
        Headers = $Headers
        ContentType = "application/json"
    }

    $Response = Invoke-RMRestMethod -Params $Params
    
    return $Response.content
}

function Get-RMMigrationsByIds {
    param(
        [string[]] $MigrationIds
    )

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

    $MigrationIdString  = $MigrationIds -join ","

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

    $Params = @{
        Method = "Get"
        Uri = $Uri.Value + "/migrations?migration_ids=" + $MigrationIdString
        Headers = $Headers
        ContentType = "application/json"
    }

    return Invoke-RMRestMethod -Params $Params
}

function Get-RMCurrentStepIndex {
    param(
        [system.Object] $Migration
    )
    $Index = 0
    switch ($Migration.state) {
        "success" {
            $Index = $Migration.steps.Count
            break
        }
        {($_ -ieq "running") -or ($_ -ieq "error")} {
            while ($Migration.steps.Count -gt ($Index + 1) -and $Migration.steps[$Index + 1].state -ine "pending") {
                $Index++
            }
            break
        }
    }

    return $Index
}

function Get-RMFirstPendingStepIndex {
    param(
        [System.Object] $Migration
    )
    $Index = -1
    foreach ($Step in $Migration.steps) {
        $Index ++
        if ($Step.state -ieq "pending") {
            return $Index
        }
    }

    return $Index
}

function Get-RMMigrationProgress {
    param(
        [System.Object] $Migration
    )
    $StepIndex = 0
    if ($Migration.state -ieq "pending") {
        $StepIndex = Get-RMFirstPendingStepIndex -Migration $Migration
    } else {
        $StepIndex = Get-RMCurrentStepIndex -Migration $Migration
    }

    return [int](($StepIndex/$Migration.steps.Count) * 100)
}

function Test-RMMigrationStalled {
    param(
        [System.Object] $Migration
    )

    if ($Migration.state -ne "running") {
        return $false
    }
    foreach ($Step in $Migration.steps) {
        if ($Step.state -eq "running" -and $null -ne $Step.recoverable_errors -and $Step.recoverable_errors.Count -gt 0) {
            return $true
        }
    }

    return $false
}

function Get-RMMigrationsNotFound {
    param(
        [string[]] $ReceivedMigrationIds,
        [string[]] $UserInputMigrationIds
    )

    $NotFoundMigrationIds = @()
    $CompareResults = Compare-Object -ReferenceObject $UserInputMigrationIds -DifferenceObject $ReceivedMigrationIds
    foreach ($CompareResult in $CompareResults) {
        if ($CompareResult.SideIndicator -contains "<=") {
            $NotFoundMigrationIds += $CompareResult.InputObject
        }
    }

    return $NotFoundMigrationIds
}

function Get-RMMigrationIdFromResponse {
    param(
        [System.Object] $Response
    )
    $MigrationId = ""
    if ($Response.links[1].rel -ine "migration") {
        return $MigrationId
    }

    $SplitData = $Response.links[1].href.split("/")
    if ($SplitData.Count -lt 7) {
        return $MigrationId
    }

    if ($SplitData[6].Contains("{")) {
        $MigrationId = $SplitData[6].SubString(0, $SplitData[6].IndexOf("{"))
    } else {
        $MigrationId = $SplitData[6].SubString(0, $SplitData[6].Length)
    }
    return $MigrationId
}

function Add-RMOSUpgrade {
    param (
        [hashtable] $UserParameter,
        [hashtable] $UpdatedParameter,
        [System.Object] $Source
    )
    $SourceOSMMapping = Get-RMOSMMappingBySource -Source $Source
    $UpgradeOSVersion = $UserParameter["UpgradeOSVersion"]
    if (![string]::IsNullOrEmpty($UpgradeOSVersion) -and $null -ne $SourceOSMMapping[$UpgradeOSVersion] `
            -and $SourceOSMMapping.Keys.Count -gt 0) {
        $UpgradeOSVersion = $UpgradeOSVersion.Trim('"')
        $UpgradeOSVersion = $UpgradeOSVersion.Trim("'")
        $UpdatedParameter.Add("UpgradeOSVersion", $SourceOSMMapping[$UpgradeOSVersion])
        $UpdatedParameter.Add("InPlaceUpgrade", $true)
    } else {
        $UpdatedParameter.Add("UpgradeOSVersion", $null)
        $UpdatedParameter.Add("InPlaceUpgrade", $false)
    }    
}

function Add-RMOSConversionUpgrade {
    param(
        [hashtable] $UserParameter,
        [hashtable] $UpdatedParameter,
        [System.Object] $Source
    )

    $SourceOSConversionMapping = Get-RMOSConversionBySource -Source $Source
    $UpgradeOSConversionVersion = $UserParameter["UpgradeOSConversion"]
   
    if (![string]::IsNullOrEmpty($UpgradeOSConversionVersion) -and $null -ne $SourceOSConversionMapping[$UpgradeOSConversionVersion] `
            -and $SourceOSConversionMapping.Keys.Count -gt 0) {
        $UpgradeOSConversionVersion = $UpgradeOSConversionVersion.Trim('"')
        $UpgradeOSConversionVersion = $UpgradeOSConversionVersion.Trim("'")
        $UpdatedParameter.Add("UpgradeOSVersion", $SourceOSConversionMapping[$UpgradeOSConversionVersion])
        $UpdatedParameter.Add("InPlaceUpgrade", $true)
    } else {
        $UpdatedParameter.Add("UpgradeOSVersion", $null)
        $UpdatedParameter.Add("InPlaceUpgrade", $false)
    }
}

function Add-RMMigrationExtension {
    param (
        [hashtable] $UpdatedParameter,
        [string] $MigrationExtension,
        [string] $MigrationExtensionOSM,
        [System.Object] $MigrationExtensionResponse
    )

    if (![string]::IsNullOrEmpty($MigrationExtension)) {
        $MigrationExtensionId = Get-RMMigrationExtensionId -MigrationExtension $MigrationExtension -MigrationExtensionArray $MigrationExtensionResponse.content `
            -ExecutionStep 3
        $UpdatedParameter.Add("MigrationExtension", $MigrationExtension)
        $UpdatedParameter.Add("MigrationExtensionId", $MigrationExtensionId)
    }

    if (![string]::IsNullOrEmpty($MigrationExtensionOSM)) {
        $MigrationExtensionIdOSM = Get-RMMigrationExtensionId -MigrationExtension $MigrationExtensionOSM -MigrationExtensionArray $MigrationExtensionResponse.content `
            -ExecutionStep 4
        $UpdatedParameter.Add("MigrationExtensionOSM", $MigrationExtensionOSM)
        $UpdatedParameter.Add("MigrationExtensionIdOSM", $MigrationExtensionIdOSM)
    }
}

function Read-RMMigrationExtension {
    param(
        [System.Object] $CloudAccount,
        [System.Array] $MigrationExtension,
        [System.Object] $MigrationExtensionObject,
        [hashtable] $UpdatedUserInput
    )

    if ($MigrationExtension.Count -gt 0) {
        $ReadValue = Read-RMString -UserMessage "Enter migration extensions" -Options  $MigrationExtension -ParameterName "Migration Extension" `
            -IsRequired $false -DefaultValue "None"
        $MigrationExtensionId = Get-RMMigrationExtensionId -MigrationExtension $ReadValue -MigrationExtensionArray $MigrationExtensionObject `
            -ExecutionStep 3
        $UpdatedUserInput.Add("MigrationExtension", $ReadValue)
        $UpdatedUserInput.Add("MigrationExtensionId", $MigrationExtensionId)
    } else {
        $UpdatedUserInput.Add("MigrationExtensionOSM", $null)
        $UpdatedUserInput.Add("MigrationExtensionIdOSM", $null)
    }
}

function Read-RMMigrationExtensionOSM {
    param (
       [System.Array] $MigrationExtensionOSM,
       [System.Object] $MigrationExtensionObject,
       [hashtable] $UpdatedUserInput
    )

    if ($MigrationExtensionOSM.Count -gt 0) {
        $ReadValue = Read-RMString -UserMessage "Enter migration extension name" -Options  $MigrationExtensionOSM -ParameterName "Migration Extension" `
            -IsRequired $false -DefaultValue "None"
        $MigrationExtensionIdOSM = Get-RMMigrationExtensionId -MigrationExtension $ReadValue -MigrationExtensionArray $MigrationExtensionObject `
            -ExecutionStep 4 
        $UpdatedUserInput.Add("MigrationExtensionOSM", $ReadValue)
        $UpdatedUserInput.Add("MigrationExtensionIdOSM", $MigrationExtensionIdOSM)
    } else {
        $UpdatedUserInput.Add("MigrationExtensionOSM", $null)
        $UpdatedUserInput.Add("MigrationExtensionIdOSM", $null)
    }
}

function Read-RMOSUpgradeOption {
    param (
        [System.Object] $Source,
        [hashtable] $UpdatedUserInput
    )

    $SourceOSMMapping = Get-RMOSMMappingBySource -Source $Source
    $SourceOSCMapping = Get-RMOSConversionBySource -Source $Source

    if ($SourceOSMMapping.Keys.Count -gt 0 -and $SourceOSCMapping.Keys.Count -gt 0) {
        $ReadValue = Read-RMString -UserMessage "Do you want to upgrade the OS or convert the OS?" -Options "OS_Version", "OS_Conversion" `
            -DefaultValue "None" -ParameterName "Upgrade Version" -IsRequired $false
        
        if ("OS_Version" -ieq $ReadValue) {
            Read-RMOSMUpgradeOption -Source $Source -UpdatedUserInput $UpdatedUserInput -SourceOSMMapping $SourceOSMMapping
        } elseif ('OS_Conversion' -ieq $ReadValue) {
            Read-RMOSConversionUpgradeOption -Source $Source -UpdatedUserInput $UpdatedUserInput -SourceOSConversionMapping $SourceOSCMapping
        } else {
            $UpdatedUserInput.Add("UpgradeOSVersion", $null)
            $UpdatedUserInput.Add("InPlaceUpgrade", $false)
        }
    } elseif ($SourceOSMMapping.Keys.Count -gt 0) {
        Read-RMOSMUpgradeOption -Source $Source -UpdatedUserInput $UpdatedUserInput -SourceOSMMapping $SourceOSMMapping
    } elseif ($SourceOSCMapping.keys.Count -gt 0) {
        Read-RMOSConversionUpgradeOption -Source $Source -UpdatedUserInput $UpdatedUserInput -SourceOSConversionMapping $SourceOSCMapping
    } else {
        $UpdatedUserInput.Add("UpgradeOSVersion", $null)
        $UpdatedUserInput.Add("InPlaceUpgrade", $false)
    }
}

function Read-RMOSConversionUpgradeOption {
    param(
        [System.Object] $Source,
        [hashtable] $UpdatedUserInput,
        [hashtable] $SourceOSConversionMapping
    )
    if ($SourceOSConversionMapping.Keys.Count -gt 0) {
        $ReadValue = Read-RMString -UserMessage "Enter the OS conversion version to upgrade to" -Options $SourceOSConversionMapping.keys -DefaultValue "None" `
            -ParameterName "Upgrade OS version" -IsRequired $false
        if ("" -ne $ReadValue) {
            $ReadValue = $ReadValue.Trim('"')
            $ReadValue = $ReadValue.Trim("'")
            $UpdatedUserInput.Add("UpgradeOSVersion", $SourceOSConversionMapping[$ReadValue])
            $UpdatedUserInput.Add("InPlaceUpgrade", $true)
            Read-RMConvertFileSystem -Source $Source -UpdatedUserInput $UpdatedUserInput
        } else {
            $UpdatedUserInput.Add("UpgradeOSVersion", $null)
            $UpdatedUserInput.Add("InPlaceUpgrade", $false)
        }
    } else {
        $UpdatedUserInput.Add("UpgradeOSVersion", $null)
        $UpdatedUserInput.Add("InPlaceUpgrade", $false)
    }
}

function Read-RMOSMUpgradeOption {
    param(
        [System.Object] $Source,
        [hashtable] $UpdatedUserInput,
        [hashtable] $SourceOSMMapping
    )
    if ($SourceOSMMapping.Keys.Count -gt 0) {
        $ReadValue = Read-RMString -UserMessage "Enter the OS version to upgrade to" -Options $SourceOSMMapping.keys -DefaultValue "None" `
            -ParameterName "Upgrade OS version" -IsRequired $false
        if ("" -ne $ReadValue) {
            $ReadValue = $ReadValue.Trim('"')
            $ReadValue = $ReadValue.Trim("'")
            $UpdatedUserInput.Add("UpgradeOSVersion", $SourceOSMMapping[$ReadValue])
            $UpdatedUserInput.Add("InPlaceUpgrade", $true)
            Read-RMConvertFileSystem -Source $Source -UpdatedUserInput $UpdatedUserInput
        } else {
            $UpdatedUserInput.Add("UpgradeOSVersion", $null)
            $UpdatedUserInput.Add("InPlaceUpgrade", $false)
        }
    } else {
        $UpdatedUserInput.Add("UpgradeOSVersion", $null)
        $UpdatedUserInput.Add("InPlaceUpgrade", $false)
    }    
}

function Read-RMConvertFileSystem {
    param (
        [System.Object] $Source,
        [hashtable] $UpdatedUserInput
    ) 

    $ConvertFileSystemObject = @{}
    
    if ("linux" -ieq $Source.os_type -and  `
        $Source.attributes.storage.mounts.psobject.properties.value.fs_type -contains 'ext4') {
            $ReadValue = Read-RMBoolean -UserMessage "Linux filesystem converter" -DefaultValue "false"
            $SelectedMountPoints =  $UpdatedUserInput['MountPoints']
            if ($ReadValue) {
                foreach($MointPoint in $SelectedMountPoints.Values) {
                    $ConvertFileSystemObject.Add($MointPoint, "xfs")
                }
            }   
    }  
    
    $UpdatedUserInput.Add("ConvertFileSystem", $ConvertFileSystemObject)
}

function Add-RMConvertFileSystem {
    param (
        [System.Object] $Source,
        [hashtable] $UpdatedUserInput,
        [string] $ConvertFileSystem
    )

    $ConvertFileSystemObject = @{}

    if ("linux" -ieq $Source.os_type -and  `
        $Source.attributes.storage.mounts.psobject.properties.value.fs_type -contains 'ext4') {
        $SelectedMountPoints =  $UpdatedUserInput['MountPoints']
        foreach($MointPoint in $SelectedMountPoints.Values) {
            $ConvertFileSystemObject.Add($MointPoint, "xfs")
        }
    }
    $UpdatedUserInput.Add("ConvertFileSystem", $ConvertFileSystemObject)
}

function Read-RMSQLServerUpgradeOption {
    param (
        [System.Object] $Source
    )

    $SQLServerUpgradeArray = @()
    $SourceSQLServerMapping = Get-RMSQLMMappingBySource -Source $Source
    
    if ($SourceSQLServerMapping.Count -lt 1) {
        return $SQLServerUpgradeArray
    }

    $ReadValue = Read-RMBoolean -UserMessage "Do you want to upgrade SQL server?" -DefaultValue $false

    if (!$ReadValue) {
        return $SQLServerUpgradeArray
    }

    if ($SourceSQLServerMapping.Count -gt 0) { 
        foreach ($SQLServerObject in $SourceSQLServerMapping) {
            $Instance = $SQLServerObject.display_name
            $UpgradeVersion = Read-RMString -UserMessage "Enter the SQL version to upgrade to for $Instance" -Options  $SQLServerObject.upgrade_options -DefaultValue "None" `
                -ParameterName "Upgrade Version" -IsRequired $false
            if (![string]::IsNullOrWhiteSpace($UpgradeVersion)) {
                $AdditionalProperty = Read-RMString -UserMessage "Enter any additional parameters:" -DefaultValue "None" -ParameterName "Additional Parameters" `
                    -IsRequired $false
                $SQLServerMapping = Get-RMSQLServerMapping -GUID $SQLServerObject.guid -UpgradeVersion $UpgradeVersion -UpgradeDisplayName $SQLServerObject.display_name `
                    -AdditionalParam $AdditionalProperty
                $SQLServerUpgradeArray +=  $SQLServerMapping
            }
        }
    }

    return $SQLServerUpgradeArray
}

function Get-RMUpgradeSQLServer {
    param(
        [hashtable[]] $UpgradeSQLServer,
        [System.Object] $Source,
        [System.Object] $SourceSQLServerMapping
    )
    $SQLServerUpgradeArray = @()

    foreach($Upgrade in $UpgradeSQLServer) {
        foreach($SQLServerObject in $SourceSQLServerMapping) {
            if ($Upgrade.InstanceName -ieq $SQLServerObject.instance_name) {
                $SQLServerMapping =  Get-RMSQLServerMapping -GUID $SQLServerObject.guid -UpgradeVersion $Upgrade.UpgradeVersion `
                    -UpgradeDisplayName $SQLServerObject.display_name -AdditionalParam $Upgrade.AdditionalParams
                $SQLServerUpgradeArray += $SQLServerMapping
            }
        }
    }
    
    return  $SQLServerUpgradeArray
}

function Get-RMSQLServerMapping {
    param(
        [string] $GUID,
        [string] $UpgradeVersion,
        [string] $UpgradeDisplayName,
        [string] $AdditionalParam
    )

    $UpgradeDisplayName =  $UpgradeDisplayName -replace " -" , ","
    $UpgradeDisplayName = $UpgradeDisplayName + " : " + $UpgradeVersion
    $UpgradeVersion = "MSSQL" + $UpgradeVersion
    $GUID = $GUID.ToUpper()
    $SQLServiceMapping = @{
        "product_family" = "mssql"
        "guid" = "{$GUID}"
        "upgrade_version" = $UpgradeVersion
        "upgrade_display_name" = $UpgradeDisplayName
        "upgrade_parameters" = @{
            "additional_setup_params" =  $AdditionalParam
        }
    }

    return  $SQLServiceMapping
}

function Test-RMSourceHasRunningMigration {
    param(
        [string] $OrganizationId,
        [string] $SourceId
    )
    $MigrationList = Get-RMMigrationListBySourceId -OrganizationId $OrganizationId -SourceId $SourceId
    foreach ($Mig in $MigrationList) {
        if ("running" -eq $Mig.state) {
            return $true
        }
    }

    return $false
}

function Get-RMMigrationExtensionFromStep {
    param (
        [System.Object] $MigrationExtensionArray
    )

    $MigrationExtension = @()
    $MigrationExtensionOSM = @()

    foreach ($Me in $MigrationExtensionArray) {
        if (4 -eq $Me.execution_step) {
            $MigrationExtensionOSM += $Me.name
        } else {
            $MigrationExtension += $Me.name
        }
    }
    
    return $MigrationExtension, $MigrationExtensionOSM 
}


function Get-RMMigrationExtensionId {
    param (
        [string] $MigrationExtension,
        [System.Object] $MigrationExtensionArray,
        [int] $ExecutionStep
    )
    
    $MigrationExtensionId = ""
    if ("" -ne  $MigrationExtension) {
        foreach ($Me in $MigrationExtensionArray) {
            if ($MigrationExtension -ieq $Me.name -and $ExecutionStep -eq $Me.execution_step) {
                $MigrationExtensionId = $Me.id
                break
            }
        }
    }
    return $MigrationExtensionId
}