From c731467e2c83f3df0b59c44575616e6241a63c7d Mon Sep 17 00:00:00 2001 From: aszlig Date: Sat, 15 Feb 2014 23:23:47 +0100 Subject: [PATCH] vm/windows: Split install into several stages. These stages are in particular: * Install of the bare Windows VM with Cygwin and shut down. * Boot up the same VM again without the installation media and dump the VMs memory to state.gz. * Resume from state.gz and build whatever we want to build. Every single stage involves a new "controller", which is more like an abstraction on the Nix side that constructs the madness described in 276b72fb93d60ae0e59088ea0e0029da87e6f31c. Signed-off-by: aszlig --- .../vm/windows/controller/default.nix | 173 +++++++++++++++++ pkgs/build-support/vm/windows/default.nix | 177 ++++-------------- .../vm/windows/install/default.nix | 43 ++++- 3 files changed, 239 insertions(+), 154 deletions(-) create mode 100644 pkgs/build-support/vm/windows/controller/default.nix diff --git a/pkgs/build-support/vm/windows/controller/default.nix b/pkgs/build-support/vm/windows/controller/default.nix new file mode 100644 index 000000000000..49d6815a3dce --- /dev/null +++ b/pkgs/build-support/vm/windows/controller/default.nix @@ -0,0 +1,173 @@ +{ sshKey +, qemuArgs ? [] +, command ? "sync" +, suspendTo ? null +, resumeFrom ? null +, installMode ? false +}: + +let + inherit (import {}) lib stdenv writeScript vmTools makeInitrd; + inherit (import {}) samba vde2 busybox openssh; + inherit (import {}) socat netcat coreutils gzip; + + preInitScript = writeScript "preinit.sh" '' + #!${vmTools.initrdUtils}/bin/ash -e + export PATH=${vmTools.initrdUtils}/bin + mount -t proc none /proc + mount -t sysfs none /sys + for arg in $(cat /proc/cmdline); do + if [ "x''${arg#command=}" != "x$arg" ]; then + command="''${arg#command=}" + fi + done + + for i in $(cat ${modulesClosure}/insmod-list); do + insmod $i + done + + mkdir -p /tmp /dev + mknod /dev/null c 1 3 + mknod /dev/zero c 1 5 + mknod /dev/random c 1 8 + mknod /dev/urandom c 1 9 + mknod /dev/tty c 5 0 + + ifconfig lo up + ifconfig eth0 up 192.168.0.2 + + mkdir -p /nix/store /etc /var/run /var/log + + cat > /etc/passwd < /etc/samba/smb.conf < '${suspendTo}'" + quit + CMD + wait %% + ''; + +in writeScript "run-cygwin-vm.sh" '' + #!${stdenv.shell} -e + ${preVM} + ${vmExec} +'' diff --git a/pkgs/build-support/vm/windows/default.nix b/pkgs/build-support/vm/windows/default.nix index 470fac0437df..2ecadbae7cfb 100644 --- a/pkgs/build-support/vm/windows/default.nix +++ b/pkgs/build-support/vm/windows/default.nix @@ -1,160 +1,49 @@ -with import {}; - -with import { - inherit system; - minimal = false; -}; - let + inherit (import {}) lib stdenv requireFile writeText qemu; + winISO = /path/to/iso/XXX; - base = import ./install { + installedVM = import ./install { isoFile = winISO; productKey = "XXX"; }; - maybeKvm64 = lib.optional (stdenv.system == "x86_64-linux") "-cpu kvm64"; - - cygwinQemuArgs = lib.concatStringsSep " " (maybeKvm64 ++ [ - "-monitor unix:$MONITOR_SOCKET,server,nowait" - "-nographic" - "-boot order=c,once=d" - "-drive file=${base.floppy},readonly,index=0,if=floppy" - "-drive file=winvm.img,index=0,media=disk" - "-drive file=${winISO},index=1,media=cdrom" - "-drive file=${base.iso}/iso/cd.iso,index=2,media=cdrom" - "-net nic,vlan=0,macaddr=52:54:00:12:01:01" - "-net vde,vlan=0,sock=$QEMU_VDE_SOCKET" - "-rtc base=2010-01-01,clock=vm" - ]); - - modulesClosure = lib.overrideDerivation vmTools.modulesClosure (o: { - rootModules = o.rootModules ++ lib.singleton "virtio_net"; + runInVM = img: attrs: import ./controller (attrs // { + inherit (installedVM) sshKey; + qemuArgs = attrs.qemuArgs or [] ++ [ + "-boot order=c" + "-drive file=${img},index=0,media=disk" + ]; }); - controllerQemuArgs = cmd: let - preInitScript = writeScript "preinit.sh" '' - #!${vmTools.initrdUtils}/bin/ash -e - export PATH=${vmTools.initrdUtils}/bin - mount -t proc none /proc - mount -t sysfs none /sys - for arg in $(cat /proc/cmdline); do - if [ "x''${arg#command=}" != "x$arg" ]; then - command="''${arg#command=}" - fi - done - - for i in $(cat ${modulesClosure}/insmod-list); do - insmod $i - done - - mkdir -p /tmp /dev - mknod /dev/null c 1 3 - mknod /dev/zero c 1 5 - mknod /dev/random c 1 8 - mknod /dev/urandom c 1 9 - mknod /dev/tty c 5 0 - - ifconfig lo up - ifconfig eth0 up 192.168.0.2 - - mkdir -p /nix/store /etc /var/run /var/log - - cat > /etc/passwd < /etc/samba/smb.conf < '$out/state.gz'" - CMD cp winvm.img "$out/disk.img" + cp state.gz "$out/state.gz" ''; }; -in bootstrap + resumeAndRun = command: runInVM "${suspendedVM}/disk.img" { + resumeFrom = "${suspendedVM}/state.gz"; + qemuArgs = lib.singleton "-snapshot"; + inherit command; + }; + + runFromSuspended = command: stdenv.mkDerivation { + name = "cygwin-vm-run"; + buildCommand = '' + ${resumeAndRun command} + ''; + }; + +in runFromSuspended "uname -a" diff --git a/pkgs/build-support/vm/windows/install/default.nix b/pkgs/build-support/vm/windows/install/default.nix index 0021bae87bc8..d766cbcf8e3a 100644 --- a/pkgs/build-support/vm/windows/install/default.nix +++ b/pkgs/build-support/vm/windows/install/default.nix @@ -3,7 +3,7 @@ }: let - inherit (import {}) lib stdenv runCommand openssh; + inherit (import {}) lib stdenv runCommand openssh qemu; bootstrapAfterLogin = runCommand "bootstrap.sh" {} '' cat > "$out" <> /etc/fstab + shutdown -s now EOF ''; @@ -28,10 +28,16 @@ let ''; }; - packages = [ "openssh" ]; + sshKey = "${cygwinSshKey}/key"; -in { - iso = import ../cygwin-iso { + packages = [ "openssh" "shutdown" ]; + + instfloppy = import ./unattended-image.nix { + cygwinPackages = packages; + inherit productKey; + }; + + cygiso = import ../cygwin-iso { inherit packages; extraContents = lib.singleton { source = bootstrapAfterLogin; @@ -39,10 +45,27 @@ in { }; }; - floppy = import ./unattended-image.nix { - cygwinPackages = packages; - inherit productKey; + installController = import ../controller { + inherit sshKey; + installMode = true; + qemuArgs = [ + "-boot order=c,once=d" + "-drive file=${instfloppy},readonly,index=0,if=floppy" + "-drive file=winvm.img,index=0,media=disk" + "-drive file=${isoFile},index=1,media=cdrom" + "-drive file=${cygiso}/iso/cd.iso,index=2,media=cdrom" + ]; }; - sshKey = "${cygwinSshKey}/key"; +in stdenv.mkDerivation { + name = "cygwin-base-vm"; + buildCommand = '' + ${qemu}/bin/qemu-img create -f qcow2 winvm.img 2G + ${installController} + ensureDir "$out" + cp winvm.img "$out/disk.img" + ''; + passthru = { + inherit sshKey; + }; }