about summary refs log tree commit diff
path: root/pkgs/build-support/vm/windows/default.nix
blob: 470fac0437dfecb74b2823166e5f647d4abd3b21 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
with import <nixpkgs> {};

with import <nixpkgs/nixos/lib/build-vms.nix> {
  inherit system;
  minimal = false;
};

let
  winISO = /path/to/iso/XXX;

  base = 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";
  });

  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 <<PASSWD
      root:x:0:0::/root:/bin/false
      nobody:x:65534:65534::/var/empty:/bin/false
      PASSWD

      mount -t 9p \
        -o trans=virtio,version=9p2000.L,msize=262144,cache=loose \
        store /nix/store

      exec "$command"
    '';
    initrd = makeInitrd {
      contents = lib.singleton {
        object = preInitScript;
        symlink = "/init";
      };
    };
    initScript = writeScript "init.sh" ''
      #!${stdenv.shell}
      ${coreutils}/bin/mkdir -p /etc/samba /etc/samba/private /var/lib/samba
      ${coreutils}/bin/cat > /etc/samba/smb.conf <<CONFIG
      [global]
      security = user
      map to guest = Bad User
      workgroup = cygwin
      netbios name = controller
      server string = %h
      log level = 1
      max log size = 1000
      log file = /var/log/samba.log

      [nixstore]
      path = /nix/store
      read only = no
      guest ok = yes
      CONFIG

      ${samba}/sbin/nmbd -D
      ${samba}/sbin/smbd -D
      ${coreutils}/bin/cp -L "${base.sshKey}" /ssh.key
      ${coreutils}/bin/chmod 600 /ssh.key

      echo -n "Waiting for Windows VM to become ready"
      while ! ${netcat}/bin/netcat -z 192.168.0.1 22; do
        echo -n .
        ${coreutils}/bin/sleep 1
      done
      echo " ready."

      ${openssh}/bin/ssh \
        -o UserKnownHostsFile=/dev/null \
        -o StrictHostKeyChecking=no \
        -i /ssh.key \
        -l Administrator \
        192.168.0.1 -- "${cmd}"

      ${busybox}/sbin/poweroff -f
    '';
    kernelAppend = lib.concatStringsSep " " [
      "panic=1"
      "loglevel=4"
      "console=tty1"
      "console=ttyS0"
      "command=${initScript}"
    ];
  in lib.concatStringsSep " " (maybeKvm64 ++ [
    "-nographic"
    "-no-reboot"
    "-virtfs local,path=/nix/store,security_model=none,mount_tag=store"
    "-kernel ${modulesClosure.kernel}/bzImage"
    "-initrd ${initrd}/initrd"
    "-append \"${kernelAppend}\""
    "-net nic,vlan=0,macaddr=52:54:00:12:01:02,model=virtio"
    "-net vde,vlan=0,sock=$QEMU_VDE_SOCKET"
  ]);

  bootstrap = stdenv.mkDerivation {
    name = "windown-vm";

    buildCommand = ''
      ${qemu}/bin/qemu-img create -f qcow2 winvm.img 2G
      QEMU_VDE_SOCKET="$(pwd)/vde.ctl"
      MONITOR_SOCKET="$(pwd)/monitor"
      ${vde2}/bin/vde_switch -s "$QEMU_VDE_SOCKET" &
      ${vmTools.qemuProg} ${cygwinQemuArgs} &
      ${vmTools.qemuProg} ${controllerQemuArgs "sync"}

      ensureDir "$out"
      ${socat}/bin/socat - UNIX-CONNECT:$MONITOR_SOCKET <<CMD
      stop
      migrate_set_speed 4095m
      migrate "exec:${gzip}/bin/gzip -c > '$out/state.gz'"
      CMD
      cp winvm.img "$out/disk.img"
    '';
  };

in bootstrap