RiverMeadow.Migrate.psm1

Import-Module -Name $PSScriptRoot\Util\Util
function Start-RMAzureOSBasedMigration {
    param(
        [Alias("can")]
        [string] $CloudAccountName,

        [Alias("sip")]
        [string] $SourceIP,

        [Alias("rsa")]
        [bool] $RefreshSourceAttributes,

        [Alias("tvmname")]
        [string] $TargetVMName,

        [Alias("tm")]
        [ValidateSet("file-based", "block-based")]
        [string] $TransferMethod,

        [Alias("crg")]
        [bool] $CreateResourceGroup,

        [Alias("rg")]
        [string] $ResourceGroup,

        [Alias("rgr")]
        [string] $ResourceGroupRegion,

        [Alias("vmsn")]
        [string] $VMSizeName,

        [Alias("vt")]
        [ValidateSet("Standard_SSD", "Standard_HDD", "Premium_SSD")]
        [string] $VolumeType,

        [Alias("mp")]
        [string[]] $MountPoints,

        [Alias("rmp")]
        [string[]] $ResizeMountPoints,

        [Alias("dtp")]
        [int] $DataTransferPort,

        [Alias("vn")]
        [string] $VirtualNetwork,

        [Alias("sn")]
        [string] $Subnet,

        [Alias("apip")]
        [bool] $AssignPublicIP,

        [Alias("spip")]
        [string] $StaticPrivateIP,

        [Alias("etni")]
        [bool] $EnforceTargetNetworkIsolation,

        [Alias("sg")]
        [string] $SecurityGroup,

        [Alias("dtdnsr")]
        [bool] $DisableTargetDNSRegistration,

        [Alias("itags")]
        [string[]] $InstanceTags,

        #TODO: parameterset
        [Alias("ao")]
        [ValidateSet("None", "AvailabilityZone", "AvailabilitySet")]
        [string] $AvailabilityOptions,

        [Alias("az")]
        [ValidateSet(1, 2, 3)]
        [int] $AvailabilityZone,

        [Alias("cas")]
        [bool] $CreateAvailabilitySet,

        [Alias("as")]
        [string] $AvailabilitySet,

        [Alias("fd")]
        [int] $FaultDomains,

        [Alias("ud")]
        [int] $UpdateDomains,

        #TODO: parameterset
        [Alias("ebd")]
        [bool] $EnableBootDiagnostics,

        [Alias("sa")]
        [string] $StorageAccount,

        #TODO: parameterset
        [Alias("det")]
        [ValidateSet("platform-managed", "customer-managed")]
        [string] $DiskEncryptionType,

        [Alias("es")]
        [string] $EncryptionSet,

        [Alias("ehub")]
        [bool] $EnableHybridUseBenefit,

        [Alias("uosv")]
        [string] $UpgradeOSVersion,

        [Alias("ss")]
        [bool] $ShutdownSource,

        [Alias("st")]
        [bool] $ShutdownTarget,

        [Alias("rrmsa")]
        [bool] $RemoveRMSAgent,

        [Alias("mi")]
        [string[]] $MigrationInstructions
    )

    $UserLoginStatus = Test-UserLoggedIn
    if (!$UserLoginStatus) {
        return
    }

    Import-Module -Name $PSScriptRoot\Migration\AZURE\AZURE
    if (0 -eq $PSBoundParameters.Count) {
        Start-RMAzureOSBasedInteractiveMigration
    } else {
        Start-RMAzureOSBasedNonInteractiveMigration @PSBoundParameters
    }
}

