AhvFunctions.ps1


$TaskStates = @('ABORTED', 'CANCELED', 'FAILED', 'QUEUED', 'RUNNING', 'PAUSED', 'SKIPPED', 'SUCCEEDED', 'SCHEDULED')
$FailedTaskStates = @('ABORTED', 'CANCELED', 'FAILED', 'SKIPPED')
$SuccessTaskStates = @('SUCCEEDED')

Function ApiCall([string]$Hostname, [int]$Port, [string]$Username, [string]$Password, [string]$Method, [string]$Route, [hashtable]$Body=$Null, [string]$FilePath=$Null)
{
    $url = "https://$($Hostname):$($Port)/$Route"

    $bytes = [System.Text.Encoding]::UTF8.GetBytes("$Username" + ':' + "$Password")
    $authorization = [System.Convert]::ToBase64String($bytes)

    $parameters = @{
        Headers = @{ "Authorization" = "Basic $authorization" }
        Method = $Method
    }
    if ($Body) {
        $parameters['Headers']['Content-Type'] = 'application/json'
        $parameters['Body'] = $Body | ConvertTo-Json
        Log "REST $Method $url with $($parameters['Body'])" $True
    }
    elseif ($FilePath) {
        $parameters['Headers']['Content-Type'] = 'application/octet-stream'
        $parameters['Headers']['X-Nutanix-Destination-Container'] = '64588254-e6ec-4c00-b65a-bad687cc6a22'
        # $parameters['InFile'] = $FilePath
        $content = Get-Content -Path $FilePath
        $parameters['Body'] = $content
        Log "REST $Method $url with file $FilePath" $True
    }
    else {
        Log "REST $Method $url" $True
    }
    try {
        return Invoke-WebRequest -Uri $url @parameters | ConvertFrom-Json
    }
    catch {
        throw "REST $Method $url with $json failed: $_"
    }
}

Function WaitForTask([string]$Hostname, [int]$Port, [string]$Username, [string]$Password, [string]$TaskUuid, [int]$Timeout, [int]$Wait=10)
{
    Log "Waiting for task $TaskUuid"
    $iterations = $Timeout / $Wait
    $count = 0
    While ($count++ -le $iterations) {
        $task = ApiCall -Hostname $Hostname -Port $Port -Username $Username -Password $Password -Method "GET" -Route "api/nutanix/v3/tasks/$TaskUuid"
        Log "WaitForTask $(ConvertTo-Json $task)" $False
        if ($SuccessTaskStates -Contains $task.status) {
            return $task
        }
        elseif ($FailedTaskStates -Contains $task.status)
        {
            throw "WaitForTask status $($task.status) error $($task.error_detail)"
        }
        Start-Sleep -Seconds $Wait
    }
    throw "Timeout waiting for task"
}

Function CreateImageOld([string]$Hostname, [int]$Port, [string]$Username, [string]$Password, [string]$Name, [string]$ImageType, [string]$Description=$Null)
{
    Log "Creating image $Name of type $ImageType"
    $body = @{
        name = $Name
        imageType = $ImageType
    }
    $image = ApiCall -Hostname $Hostname -Username $Username -Password $Password -Port $Port -method "POST" -route "/api/nutanix/v0.8/images" -Body $body
    Log "Create image request $(ConvertTo-Json $image)"
    $taskUuid = $image.taskUuid
    $task = WaitForTask -Hostname $Hostname -Port $Port -Username $Username -Password $Password -TaskUuid $taskUuid -Timeout 90
    Log "created image task uuid=$TaskUuid task=$(ConvertTo-Json $task)" $False
    return $task.entity_reference_list[0].uuid
}

Function CreateImage([string]$Hostname, [int]$Port, [string]$Username, [string]$Password, [string]$Name, [string]$ImageType, [string]$Description=$Null)
{
    Log "Creating image $Name of type $ImageType"
    $body = @{
        metadata = @{ kind = "image" }
        spec = @{
            name = $Name
            resources = @{ image_type = $ImageType }
        }
    }
    if ($Description) {
        $body['spec']['description'] = $Description
    }
    $image = ApiCall -Hostname $Hostname -Username $Username -Password $Password -Port $Port -method "POST" -route "api/nutanix/v3/images" -Body $body
    Log "Create image request $(ConvertTo-Json $image)"
    $taskUuid = $image.status.execution_context.task_uuid
    $task = WaitForTask -Hostname $Hostname -Port $Port -Username $Username -Password $Password -TaskUuid $taskUuid -Timeout 90
    Log "created image task uuid=$TaskUuid task=$(ConvertTo-Json $task)" $False
    return $image.metadata.uuid
}

Function UploadImage([string]$Hostname, [int]$Port, [string]$Username, [string]$Password, [string]$ImageUuid, [string]$Path)
{
    Log "Uploading image $Path to $ImageUuid"
    # $upload = ApiCall -Hostname $Hostname -Username $Username -Password $Password -Port $Port -method "PUT" -route "api/nutanix/v3/images/$ImageUuid/file" -FilePath $Path
    $upload = ApiCall -Hostname $Hostname -Username $Username -Password $Password -Port $Port -method "PUT" -route "api/nutanix/v0.8/images/$ImageUuid/upload" -FilePath $Path
    Log "Upload image request $(ConvertTo-Json $upload)"
    $taskUuid = $upload.task_uuid
    $task = WaitForTask -Hostname $Hostname -Port $Port -Username $Username -Password $Password -TaskUuid $taskUuid -Timeout 300
    Log "upload image task=$(ConvertTo-Json $task)"
}

Function SslNoCertCheck()
{
    Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
    return true;
}
}
"@

    
    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}

Function UploadToAhv([string]$Hostname, [int]$Port, [string]$Username, [string]$Password, [string]$Name, [string]$Path, [string]$Description=$Null, [bool]$SslNoCheck=$True)
{
    if ($SslNoCheck) {
        Log "Not checking SSL cert for $Hostname"
        SslNoCertCheck
    }

    Log "Uploading to AHV $Hostname : $Port as $Username"

    $imageUuid = CreateImage -Hostname $Hostname -Port $Port -Username $Username -Password $Password -ImageType "DISK_IMAGE" -Name $Name -Description $Description
    UploadImage -Hostname $Hostname -Port $Port -Username $Username -Password $Password -ImageUuid $imageUuid -Path $Path

    Log "Copied disk $Path to AHV image $imageUuid"
    return $imageUuid
}