functions/Export-DiskImageToContainerImage.ps1

# <copyright file="Export-DiskImageToContainerImage.ps1" company="Endjin Limited">
# Copyright (c) Endjin Limited. All rights reserved.
# </copyright>
function Export-DiskImageToContainerImage
{
    <#
    .SYNOPSIS
        Packages a Linux raw disk image inside a container image as a single file.
 
    .DESCRIPTION
        Copies the specified Linux raw disk image into a new container image. This can be useful as a means of versioning
        and distributing such disk images as part of a process for managing Firecracker virtual machine disk image templates.
 
    .PARAMETER SourceDiskImagePath
        The path to the disk image file that will be added to the container image.
 
    .PARAMETER DestinationContainerImageName
        The repository, name and tag of the container image that will be built.
 
    .PARAMETER Configuration
        When specified as 'Release', the built image be based on the 'scratch' image (i.e. empty) to optimise its size.
        When not specified as 'Release' (e.g. 'Debug' or blank), the built image be based on the 'busybox' image, to provide
        a minimal shell environment to support diagnosing issues with the container image.
 
    .EXAMPLE
        Export-DiskImageToContainerImage -SourceDiskImagePath "C:\Images\mydiskimage.img" `
                                         -ContainerImageName "mycontainerimage:latest"
 
        This command create a docker image containing the single file: `/mydiskimage.img`.
 
    .EXAMPLE
        Export-DiskImageToContainerImage -SourceDiskImagePath "C:\Images\mydiskimage.img" `
                                         -ContainerImageName "mycontainerimage:latest" `
                                         -Configuration "Debug"
                                          
        This command create a docker image that includes the file `/mydiskimage.img` as well as a minimal shell environment.
 
    .NOTES
        This function requires Docker to be installed and running on the host system.
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string] $SourceDiskImagePath,

        [Parameter(Mandatory=$true)]
        [string] $DestinationContainerImageName,

        [Parameter()]
        [string] $Configuration = "Release"
    )

    if ($IsWindows) {
        throw "This function is only supported on Linux-like operating systems"
    }

    @(
        "docker"
    ) | ForEach-Object {
        if (!(Get-Command $_ -ErrorAction Ignore)) {
            throw "The '$_' command is required to run this function"
        }
    }
    
    # Ensure errors from external tools are propagated to the script - this overridden
    # value will fall out of scope when the function completes
    $PSNativeCommandUseErrorActionPreference = $true

    $basePath = Split-Path -Parent $SourceDiskImagePath
    $baseName = Split-Path -LeafBase $SourceDiskImagePath

    # - Use 'busybox' for non-Release builds to make it easier to inspect the contents
    # of the container image, as it provides a minimal shell
    # - Use 'scratch' for Release builds to optimise for image size
    $diskImageBase = ($Configuration -ne "Release") ? "busybox" : "scratch"
    $tempDockerfile = @"
FROM $diskImageBase
COPY $baseName.img /rootfs.img
"@

    $tempDockerfileName = "Dockerfile.diskimage"
    $tempDockerFilePath = Join-Path ([IO.Path]::GetTempPath()) $tempDockerfileName
    Set-Content -Path $tempDockerFilePath -Value $tempDockerfile

    try {
        $tagVersion = ($ContainerImageVersionOverride -eq "") ? $GitVersion.SemVer : $ContainerImageVersionOverride
        Write-Host "Building '$DestinationContainerImageName-rootfs' with Docker"
        $diskImageContainerTag = "$DestinationContainerImageName-rootfs:$tagVersion"
        & docker build -t $diskImageContainerTag `
                       -f $tempDockerFilePath `
                       $basePath |
            Write-Host
    }
    finally {
        Remove-Item $tempDockerFilePath -Force
    }

    return $diskImageContainerTag
}