summary refs log tree commit diff
path: root/nixos/modules/virtualisation/azure-image.nix
blob: f7949b50137573c62c6b6e490daf8bec275b5e35 (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
{ config, lib, pkgs, ... }:

with lib;
let
  diskSize = "30720";
in
{
  system.build.azureImage =
    pkgs.vmTools.runInLinuxVM (
      pkgs.runCommand "azure-image"
        { preVM =
            ''
              mkdir $out
              diskImage=$out/$diskImageBase

              cyl=$(((${diskSize}*1024*1024)/(512*63*255)))
              size=$(($cyl*255*63*512))              
              roundedsize=$((($size/(1024*1024)+1)*(1024*1024)))
              ${pkgs.vmTools.qemu-220}/bin/qemu-img create -f raw $diskImage $roundedsize
              mv closure xchg/
            '';

          postVM =
            ''
              mkdir -p $out
              ${pkgs.vmTools.qemu-220}/bin/qemu-img convert -f raw -O vpc -o subformat=fixed $diskImage $out/disk.vhd
              rm $diskImage
            '';
          diskImageBase = "nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw";
          buildInputs = [ pkgs.utillinux pkgs.perl ];
          exportReferencesGraph =
            [ "closure" config.system.build.toplevel ];
        }
        ''
          # Create partition table
          ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
          ${pkgs.parted}/sbin/parted /dev/vda mkpart primary ext4 1 ${diskSize}M
          ${pkgs.parted}/sbin/parted /dev/vda print
          . /sys/class/block/vda1/uevent
          mknod /dev/vda1 b $MAJOR $MINOR

          # Create an empty filesystem and mount it.
          ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
          ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1

          mkdir /mnt
          mount /dev/vda1 /mnt

          # The initrd expects these directories to exist.
          mkdir /mnt/dev /mnt/proc /mnt/sys

          mount --bind /proc /mnt/proc
          mount --bind /dev /mnt/dev
          mount --bind /sys /mnt/sys

          # Copy all paths in the closure to the filesystem.
          storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)

          mkdir -p /mnt/nix/store
          echo "copying everything (will take a while)..."
          cp -prd $storePaths /mnt/nix/store/

          echo Register the paths in the Nix database.
          printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
              chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group ""

          echo Create the system profile to allow nixos-rebuild to work.
          chroot /mnt ${config.nix.package}/bin/nix-env \
              -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel} --option build-users-group ""

          echo nixos-rebuild requires an /etc/NIXOS.
          mkdir -p /mnt/etc
          touch /mnt/etc/NIXOS

          echo switch-to-configuration requires a /bin/sh
          mkdir -p /mnt/bin
          ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh

          echo Install a configuration.nix.
          mkdir -p /mnt/etc/nixos /mnt/boot/grub
          cp ${./azure-config-user.nix} /mnt/etc/nixos/configuration.nix

          echo Generate the GRUB menu.
          ln -s vda /dev/sda
          chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot

          echo Almost done
          umount /mnt/proc /mnt/dev /mnt/sys
          umount /mnt
        ''
    );

  imports = [ ./azure-common.nix ];

  # Azure metadata is available as a CD-ROM drive.
  fileSystems."/metadata".device = "/dev/sr0";

  systemd.services.fetch-ssh-keys =
    { description = "Fetch host keys and authorized_keys for root user";

      wantedBy = [ "sshd.service" "waagent.service" ];
      before = [ "sshd.service" "waagent.service" ];
      after = [ "local-fs.target" ];

      path  = [ pkgs.coreutils ];
      script =
        ''
          eval "$(cat /metadata/CustomData.bin)"
          if ! [ -z "$ssh_host_ecdsa_key" ]; then
            echo "downloaded ssh_host_ecdsa_key"
            echo "$ssh_host_ecdsa_key" > /etc/ssh/ssh_host_ed25519_key
            chmod 600 /etc/ssh/ssh_host_ed25519_key
          fi

          if ! [ -z "$ssh_host_ecdsa_key_pub" ]; then
            echo "downloaded ssh_host_ecdsa_key_pub"
            echo "$ssh_host_ecdsa_key_pub" > /etc/ssh/ssh_host_ed25519_key.pub
            chmod 644 /etc/ssh/ssh_host_ed25519_key.pub
          fi

          if ! [ -z "$ssh_root_auth_key" ]; then
            echo "downloaded ssh_root_auth_key"
            mkdir -m 0700 -p /root/.ssh
            echo "$ssh_root_auth_key" > /root/.ssh/authorized_keys
            chmod 600 /root/.ssh/authorized_keys
          fi
        '';
      serviceConfig.Type = "oneshot";
      serviceConfig.RemainAfterExit = true;
      serviceConfig.StandardError = "journal+console";
      serviceConfig.StandardOutput = "journal+console";
     };

}