function Start-RMVSphereOSBasedMigration {
    param(
        [Alias('can')]
        [string] $CloudAccountName,

        [Alias("sip")]
        [string] $SourceIP,

        [Alias("rsa")]
        [bool] $RefreshSourceAttributes,

        [Alias("tvmname")]
        [string] $TargetVMName,

        [Alias("mp")]
        [string[]] $MountPoints,

        [Alias("rmp")]
        [string[]] $ResizeMountPoints,

        [Alias("tm")]
        [ValidateSet("file-based", "block-based")]
        [string] $TransferMethod,

        [Alias("cps")]
        [string] $CoresPerSocket,

        [Alias("om")]
        [bool] $OverrideMemory,

        [Alias("oms")]
        [int] $OverrideMemorySize,

        [Alias("dtp")]
        [Int64] $DataTransferPort,

        [Alias("dcn")]
        [string] $DatacenterName,

        [Alias("edni")]
        [bool] $EnableDestinationNetworkIsolation,

        [Alias("mnn")]
        [string] $MigrationNetworkName,

        [Alias("ipt")]
        [ValidateSet("static", "dhcp")]
        [string] $IpType,

        [Alias("ipa")]
        [string] $IpAddress,

        [Alias("nm")]
        [string] $Netmask,

        [Alias("dg")]
        [string] $DefaultGateway,

        [Alias("pdns")]
        [string] $PrimaryDNS,

        [Alias("sdns")]
        [string] $SecondaryDNS,

        [Alias("inn")]
        [string] $IsolatedNetworkName,

        [Alias("iipt")]
        [ValidateSet("static", "dhcp")]
        [string] $IsolatedIpType,

        [Alias("iipa")]
        [string] $IsolatedIpAddress,

        [Alias("in")]
        [string] $IsolatedNetmask,

        [Alias("idg")]
        [string] $IsolatedDefaultGateway,

        [Alias("ipdns")]
        [string] $IsolatedPrimaryDNS,

        [Alias("isdns")]
        [string] $IsolatedSecondaryDNS,

        [Alias("dadnsrot")]
        [bool] $DisableAuthomaticDNSRegistrationOnTheTarget,

        [Alias("cl")]
        [string] $Cluster,

        [Alias("rp")]
        [string] $ResourcePool,

        [Alias("fn")]
        [string] $FolderName,

        [Alias("dc")]
        [string] $DatastoreCluster,

        [Alias("dl")]
        [string] $DatastoreLocations,

        [Alias("dpt")]
        [string] $DisksProvisioningType,

        [Alias("hv")]
        [string] $HardwareVersion,

        [Alias("ss")]
        [bool] $ShutdownSource,

        [Alias("st")]
        [bool] $ShutdownTarget,

        [Alias("rrmsa")]
        [bool] $RemoveRMSAgent,

        [Alias("mi")]
        [hashtable] $MigrationInstructions,

        [Alias("uosv")]
        [string]  $UpgradeOSVersion
    )

    Import-Module -Name $PSScriptRoot\Migration\vSphere\vSphere -Force

    if (0 -eq $PSBoundPArameters.Count) {
        return Start-RMInteractiveVSphereOSBasedMigration -Entitlement $Entitlement
    } else {
        return Start-RMNonInteractiveVsphereOsBasedMigration  @PSBoundParameters
    }
}

function Start-RMVSphereDifferentialMigration {
   param(
    [Alias("mid")]
    [string] $MigrationId
   )

   Import-Module -Name $PSScriptRoot\Migration\vSphere\vSphere -Force

   if (0 -eq $PSBoundPArameters.Count) {
        $ReadValue = Read-Host "Enter the migration ID"
        if ("" -eq $ReadValue) {
            throw "Migration ID is required, please try again"
        }
        $MigrationId = $ReadValue
   }


   return Start-RMVSphereOsBasedDifferentialMigration -MigrationId $MigrationId 
}

function Get-RMEntitlement {
    param()
    $CurrentProjectId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly
    $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 + "/organizations/" + $CurrentProjectId + "/entitlements"
        Headers = $Headers
    }

    $Entitlements = Invoke-RMRestMethod -Params $Params
    foreach ($Entitlement in $Entitlements.content) {
        $Remaining = $Entitlement.total - $Entitlement.used
        if ($Remaining -ge 1) {
            return $Entitlement
        }
    }

    throw "Not enough entitlements available to start the migration"
}

