DifferentialMigration/DifferentialMigration.psm1

Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath DifferentialProfile  | Join-Path -ChildPath DifferentialProfile)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Util | Join-Path -ChildPath MigrationUtil)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Preflight | Join-Path -ChildPath Preflight)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Common | Join-Path -ChildPath Common)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath CloudAccount | Join-Path -ChildPath CloudAccount)

function Start-RMDM {
    param (
        [string] $MigrationId,
        [bool] $IgnoreValidationErrors
    )
    $Errors, $IsValidMigrationId = Confirm-RMDMParameter -UserParameter $PSBoundParameters
    if (!$IsValidMigrationId) {
        Out-RMUserParameterResult -ErrorMessage $Errors
        return
    }

    $OrganizationId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly
    $Migration = $null

    if ($IsValidMigrationId) {
        $Migration = Get-RMMigrationByIdAndStatus -MigrationId $MigrationId
        if ($null -eq $Migration) {
            # Show-RMError has already displayed the error, hence return
            return
        }
        $MigrationType = $Migration.migration_type
        $HeartbeatStatus = Test-RMApplianceHeartbeating -ApplianceId $Migration.cloud_appliance_id -AccountType $Migration.target_cloud_type
        if (!$HeartbeatStatus) {
            $Errors += "Appliance is not ready, cannot start differential migration"
        }

        if ("full" -ne $MigrationType) {
            $Errors += "Migration type for the given migration ID is '$MigrationType', differential migration can only be started for a full migration."
        } else {
            $SourceId = $Migration.source_id
            $MigrationList = Get-RMMigrationListBySourceId -OrganizationId $OrganizationId -SourceId $SourceId
            foreach ($Mig in $MigrationList) {
                if ("running" -eq $Mig.state) {
                    Write-Warning "Currently there is a migration running for the source of the given migration ID, this differential migration might fail."
                    Break;
                }
            }
        }
    }

    if ($Errors.Count -gt 0) {
        Out-RMUserParameterResult -ErrorMessage $Errors
        return
    }

    $TransferType = $Migration.transfer_type
    $TargetProperties = $Migration.target.properties
    $MigrationInstructions =  $Migration.migration_instructions
    $Name = "PowerShell - Differential Profile - " + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()

    $HashArguments = @{
        Name = $Name
        OrganizationId = $OrganizationId
        Description = $Description
        ApplianceId = $Migration.cloud_appliance_id
        Schedule = $Schedule
        TransferMode = $TransferMode
        MigrationId = $Migration.id
        SourceId = $Migration.source_id
        Target = $Target
        Source =  @{
            "host" = $Migration.source_hostname
        }
        ShutdownSource = $false
        ShutdownTarget = $false
        RemoveTargetAgent = $false
        PublishMigrationHub = $false
        TransferType = $TransferType
        MigrationInstructions = $MigrationInstructions
        TargetProperties = $TargetProperties
        TargetIp = $Migration.target.ip
        IgnoreValidationErrors = $IgnoreValidationErrors
    }

    $Response = New-RMDifferentialProfile @HashArguments
    $ShouldExit = Start-RMDifferentialMigrationPreflight -DifferentialProfileId $Response.id -IgnoreValidationErrors $IgnoreValidationErrors
    if ($ShouldExit) {
        return
    }

    $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 = "Post"
        Uri = $Uri.Value + "/differentialprofiles/" + $Response.id + "/migrations"
        Headers = $Headers
        ContentType = "application/json"
    }

    $MigrationResponse = Invoke-RMRestMethod -Params $Params
    Out-MigrationIdFromResponse -Response $MigrationResponse
}

function Test-RMApplianceHeartbeating {
    param(
        [string] $ApplianceId,
        [string] $AccountType
    )
    $HeartBeatingCloudAccounts, $NonHeartBeatingCloudAccounts = Get-RMCloudAccountsForCurrentProject -AccountType $AccountType
    foreach ($CloudAccount in $HeartBeatingCloudAccounts.Values) {
        if ($CloudAccount.appliance.id -eq $ApplianceId) {
            return $true
        }
    }

    return $false
}

function Confirm-RMDMParameter {
    param(
        [hashtable] $UserParameter
    )
    $Errors = @()
    $IsValidMigrationId = $true
    if (!$UserParameter.ContainsKey("MigrationId") -or [string]::IsNullOrEmpty($UserParameter["MigrationId"])) {
        $Errors += "MigrationId is required"
        $IsValidMigrationId = $false
    }
    return $Errors, $IsValidMigrationId
}