1{ config, lib, pkgs, ... }: 2 3with lib; 4let 5 diskSize = "20G"; 6in 7{ 8 imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ]; 9 10 system.build.brightboxImage = 11 pkgs.vmTools.runInLinuxVM ( 12 pkgs.runCommand "brightbox-image" 13 { preVM = 14 '' 15 mkdir $out 16 diskImage=$out/$diskImageBase 17 truncate $diskImage --size ${diskSize} 18 mv closure xchg/ 19 ''; 20 21 postVM = 22 '' 23 PATH=$PATH:${pkgs.gnutar}/bin:${pkgs.gzip}/bin 24 pushd $out 25 ${pkgs.qemu_kvm}/bin/qemu-img convert -c -O qcow2 $diskImageBase nixos.qcow2 26 rm $diskImageBase 27 popd 28 ''; 29 diskImageBase = "nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw"; 30 buildInputs = [ pkgs.utillinux pkgs.perl ]; 31 exportReferencesGraph = 32 [ "closure" config.system.build.toplevel ]; 33 } 34 '' 35 # Create partition table 36 ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos 37 ${pkgs.parted}/sbin/parted /dev/vda mkpart primary ext4 1 ${diskSize} 38 ${pkgs.parted}/sbin/parted /dev/vda print 39 . /sys/class/block/vda1/uevent 40 mknod /dev/vda1 b $MAJOR $MINOR 41 42 # Create an empty filesystem and mount it. 43 ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1 44 ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1 45 46 mkdir /mnt 47 mount /dev/vda1 /mnt 48 49 # The initrd expects these directories to exist. 50 mkdir /mnt/dev /mnt/proc /mnt/sys 51 52 mount --bind /proc /mnt/proc 53 mount --bind /dev /mnt/dev 54 mount --bind /sys /mnt/sys 55 56 # Copy all paths in the closure to the filesystem. 57 storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure) 58 59 mkdir -p /mnt/nix/store 60 echo "copying everything (will take a while)..." 61 cp -prd $storePaths /mnt/nix/store/ 62 63 # Register the paths in the Nix database. 64 printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \ 65 chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group "" 66 67 # Create the system profile to allow nixos-rebuild to work. 68 chroot /mnt ${config.nix.package}/bin/nix-env \ 69 -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel} \ 70 --option build-users-group "" 71 72 # `nixos-rebuild' requires an /etc/NIXOS. 73 mkdir -p /mnt/etc 74 touch /mnt/etc/NIXOS 75 76 # `switch-to-configuration' requires a /bin/sh 77 mkdir -p /mnt/bin 78 ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh 79 80 # Install a configuration.nix. 81 mkdir -p /mnt/etc/nixos /mnt/boot/grub 82 cp ${./brightbox-config.nix} /mnt/etc/nixos/configuration.nix 83 84 # Generate the GRUB menu. 85 ln -s vda /dev/sda 86 chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot 87 88 umount /mnt/proc /mnt/dev /mnt/sys 89 umount /mnt 90 '' 91 ); 92 93 fileSystems."/".label = "nixos"; 94 95 # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. 96 boot.loader.grub.device = "/dev/vda"; 97 boot.loader.grub.timeout = 0; 98 99 # Don't put old configurations in the GRUB menu. The user has no 100 # way to select them anyway. 101 boot.loader.grub.configurationLimit = 0; 102 103 # Allow root logins only using the SSH key that the user specified 104 # at instance creation time. 105 services.openssh.enable = true; 106 services.openssh.permitRootLogin = "without-password"; 107 108 # Force getting the hostname from Google Compute. 109 networking.hostName = mkDefault ""; 110 111 # Always include cryptsetup so that NixOps can use it. 112 environment.systemPackages = [ pkgs.cryptsetup ]; 113 114 systemd.services."fetch-ec2-data" = 115 { description = "Fetch EC2 Data"; 116 117 wantedBy = [ "multi-user.target" "sshd.service" ]; 118 before = [ "sshd.service" ]; 119 wants = [ "ip-up.target" ]; 120 after = [ "ip-up.target" ]; 121 122 path = [ pkgs.wget pkgs.iproute ]; 123 124 script = 125 '' 126 wget="wget -q --retry-connrefused -O -" 127 128 ${optionalString (config.networking.hostName == "") '' 129 echo "setting host name..." 130 ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/latest/meta-data/hostname) 131 ''} 132 133 # Don't download the SSH key if it has already been injected 134 # into the image (a Nova feature). 135 if ! [ -e /root/.ssh/authorized_keys ]; then 136 echo "obtaining SSH key..." 137 mkdir -m 0700 -p /root/.ssh 138 $wget http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /root/key.pub 139 if [ $? -eq 0 -a -e /root/key.pub ]; then 140 if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then 141 cat /root/key.pub >> /root/.ssh/authorized_keys 142 echo "new key added to authorized_keys" 143 fi 144 chmod 600 /root/.ssh/authorized_keys 145 rm -f /root/key.pub 146 fi 147 fi 148 149 # Extract the intended SSH host key for this machine from 150 # the supplied user data, if available. Otherwise sshd will 151 # generate one normally. 152 $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true 153 key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)" 154 key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)" 155 if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then 156 mkdir -m 0755 -p /etc/ssh 157 (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) 158 echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub 159 fi 160 ''; 161 162 serviceConfig.Type = "oneshot"; 163 serviceConfig.RemainAfterExit = true; 164 }; 165 166}