function Stop-RMMigration {
    param (
        [Alias("mid")]
        [string] $MigrationId
    )

    $Migration = Get-Migration -MigrationId $MigrationId

    if("error" -ne $Migration.state -and "success" -ne $Migration.state -and "cancel" -ne $Migration.state) {

        $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 + "/migrations/" + $MigrationId + "/cancel"
            Headers = $Headers
            ContentType = "application/json"
        }
    
        $Response = Invoke-RMRestMethod -Params $Params
        return "Migration " + $Response.id + " is cancelled."
    }
    throw "Migration is in final state " +  $Migration.state + ", cannot be cancelled."
}

function Get-RMMigration {
    param(
        [Alias("mid")]
        [string] $MigrationId
    )

    if (0 -eq $PSBoundParameters.Count) {
        $ReadValue = Read-Host "Enter migration ID"
        if("" -eq $ReadValue) {
            throw "Migration ID is required, please try again"
        }
        $MigrationId = $ReadValue
    }

    $Response =  Get-Migration -MigrationId $MigrationId
    if ("running" -eq $Response.state) {
        $Progress = Get-RMMigrationProgress -MigrationObject $Response
    }

    $ResponseArray = @{}
    $ResponseArray.Add("State", $Response.state)
    $ResponseArray.Add("Progress", $Progress )

    return  $ResponseArray | Select-Object -Property State , Progress | Format-List -Property State, Progress 
}

function Get-RMMigrations {
    param (
        [Alias("mid")]
        [string[]] $MigrationIds
    )

    if (0 -eq $PSBoundParameters.Count) {
        $ReadValue = Read-Host "Enter migration ids"
        if("" -eq $ReadValue) {
            throw "Migration id is required, please try again"
       }
       $MigrationIds = $ReadValue
    } else {
        if ("" -eq $MigrationIds) {
            throw "Migration id is required, please try again"
        }
    }
    
    $Result = @()
    $Response = Get-MigrationList -MigrationIds $MigrationIds -PageNumber 0
    $Result += $Response
    for ($index = 1; $index -lt $Response.page.totalPages; $index++) {
        $Result += Get-MigrationList -MigrationIds $MigrationIds -PageNumber $index
    }
    
    $ResponseArray = @()
    foreach($Res in $Result.content) {
       $Progress = ""
       if ("running" -eq $Res.state) {
            $Progress = Get-RMMigrationProgress -MigrationObject $Res
       }
       $ResponseObject = [ResponseObject]::new($Res.id, $Res.state,  $Progress)
       $ResponseArray += $ResponseObject
    }

    return $ResponseArray 
}

function Get-MigrationList {
    param(
        [string[]] $MigrationIds,
        [int] $PageNumber
    )
    
    $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 + "&page=" + $PageNumber
        Headers = $Headers
        ContentType = "application/json"
    }

    return Invoke-RMRestMethod -Params $Params
}

function Get-RMMigrationProgress {
    param(
        [System.Object] $MigrationObject
    )

    $StepCount = $MigrationObject.steps.Count
    $Weight = 100/$StepCount
    $Index = 1
    $Progress = 0

    foreach($Step in $MigrationObject.steps) {
        if ("running" -eq $Step.state) {
            if ($Step.progress -eq 0 -and 1 -eq $Index ) {
                $Progress = [math]::round($Weight/2)
            } elseif ($Step.progress -gt 0 -and $Step.progress -lt 100) {
                $Progress = [math]::round((($Index - 1) * $Weight) + ($Step.progress * $Weight)/100)
            } elseif (100 -eq $Step.progress) {
                $Progress = [math]::round((($Index - 1) * $Weight) + $Weight)
            }
        } elseif("success" -eq $Step.state) {
            $Progress = [math]::round($Index * $Weight)
        }
        $Index++
    }
    return $Progress
}

class ResponseObject {
    [string] $MigrationId
    [string] $Status
    [string] $Progress

    ResponseObject( [string] $MigrationId, [string] $Status, [string] $Progress) {
        $this.MigrationId = $MigrationId
        $this.Status = $Status
        $this.Progress = $Progress
    }
}

Export-ModuleMember -Function Start-RMVSphereOSBasedMigration, Start-RMAzureOSBasedMigration, Get-RMEntitlement, Get-RMMigration, Get-RMMigrations, Stop-RMMigration