Building a Daily Ubuntu image for Hyper-V

After getting my Windows Image Factory up and running – the next thing I started to look at was how to create an “always up-to-date Ubuntu image”.  To solve this problem I ended up taking a very different route.  Some of the tools / services I used are as follows:

  • Ubuntu Cloud Images: Canonical provides daily builds of Ubuntu server for cloud deployments (https://cloud-images.ubuntu.com/).  My script checks for the latest one and pulls it down.
  • Cloud-init: The Ubuntu cloud images come preloaded with the Cloud-init client (https://cloudinit.readthedocs.org/en/latest/) – so I use this to customize the image.
  • Qemu-img: As I mentioned yesterday, qemu-img is a great tool that helps you to convert KVM images (like the ones provided by Canonical) into Hyper-V Images.
  • OSCDimg: As part of this script I need to create an ISO image on the fly.  I do this using OSCDimg – which is part of the deployment tools in the Windows ADK

This script will then:

  • Check if we already have the latest Ubuntu cloud image
  • If not – download the latest
  • Create Cloud-init metadata files
  • Convert the Qemu image to Hyper-V
  • Create an ISO with the Cloud-init metadata files in it
  • Create a virtual machine
  • Start the virtual machine, and connect to it

The script is also attached to the end of this blog post.

 

$tempPath = [System.IO.Path]::GetTempPath() + [System.Guid]::NewGuid().ToString()

 

# ADK Download - https://www.microsoft.com/en-us/download/confirmation.aspx?id=39982

# You only need to install the deployment tools

$oscdimgPath = "C:\Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"

 

# Download qemu-img from here: https://www.cloudbase.it/qemu-img-windows/

$qemuImgPath = "C:\Working Space\qemu-img\qemu-img.exe"

 

# Update this to the release of Ubuntu that you want

$ubuntuPath = "https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64"

 

$GuestOSName = "Hyper-V-VM"

$GuestOSID = "iid-123456"

$GuestAdminPassword = "P@ssw0rd"

 

$VMName = "Ubuntu Test"

$virtualSwitchName = "Virtual Switch"

 

$vmPath = "C:\Working Space\VM"

$imageCachePath = "C:\Working Space"

$vhdx = "$($vmPath)\test.vhdx"

$metaDataIso = "$($vmPath)\metadata.iso"

 

# Get the timestamp of the latest build on the Ubuntu cloud-images site

$stamp = (Invoke-WebRequest "$($ubuntuPath).manifest").BaseResponse.LastModified.ToFileTimeUtc()

 

$metadata = @"

instance-id: $($GuestOSID)

local-hostname: $($GuestOSName)

"@

 

$userdata = @"

#cloud-config

password: $($GuestAdminPassword)

runcmd:

 - [ useradd, -m, -p, "", ben ]

 - [ chage, -d, 0, ben ]

"@

 

# Check Paths

if (!(test-path $vmPath)) {mkdir $vmPath}

if (!(test-path $imageCachePath)) {mkdir $imageCachePath}

 

# Helper function for no error file cleanup

Function cleanupFile ([string]$file) {if (test-path $file) {Remove-Item $file}}

 

# Delete the VM if it is around

If ((Get-VM | ? name -eq $VMName).Count -gt 0)

      {stop-vm $VMName -TurnOff -Confirm:$false -Passthru | Remove-VM -Force}

 

cleanupFile $vhdx

cleanupFile $metaDataIso

 

# Make temp location

md -Path $tempPath

md -Path "$($tempPath)\Bits"

 

if (!(test-path "$($imageCachePath)\ubuntu-$($stamp).img")) {

      # If we do not have a matching image - delete the old ones and download the new one

      Remove-Item "$($imageCachePath)\ubuntu-*.img"

      Invoke-WebRequest "$($ubuntuPath)-disk1.img" -UseBasicParsing -OutFile "$($imageCachePath)\ubuntu-$($stamp).img"

                  }

 

# Output meta and user data to files

sc "$($tempPath)\Bits\meta-data" ([byte[]][char[]] "$metadata") -Encoding Byte

sc "$($tempPath)\Bits\user-data" ([byte[]][char[]] "$userdata") -Encoding Byte

 

# Convert cloud image to VHDX

& $qemuImgPath convert -f qcow2 "$($imageCachePath)\ubuntu-$($stamp).img" -O vhdx -o subformat=dynamic $vhdx

Resize-VHD -Path $vhdx -SizeBytes 50GB

 

# Create meta data ISO image

& $oscdimgPath "$($tempPath)\Bits" $metaDataIso -j2 -lcidata

 

# Clean up temp directory

rd -Path $tempPath -Recurse -Force

 

# Create new virtual machine and start it

new-vm $VMName -MemoryStartupBytes 2048mb -VHDPath $vhdx -Generation 1 `

               -SwitchName $virtualSwitchName -Path $vmPath | Out-Null

set-vm -Name $VMName -ProcessorCount 2

Set-VMDvdDrive -VMName $VMName -Path $metaDataIso

Start-VM $VMName

 

# Open up VMConnect

Invoke-Expression "vmconnect.exe localhost `"$VMName`""

Cheers,
Ben 

UbuntuBuild.zip