From 3da94435c07d09c792d56d1a4547668422d7c539 Mon Sep 17 00:00:00 2001 From: Rob Vermaas Date: Wed, 21 May 2014 10:55:34 +0200 Subject: [PATCH] Add option ec2.hvm, to set some boot configuration specific for EC2 HVM instances. (cherry picked from commit 35c76d917307b7ac405486855cfe63021810dba5) Conflicts: nixos/modules/virtualisation/amazon-image.nix --- nixos/modules/virtualisation/amazon-image.nix | 277 ++++++++++-------- 1 file changed, 148 insertions(+), 129 deletions(-) diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix index 138047a07db0..9e64327c3abd 100644 --- a/nixos/modules/virtualisation/amazon-image.nix +++ b/nixos/modules/virtualisation/amazon-image.nix @@ -1,164 +1,183 @@ { config, lib, pkgs, ... }: with lib; - +let + cfg = config.ec2; +in { imports = [ ../profiles/headless.nix ./ec2-data.nix ]; - system.build.amazonImage = - pkgs.vmTools.runInLinuxVM ( - pkgs.runCommand "amazon-image" - { preVM = - '' - mkdir $out - diskImage=$out/nixos.img - ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "4G" - mv closure xchg/ - ''; - buildInputs = [ pkgs.utillinux pkgs.perl ]; - exportReferencesGraph = - [ "closure" config.system.build.toplevel ]; - } - '' - # Create an empty filesystem and mount it. - ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda - ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda - mkdir /mnt - mount /dev/vda /mnt + options = { + ec2 = { + hvm = mkOption { + default = false; + description = '' + Whether the EC2 instance is a HVM instance. + ''; + }; + }; + }; - # The initrd expects these directories to exist. - mkdir /mnt/dev /mnt/proc /mnt/sys + config = { + system.build.amazonImage = + pkgs.vmTools.runInLinuxVM ( + pkgs.runCommand "amazon-image" + { preVM = + '' + mkdir $out + diskImage=$out/nixos.img + ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "4G" + mv closure xchg/ + ''; + buildInputs = [ pkgs.utillinux pkgs.perl ]; + exportReferencesGraph = + [ "closure" config.system.build.toplevel ]; + } + '' + # Create an empty filesystem and mount it. + ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda + ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda + mkdir /mnt + mount /dev/vda /mnt - mount -o bind /proc /mnt/proc + # The initrd expects these directories to exist. + mkdir /mnt/dev /mnt/proc /mnt/sys - # Copy all paths in the closure to the filesystem. - storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure) + mount -o bind /proc /mnt/proc - mkdir -p /mnt/nix/store - echo "copying everything (will take a while)..." - cp -prd $storePaths /mnt/nix/store/ + # Copy all paths in the closure to the filesystem. + storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure) - # 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 + mkdir -p /mnt/nix/store + echo "copying everything (will take a while)..." + cp -prd $storePaths /mnt/nix/store/ - # 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} + # 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 - # `nixos-rebuild' requires an /etc/NIXOS. - mkdir -p /mnt/etc - touch /mnt/etc/NIXOS + # 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} - # `switch-to-configuration' requires a /bin/sh - mkdir -p /mnt/bin - ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh + # `nixos-rebuild' requires an /etc/NIXOS. + mkdir -p /mnt/etc + touch /mnt/etc/NIXOS - # Install a configuration.nix. - mkdir -p /mnt/etc/nixos - cp ${./amazon-config.nix} /mnt/etc/nixos/configuration.nix + # `switch-to-configuration' requires a /bin/sh + mkdir -p /mnt/bin + ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh - # Generate the GRUB menu. - chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot + # Install a configuration.nix. + mkdir -p /mnt/etc/nixos + cp ${./amazon-config.nix} /mnt/etc/nixos/configuration.nix - umount /mnt/proc - umount /mnt - '' - ); + # Generate the GRUB menu. + chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot - fileSystems."/".device = "/dev/disk/by-label/nixos"; + umount /mnt/proc + umount /mnt + '' + ); - boot.initrd.kernelModules = [ "xen-blkfront" ]; - boot.kernelModules = [ "xen-netfront" ]; - boot.kernelParams = [ "console=ttyS0" ]; + fileSystems."/".device = "/dev/disk/by-label/nixos"; - # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. - boot.loader.grub.version = 1; - boot.loader.grub.device = "nodev"; - boot.loader.grub.timeout = 0; - boot.loader.grub.extraPerEntryConfig = "root (hd0)"; + boot.initrd.kernelModules = [ "xen-blkfront" ]; + boot.kernelModules = [ "xen-netfront" ]; - boot.initrd.postDeviceCommands = - '' - # Force udev to exit to prevent random "Device or resource busy - # while trying to open /dev/xvda" errors from fsck. - udevadm control --exit || true - kill -9 -1 - ''; + # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. + boot.loader.grub.version = 1; + boot.loader.grub.device = if cfg.hvm then "/dev/xvda" else "nodev"; + boot.loader.grub.timeout = 0; + boot.loader.grub.extraPerEntryConfig = "root (hd0${lib.optionalString cfg.hvm ",0"})"; - # Mount all formatted ephemeral disks and activate all swap devices. - # We cannot do this with the ‘fileSystems’ and ‘swapDevices’ options - # because the set of devices is dependent on the instance type - # (e.g. "m1.large" has one ephemeral filesystem and one swap device, - # while "m1.large" has two ephemeral filesystems and no swap - # devices). Also, put /tmp and /var on /disk0, since it has a lot - # more space than the root device. Similarly, "move" /nix to /disk0 - # by layering a unionfs-fuse mount on top of it so we have a lot more space for - # Nix operations. - boot.initrd.postMountCommands = - '' - diskNr=0 - diskForUnionfs= - for device in /dev/xvd[abcde]*; do - if [ "$device" = /dev/xvda -o "$device" = /dev/xvda1 ]; then continue; fi - fsType=$(blkid -o value -s TYPE "$device" || true) - if [ "$fsType" = swap ]; then - echo "activating swap device $device..." - swapon "$device" || true - elif [ "$fsType" = ext3 ]; then - mp="/disk$diskNr" - diskNr=$((diskNr + 1)) - echo "mounting $device on $mp..." - if mountFS "$device" "$mp" "" ext3; then - if [ -z "$diskForUnionfs" ]; then diskForUnionfs="$mp"; fi - fi - else - echo "skipping unknown device type $device" - fi - done + boot.initrd.postDeviceCommands = + '' + # Force udev to exit to prevent random "Device or resource busy + # while trying to open /dev/xvda" errors from fsck. + udevadm control --exit || true + kill -9 -1 + ''; - if [ -n "$diskForUnionfs" ]; then - mkdir -m 755 -p $targetRoot/$diskForUnionfs/root + # Mount all formatted ephemeral disks and activate all swap devices. + # We cannot do this with the ‘fileSystems’ and ‘swapDevices’ options + # because the set of devices is dependent on the instance type + # (e.g. "m1.large" has one ephemeral filesystem and one swap device, + # while "m1.large" has two ephemeral filesystems and no swap + # devices). Also, put /tmp and /var on /disk0, since it has a lot + # more space than the root device. Similarly, "move" /nix to /disk0 + # by layering a unionfs-fuse mount on top of it so we have a lot more space for + # Nix operations. + boot.initrd.postMountCommands = + '' + diskNr=0 + diskForUnionfs= + for device in /dev/xvd[abcde]*; do + if [ "$device" = /dev/xvda -o "$device" = /dev/xvda1 ]; then continue; fi + fsType=$(blkid -o value -s TYPE "$device" || true) + if [ "$fsType" = swap ]; then + echo "activating swap device $device..." + swapon "$device" || true + elif [ "$fsType" = ext3 ]; then + mp="/disk$diskNr" + diskNr=$((diskNr + 1)) + echo "mounting $device on $mp..." + if mountFS "$device" "$mp" "" ext3; then + if [ -z "$diskForUnionfs" ]; then diskForUnionfs="$mp"; fi + fi + else + echo "skipping unknown device type $device" + fi + done - mkdir -m 1777 -p $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp - mount --bind $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp + if [ -n "$diskForUnionfs" ]; then + mkdir -m 755 -p $targetRoot/$diskForUnionfs/root - if [ ! -e $targetRoot/.ebs ]; then - mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/var $targetRoot/var - mount --bind $targetRoot/$diskForUnionfs/root/var $targetRoot/var + mkdir -m 1777 -p $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp + mount --bind $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp - mkdir -p /unionfs-chroot/ro-nix - mount --rbind $targetRoot/nix /unionfs-chroot/ro-nix + if [ ! -e $targetRoot/.ebs ]; then + mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/var $targetRoot/var + mount --bind $targetRoot/$diskForUnionfs/root/var $targetRoot/var - mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/nix - mkdir -p /unionfs-chroot/rw-nix - mount --rbind $targetRoot/$diskForUnionfs/root/nix /unionfs-chroot/rw-nix + mkdir -p /unionfs-chroot/ro-nix + mount --rbind $targetRoot/nix /unionfs-chroot/ro-nix - unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot,max_files=32768 /rw-nix=RW:/ro-nix=RO $targetRoot/nix - fi - fi - ''; + mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/nix + mkdir -p /unionfs-chroot/rw-nix + mount --rbind $targetRoot/$diskForUnionfs/root/nix /unionfs-chroot/rw-nix - boot.initrd.extraUtilsCommands = - '' - # We need swapon in the initrd. - cp ${pkgs.utillinux}/sbin/swapon $out/bin - ''; + unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot,max_files=32768 /rw-nix=RW:/ro-nix=RO $targetRoot/nix + fi + fi + ''; - # Don't put old configurations in the GRUB menu. The user has no - # way to select them anyway. - boot.loader.grub.configurationLimit = 0; + boot.initrd.extraUtilsCommands = + '' + # We need swapon in the initrd. + cp ${pkgs.utillinux}/sbin/swapon $out/bin + ''; - # Allow root logins only using the SSH key that the user specified - # at instance creation time. - services.openssh.enable = true; - services.openssh.permitRootLogin = "without-password"; + # Don't put old configurations in the GRUB menu. The user has no + # way to select them anyway. + boot.loader.grub.configurationLimit = 0; - # Force getting the hostname from EC2. - networking.hostName = mkDefault ""; + # Allow root logins only using the SSH key that the user specified + # at instance creation time. + services.openssh.enable = true; + services.openssh.permitRootLogin = "without-password"; - # Always include cryptsetup so that Charon can use it. - environment.systemPackages = [ pkgs.cryptsetup ]; + # Force getting the hostname from EC2. + networking.hostName = mkDefault ""; - boot.initrd.supportedFilesystems = [ "unionfs-fuse" ]; + # Always include cryptsetup so that Charon can use it. + environment.systemPackages = [ pkgs.cryptsetup ]; + + boot.initrd.supportedFilesystems = [ "unionfs-fuse" ]; + + # Prevent logging in as root without a password. This doesn't really matter, + # since the only PAM services that allow logging in with a null + # password are local ones that are inaccessible on EC2 machines. + security.initialRootPassword = mkDefault "!"; + }; }