From 588d1c7196433d3d95a6df47ac343038099042c1 Mon Sep 17 00:00:00 2001 From: phaer Date: Wed, 18 Sep 2024 01:23:07 +0200 Subject: [PATCH] make-disk-image: allow pre/post format files in vm --- lib/make-disk-image.nix | 67 +++++++++++++++++++++++++++++------------ module.nix | 41 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/lib/make-disk-image.nix b/lib/make-disk-image.nix index f81a473c..04754dc2 100644 --- a/lib/make-disk-image.nix +++ b/lib/make-disk-image.nix @@ -42,6 +42,26 @@ let util-linux findutils ] ++ cfg.extraDependencies; + + prepareFile = name: content: '' + out="$(echo "${name}" | base64)" + ${if lib.isStorePath content + then ''cp --reflink=auto -r "${content}" "$out"'' + else content + } + ''; + + prepareFiles = '' + ( + cd $TMPDIR/xchg + mkdir -p pre_format_files post_format_files + cd pre_format_files + ${lib.concatStringsSep "\n" (lib.attrValues (lib.mapAttrs prepareFile cfg.preFormatFiles))} + cd ../post_format_files + ${lib.concatStringsSep "\n" (lib.attrValues (lib.mapAttrs prepareFile cfg.postFormatFiles))} + ) + ''; + preVM = '' ${lib.concatMapStringsSep "\n" (disk: "${pkgs.qemu}/bin/qemu-img create -f ${imageFormat} ${disk.name}.${imageFormat} ${disk.imageSize}") (lib.attrValues diskoCfg.devices.disk)} # This makes disko work, when canTouchEfiVariables is set to true. @@ -59,8 +79,19 @@ let closureInfo = pkgs.closureInfo { rootPaths = [ systemToInstall.config.system.build.toplevel ]; }; + partitioner = '' - set -efux + set -eux + + set +f + for src in /tmp/xchg/pre_format_files/*; do + [ -e "$src" ] || continue + dst=$(basename "$src" | base64 -d) + mkdir -p "$(dirname "$dst")" + cp -r "$src" "$dst" + done + set -f + # running udev, stolen from stage-1.sh echo "running udev..." ln -sfn /proc/self/fd /dev/fd @@ -80,6 +111,15 @@ let export IN_DISKO_TEST=1 ''} ${systemToInstall.config.system.build.diskoScript} + + set +f + for src in /tmp/xchg/post_format_files/*; do + [ -e "$src" ] || continue + dst=/mnt/$(basename "$src" | base64 -d) + mkdir -p "$(dirname "$dst")" + cp -r "$src" "$dst" + done + set -f ''; installer = lib.optionalString cfg.copyNixStore '' @@ -108,8 +148,9 @@ in system.build.diskoImages = vmTools.runInLinuxVM (pkgs.runCommand cfg.name { buildInputs = dependencies; - inherit preVM postVM QEMU_OPTS; + inherit postVM QEMU_OPTS; inherit (diskoCfg) memSize; + preVM = preVM + prepareFiles; } (partitioner + installer)); @@ -140,20 +181,20 @@ in trap 'rm -rf "$TMPDIR"' EXIT cd "$TMPDIR" - mkdir copy_before_disko copy_after_disko + mkdir pre_format_files post_format_files while [[ $# -gt 0 ]]; do case "$1" in --pre-format-files) src=$2 dst=$3 - cp --reflink=auto -r "$src" copy_before_disko/"$(echo "$dst" | base64)" + cp --reflink=auto -r "$src" pre_format_files/"$(echo "$dst" | base64)" shift 2 ;; --post-format-files) src=$2 dst=$3 - cp --reflink=auto -r "$src" copy_after_disko/"$(echo "$dst" | base64)" + cp --reflink=auto -r "$src" post_format_files/"$(echo "$dst" | base64)" shift 2 ;; --build-memory) @@ -175,25 +216,11 @@ in export preVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "preVM.sh" '' set -efu - mv copy_before_disko copy_after_disko xchg/ + mv pre_format_files post_format_files xchg/ origBuilder=${pkgs.writeScript "disko-builder" '' set -eu export PATH=${lib.makeBinPath dependencies} - for src in /tmp/xchg/copy_before_disko/*; do - [ -e "$src" ] || continue - dst=$(basename "$src" | base64 -d) - mkdir -p "$(dirname "$dst")" - cp -r "$src" "$dst" - done - set -f ${partitioner} - set +f - for src in /tmp/xchg/copy_after_disko/*; do - [ -e "$src" ] || continue - dst=/mnt/$(basename "$src" | base64 -d) - mkdir -p "$(dirname "$dst")" - cp -r "$src" "$dst" - done ${installer} ''} echo "export origBuilder=$origBuilder" > xchg/saved-env diff --git a/module.nix b/module.nix index 91e59ac6..ec704dbd 100644 --- a/module.nix +++ b/module.nix @@ -97,6 +97,47 @@ in default = { }; }; + preFormatFiles = lib.mkOption { + type = lib.types.attrsOf (lib.types.either lib.types.str lib.types.path); + description = '' + Files to copy into the image builder VM before disko is run. + This is useful to provide secrets like LUKS keys, or other files you need for formatting. + + Names are interpreted as destination paths. If the value is a store path, + that path will be copied as-is. If it's not a store path, the value will be interpreted + as shell code is expected to write files into $out. + ''; + default = {}; + example = lib.literalExpression '' + { + "/tmp/pre/file" = pkgs.writeText "foo" "bar"; + "/tmp/pre/script" = "mkdir -p $out/foo; echo bar > $out/foo"; + } + ''; + }; + + postFormatFiles = lib.mkOption { + type = lib.types.attrsOf (lib.types.either lib.types.str lib.types.path); + description = '' + Files to copy into the final image, after disko has run. + These end up in the images later and is useful if you want to add some extra stateful files + They will have the same permissions but will be owned by root:root. + + Names are interpreted as destination paths. If the value is a store path, + that path will be copied as-is. If it's not a store path, the value will be interpreted + as shell code is expected to write files into $out. + ''; + default = {}; + example = lib.literalExpression '' + { + "/tmp/pre/file" = pkgs.writeText "foo" "bar"; + "/tmp/pre/script" = "mkdir -p $out/foo; echo bar > $out/foo"; + } + ''; + }; + + + imageFormat = lib.mkOption { type = lib.types.enum [ "raw" "qcow2" ]; description = "QEMU image format to use for the disk images";