Skip to content

Commit

Permalink
make-disk-image: allow pre/post format files in vm
Browse files Browse the repository at this point in the history
  • Loading branch information
phaer committed Sep 29, 2024
1 parent b709e1c commit 588d1c7
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 20 deletions.
67 changes: 47 additions & 20 deletions lib/make-disk-image.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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 ''
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
41 changes: 41 additions & 0 deletions module.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down

0 comments on commit 588d1c7

Please sign in to comment.