Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make-disk-image: Support creating EFI images #32618

Merged
merged 1 commit into from
Jan 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 64 additions & 18 deletions nixos/lib/make-disk-image.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@
# grafted in the file system at path `target'.
, contents ? []

, # Whether the disk should be partitioned (with a single partition
# containing the root filesystem) or contain the root filesystem
# directly.
partitioned ? true
, # Type of partition table to use; either "legacy", "efi", or "none".
# For "efi" images, the GPT partition table is used and a mandatory ESP
# partition of reasonable size is created in addition to the root partition.
# If `installBootLoader` is true, GRUB will be installed in EFI mode.
# For "legacy", the msdos partition table is used and a single large root
# partition is created. If `installBootLoader` is true, GRUB will be
# installed in legacy mode.
# For "none", no partition table is created. Enabling `installBootLoader`
# most likely fails as GRUB will probably refuse to install.
partitionTableType ? "legacy"

# Whether to invoke switch-to-configuration boot during image creation
, installBootLoader ? true
Expand All @@ -37,6 +43,10 @@
format ? "raw"
}:

assert partitionTableType == "legacy" || partitionTableType == "efi" || partitionTableType == "none";
# We use -E offset=X below, which is only supported by e2fsprogs
assert partitionTableType != "none" -> fsType == "ext4";

with lib;

let format' = format; in let
Expand All @@ -51,6 +61,27 @@ let format' = format; in let
raw = "img";
}.${format};

rootPartition = { # switch-case
legacy = "1";
efi = "2";
}.${partitionTableType};

partitionDiskScript = { # switch-case
legacy = ''
parted --script $diskImage -- \
mklabel msdos \
mkpart primary ext4 1MiB -1
'';
efi = ''
parted --script $diskImage -- \
mklabel gpt \
mkpart ESP fat32 8MiB 256MiB \
set 1 boot on \
mkpart primary ext4 256MiB -1
'';
none = "";
}.${partitionTableType};

nixpkgs = cleanSource pkgs.path;

channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" {} ''
Expand Down Expand Up @@ -79,21 +110,32 @@ let format' = format; in let
targets = map (x: x.target) contents;

prepareImage = ''
export PATH=${makeSearchPathOutput "bin" "bin" prepareImageInputs}
export PATH=${makeBinPath prepareImageInputs}

# Yes, mkfs.ext4 takes different units in different contexts. Fun.
sectorsToKilobytes() {
echo $(( ( "$1" * 512 ) / 1024 ))
}

sectorsToBytes() {
echo $(( "$1" * 512 ))
}

mkdir $out
diskImage=nixos.raw
truncate -s ${toString diskSize}M $diskImage

${if partitioned then ''
parted --script $diskImage -- mklabel msdos mkpart primary ext4 1M -1s
offset=$((2048*512))
${partitionDiskScript}

${if partitionTableType != "none" then ''
# Get start & length of the root partition in sectors to $START and $SECTORS.
eval $(partx $diskImage -o START,SECTORS --nr ${rootPartition} --pairs)

mkfs.${fsType} -F -L nixos $diskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K
'' else ''
offset=0
mkfs.${fsType} -F -L nixos $diskImage
''}

mkfs.${fsType} -F -L nixos -E offset=$offset $diskImage

root="$PWD/root"
mkdir -p $root

Expand Down Expand Up @@ -133,12 +175,12 @@ let format' = format; in let
find $root/nix/store -mindepth 1 -maxdepth 1 -type f -o -type d | xargs chmod -R a-w

echo "copying staging root to image..."
cptofs ${optionalString partitioned "-P 1"} -t ${fsType} -i $diskImage $root/* /
cptofs -p ${optionalString (partitionTableType != "none") "-P ${rootPartition}"} -t ${fsType} -i $diskImage $root/* /
'';
in pkgs.vmTools.runInLinuxVM (
pkgs.runCommand name
{ preVM = prepareImage;
buildInputs = with pkgs; [ utillinux e2fsprogs ];
buildInputs = with pkgs; [ utillinux e2fsprogs dosfstools ];
exportReferencesGraph = [ "closure" metaClosure ];
postVM = ''
${if format == "raw" then ''
Expand All @@ -152,11 +194,7 @@ in pkgs.vmTools.runInLinuxVM (
memSize = 1024;
}
''
${if partitioned then ''
rootDisk=/dev/vda1
'' else ''
rootDisk=/dev/vda
''}
rootDisk=${if partitionTableType != "none" then "/dev/vda${rootPartition}" else "/dev/vda"}

# Some tools assume these exist
ln -s vda /dev/xvda
Expand All @@ -166,6 +204,14 @@ in pkgs.vmTools.runInLinuxVM (
mkdir $mountPoint
mount $rootDisk $mountPoint

# Create the ESP and mount it. Unlike e2fsprogs, mkfs.vfat doesn't support an
# '-E offset=X' option, so we can't do this outside the VM.
${optionalString (partitionTableType == "efi") ''
mkdir -p /mnt/boot
mkfs.vfat -n ESP /dev/vda1
mount /dev/vda1 /mnt/boot
''}

# Install a configuration.nix
mkdir -p /mnt/etc/nixos
${optionalString (configFile != null) ''
Expand Down
2 changes: 1 addition & 1 deletion nixos/maintainers/scripts/ec2/amazon-image.nix
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ in {
inherit lib config;
inherit (cfg) contents format name;
pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package
partitioned = config.ec2.hvm;
partitionTableType = if config.ec2.hvm then "legacy" else "none";
diskSize = cfg.sizeMB;
configFile = pkgs.writeText "configuration.nix"
''
Expand Down
2 changes: 1 addition & 1 deletion nixos/modules/virtualisation/virtualbox-image.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ in {
name = "nixos-ova-${config.system.nixosLabel}-${pkgs.stdenv.system}";

inherit pkgs lib config;
partitioned = true;
partitionTableType = "legacy";
diskSize = cfg.baseImageSize;

postVM =
Expand Down