From aa774387d38e6b83d4ead8f79f0bd3f6abfc0116 Mon Sep 17 00:00:00 2001 From: Jonas Finnemann Jensen Date: Tue, 27 Jun 2017 17:37:07 -0700 Subject: [PATCH] Added windows image recipe --- .gitignore | 1 + examples/windows-image/build-windows-setup.sh | 29 +++ examples/windows-image/constants.sh | 18 ++ examples/windows-image/data/Autounattend.xml | 183 ++++++++++++++++++ examples/windows-image/data/README.md | 16 ++ examples/windows-image/data/install.ps1 | 6 + examples/windows-image/data/setup.ps1 | 31 +++ .../windows-image/data/unattended-setup.ps1 | 17 ++ examples/windows-image/data/wrap-setup.cmd | 3 + .../data/wrap-unattended-setup.cmd | 3 + examples/windows-image/download.sh | 30 +++ examples/windows-image/machine.json | 15 ++ tc-worker-env.Dockerfile | 2 +- 13 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 examples/windows-image/build-windows-setup.sh create mode 100644 examples/windows-image/constants.sh create mode 100644 examples/windows-image/data/Autounattend.xml create mode 100644 examples/windows-image/data/README.md create mode 100644 examples/windows-image/data/install.ps1 create mode 100644 examples/windows-image/data/setup.ps1 create mode 100644 examples/windows-image/data/unattended-setup.ps1 create mode 100644 examples/windows-image/data/wrap-setup.cmd create mode 100644 examples/windows-image/data/wrap-unattended-setup.cmd create mode 100644 examples/windows-image/download.sh create mode 100644 examples/windows-image/machine.json diff --git a/.gitignore b/.gitignore index f82c1176..72e2d802 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ coverage.out /vendor/*/ /config.env /examples/ubuntu-image/cache/ +/examples/windows-image/cache/ diff --git a/examples/windows-image/build-windows-setup.sh b/examples/windows-image/build-windows-setup.sh new file mode 100644 index 00000000..4d4e662e --- /dev/null +++ b/examples/windows-image/build-windows-setup.sh @@ -0,0 +1,29 @@ +#!/bin/bash -e + +# Load constants +source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/constants.sh" + +# Create temporary files +DATA=`mktemp -d`; +ISO="$DIR/cache/data.iso"; +TCWORKER=`mktemp`; + +echo '### Building taskcluster-worker for host (for building image)' +go build -o "$TCWORKER" github.com/taskcluster/taskcluster-worker + +echo '### Building taskcluster-worker for image (for use inside image)' +CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o "$DATA/taskcluster-worker.exe" \ + github.com/taskcluster/taskcluster-worker + +echo '### Packaging data.iso' +cp "$DIR/data"/* "$DATA/" +7z x -o"$DATA/" "$VIRTIO_WIN_ISO" +genisoimage -vJrV DATA_VOLUME -input-charset utf-8 -o "$ISO" "$DATA" + +echo "### Building $WORKER_IMAGE_NAME" +"$TCWORKER" qemu-build --boot "$INSTALLER_ISO" --cdrom "$ISO" --size "$DISKSIZE" \ + from-new "$DIR/machine.json" "$DIR/cache/$WORKER_IMAGE_NAME" + +echo '### Removing temporary files' +rm -rf "$DATA" +rm -f "$ISO" "$TCWORKER" diff --git a/examples/windows-image/constants.sh b/examples/windows-image/constants.sh new file mode 100644 index 00000000..88ac154d --- /dev/null +++ b/examples/windows-image/constants.sh @@ -0,0 +1,18 @@ +#!/bin/bash -e + +# Find location of the script no matter where it's located +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Installer ISO +INSTALLER_S3_BUCKET='private-qemu-images' +INSTALLER_S3_KEY='en_windows_10_enterprise_version_1703_updated_march_2017_x64_dvd_10189290.iso' +INSTALLER_ISO="$DIR/cache/windows_10_x64.iso" + +# virtio-win +VIRTIO_WIN_URL='https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.137-1/virtio-win.iso' +VIRTIO_WIN_ISO="$DIR/cache/virtio-win-0.1.137.iso" + +DISKSIZE='20' # GB +IMAGE_GOARCH='amd64' + +WORKER_IMAGE_NAME='windows-worker.tar.zst' diff --git a/examples/windows-image/data/Autounattend.xml b/examples/windows-image/data/Autounattend.xml new file mode 100644 index 00000000..f6bc21ad --- /dev/null +++ b/examples/windows-image/data/Autounattend.xml @@ -0,0 +1,183 @@ + + + + + + + en-US + + 0409:00000409 + en-US + en-US + en-US + en-US + + + + + + E:\viorng\w10\amd64 + E:\viostor\w10\amd64 + E:\qxldod\w10\amd64 + E:\Balloon\w10\amd64 + E:\NetKVM\w10\amd64 + E:\vioserial\w10\amd64 + E:\vioinput\w10\amd64 + E:\vioscsi\w10\amd64 + E:\pvpanic\w10\amd64 + + E:\qemufwcfg + E:\qemupciserial + + + + + + + + 1 + Primary + 100 + + + true + 2 + Primary + + + + + true + NTFS + + 1 + 1 + 0x27 + + + true + NTFS + + C + 2 + 2 + + + 0 + true + + + + + + 0 + 2 + + false + + + + true + worker + + + + NPPR9-FWDCX-D2C8J-H872K-2YT43 + Never + + + false + + + + + false + + + + + 1 + + + + + 0409:00000409 + en-US + en-US + en-US + en-US + + + true + + + 0 + + + vm + NPPR9-FWDCX-D2C8J-H872K-2YT43 + + + + + + + + true</PlainText> + </Password> + <Enabled>true</Enabled> + <Username>worker</Username> + </AutoLogon> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <NetworkLocation>Home</NetworkLocation> + <SkipUserOOBE>true</SkipUserOOBE> + <SkipMachineOOBE>true</SkipMachineOOBE> + <!-- Skip all security updates --> + <ProtectYourPC>3</ProtectYourPC> + </OOBE> + <UserAccounts> + <LocalAccounts> + <LocalAccount wcm:action="add"> + <Password> + <Value></Value> + <PlainText>true</PlainText> + </Password> + <Description>test user</Description> + <DisplayName>worker</DisplayName> + <Group>Administrators</Group> + <Name>worker</Name> + </LocalAccount> + </LocalAccounts> + </UserAccounts> + <RegisteredOrganization>Mozilla</RegisteredOrganization> + <RegisteredOwner>worker</RegisteredOwner> + <DisableAutoDaylightTimeSet>true</DisableAutoDaylightTimeSet> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <Description>Run Customization Scripts</Description> + <Order>1</Order> + <CommandLine>E:\wrap-unattended-setup.cmd</CommandLine> + <RequiresUserInput>false</RequiresUserInput> + </SynchronousCommand> + </FirstLogonCommands> + <TimeZone>UTC</TimeZone> + </component> + </settings> +</unattend> diff --git a/examples/windows-image/data/README.md b/examples/windows-image/data/README.md new file mode 100644 index 00000000..b49028d1 --- /dev/null +++ b/examples/windows-image/data/README.md @@ -0,0 +1,16 @@ +Unattended Windows Install +========================== + +./taskcluster-worker qemu-run -V playground/windows/cache/windows-setup.tar.zst -- true + +## Windows Activation + 1. Set timezone and date-time correct + 2. `cscript slmgr.vbs -skms-domain mozilla.com` now auto-discovery works + 3. `cscript slmgr.vbs -ato` activate windows + + +<!--- -C "powershell.exe -ExecutionPolicy ByPass -File 'D:\setup.ps1' | D:\taskcluster-worker.exe qemu-guest-tools post-log -" ---> + +C:\Windows\WindowsPowerShell\v1.0\powershell.exe -File E:\setup.ps1 | E:\taskcluster-worker.exe qemu-guest-tools post-log - + +ping markco for windows help... diff --git a/examples/windows-image/data/install.ps1 b/examples/windows-image/data/install.ps1 new file mode 100644 index 00000000..9b6bc3d5 --- /dev/null +++ b/examples/windows-image/data/install.ps1 @@ -0,0 +1,6 @@ +# Script executed by setup.ps1 after taskcluster-worker qemu-guest-tools have +# been installed. When this script completes the computer will shutdown and +# image will be created. +write-host "...install whatever should be in this image" +Start-Sleep -s 5 +write-host "done..." diff --git a/examples/windows-image/data/setup.ps1 b/examples/windows-image/data/setup.ps1 new file mode 100644 index 00000000..ed89d88e --- /dev/null +++ b/examples/windows-image/data/setup.ps1 @@ -0,0 +1,31 @@ +# This script is executed by wrap-setup.cmd which is triggered by setup.lnk +# on the user-login. This script will do the following: +# 1) Remove setup.lnk, +# 2) Install taskcluster-worker qemu-guest-tools, +# 3) Run install.ps1, and, +# 4) Shutdown the machine. + +write-host "Removing setup.lnk that triggered this script" +$AppDataFolder = "$env:appdata" +Remove-Item "$AppDataFolder\Microsoft\Windows\Start Menu\Programs\Startup\setup.lnk" + +write-host "Installing taskcluster-worker qemu-guest-tools" +$Media = "E:" +$AppDataFolder = "$env:appdata" +$ProgramFilesFolder = "$env:ProgramFiles" +$taskclusterWorkerPath = "$ProgramFilesFolder\taskcluster" + +New-Item -ItemType Directory -Force -Path "$taskclusterWorkerPath" +Copy-Item "$Media\taskcluster-worker.exe" "$taskclusterWorkerPath" + +$WSHShell = New-Object -comObject WScript.Shell +$Shortcut = $WSHShell.CreateShortcut("$AppDataFolder\Microsoft\Windows\Start Menu\Programs\Startup\taskcluster-worker qemu-guest-tools.lnk") +$Shortcut.TargetPath = "$taskclusterWorkerPath\taskcluster-worker.exe" +$Shortcut.Arguments = "qemu-guest-tools" +$Shortcut.Save() + +write-host "Running install.ps1" +& "$Media\install.ps1" + +write-host "Setup Completed" +Stop-Computer diff --git a/examples/windows-image/data/unattended-setup.ps1 b/examples/windows-image/data/unattended-setup.ps1 new file mode 100644 index 00000000..0c9f44f4 --- /dev/null +++ b/examples/windows-image/data/unattended-setup.ps1 @@ -0,0 +1,17 @@ +# This script is called by wrap-unattended-setup.cmd and it's output is sent +# the taskcluster-worker qemu-build process over the meta-data service. +# +# This script installs wrap-setup.cmd to be executed on login. +# Then wrap-setup.cmd will run setup.ps1, which will remove this script and +# and install taskcluster-worker qemu-guest-tools + +write-host "Installing startup link to run wrap-setup.cmd on login" + +$Media = "E:\" +$AppDataFolder = "$env:appdata" + +New-Item -ItemType Directory -Force -Path "$AppDataFolder\Microsoft\Windows\Start Menu\Programs\Startup" +$WSHShell = New-Object -comObject WScript.Shell +$Shortcut = $WSHShell.CreateShortcut("$AppDataFolder\Microsoft\Windows\Start Menu\Programs\Startup\setup.lnk") +$Shortcut.TargetPath = "E:\wrap-setup.cmd" +$Shortcut.Save() diff --git a/examples/windows-image/data/wrap-setup.cmd b/examples/windows-image/data/wrap-setup.cmd new file mode 100644 index 00000000..5b6a8b6c --- /dev/null +++ b/examples/windows-image/data/wrap-setup.cmd @@ -0,0 +1,3 @@ +:: Batch script for running setup.ps1 and posting the log as we go +:: It is executed by setup.lnk at login, created by unattended-setup.ps1 +C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -File E:\setup.ps1 | E:\taskcluster-worker.exe qemu-guest-tools post-log - diff --git a/examples/windows-image/data/wrap-unattended-setup.cmd b/examples/windows-image/data/wrap-unattended-setup.cmd new file mode 100644 index 00000000..b2af6913 --- /dev/null +++ b/examples/windows-image/data/wrap-unattended-setup.cmd @@ -0,0 +1,3 @@ +:: Batch script for running unattended-setup.ps1 and posting the log as we go +:: This is executed by unattended.xml at first login +C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -File E:\unattended-setup.ps1 | E:\taskcluster-worker.exe qemu-guest-tools post-log - diff --git a/examples/windows-image/download.sh b/examples/windows-image/download.sh new file mode 100644 index 00000000..cc82f3a3 --- /dev/null +++ b/examples/windows-image/download.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Load constants +source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/constants.sh" + +# Ensure cache dir exists +mkdir -p "$DIR/cache"; + +# Download Windows ISO +if ! [ -f "$INSTALLER_ISO" ]; then + if [ -z "$AWS_ACCESS_KEY_ID" ]; then + echo 'Fetching S3 credentials' + # Get S3 credentials through auth.taskcluster.net using tcproxy (only works from a task) + # requires task.scopes: 'auth:aws-s3:read-only:private-qemu-images/*' + curl -L --retry 10 "http://taskcluster/tcproxy/auth.taskcluster.net/v1/aws/s3/read-only/$INSTALLER_S3_BUCKET/$INSTALLER_S3_KEY" > /tmp/s3-credentials.json + export AWS_ACCESS_KEY_ID=`cat /tmp/s3-credentials.json | jq -r .credentials.accessKeyId` + export AWS_SECRET_ACCESS_KEY=`cat /tmp/s3-credentials.json | jq -r .credentials.secretAccessKey` + export AWS_SESSION_TOKEN=`cat /tmp/s3-credentials.json | jq -r .credentials.sessionToken` + rm -rf /tmp/s3-credentials.json + fi + + echo 'Downloading Windows ISO' + aws s3 cp "s3://$INSTALLER_S3_BUCKET/$INSTALLER_S3_KEY" "$INSTALLER_ISO" +fi + +# Download virtio ISO +if ! [ -f "$VIRTIO_WIN_ISO" ]; then + echo 'Downloading virtio ISO' + curl -L --retry 10 "$VIRTIO_WIN_URL" -o "$VIRTIO_WIN_ISO" +fi diff --git a/examples/windows-image/machine.json b/examples/windows-image/machine.json new file mode 100644 index 00000000..a4ed003f --- /dev/null +++ b/examples/windows-image/machine.json @@ -0,0 +1,15 @@ +{ + "version": 1, + "uuid": "52bab607-10f1-4049-a0f8-ee4725cb715b", + "chipset": "pc-i440fx-2.8", + "usb": "nec-usb-xhci", + "network": "e1000", + "mac": "aa:54:1a:30:5c:de", + "storage": "virtio-blk-pci", + "graphics": "qxl-vga", + "sound": "none", + "keyboard": "usb-kbd", + "keyboardLayout": "en-us", + "mouse": "usb-mouse", + "tablet": "usb-tablet" +} diff --git a/tc-worker-env.Dockerfile b/tc-worker-env.Dockerfile index 4c96c805..86465ccc 100644 --- a/tc-worker-env.Dockerfile +++ b/tc-worker-env.Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update -y \ && apt-get upgrade -y \ && apt-get install -y \ qemu-system-x86 qemu-utils dnsmasq-base iptables iproute2 \ - git curl screen nano genisoimage build-essential openvpn + git curl screen nano genisoimage build-essential openvpn awscli jq # Install golang 1.8 RUN curl -L https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz > /tmp/go.tar.gz \