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

Add support for incremental changes #568

Merged
merged 1 commit into from
Mar 13, 2024
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
2 changes: 1 addition & 1 deletion disk-deactivate/disk-deactivate
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -efux -o pipefail
# dependencies: bash jq util-linux lvm2 mdadm zfs
# dependencies: bash jq util-linux lvm2 mdadm zfs gnugrep
disk=$(realpath "$1")

lsblk -a -f >&2
Expand Down
2 changes: 1 addition & 1 deletion example/zfs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"com.sun:auto-snapshot" = "false";
};
mountpoint = "/";
postCreateHook = "zfs snapshot zroot@blank";
postCreateHook = "zfs list -t snapshot -H -o name | grep -E '^zroot@blank$' || zfs snapshot zroot@blank";

datasets = {
zfs_fs = {
Expand Down
12 changes: 10 additions & 2 deletions lib/tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,23 @@ let
# running direct mode
machine.succeed("${tsp-format}")
machine.succeed("${tsp-mount}")
machine.succeed("${tsp-mount}") # verify that the command is idempotent
machine.succeed("${tsp-mount}") # verify that mount is idempotent
machine.succeed("${tsp-disko}") # verify that we can destroy and recreate
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${tsp-format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}
${lib.optionalString (testMode == "module") ''
# running module mode
machine.succeed("${nodes.machine.system.build.formatScript}")
machine.succeed("${nodes.machine.system.build.mountScript}")
machine.succeed("${nodes.machine.system.build.mountScript}") # verify that the command is idempotent
machine.succeed("${nodes.machine.system.build.mountScript}") # verify that mount is idempotent
machine.succeed("${nodes.machine.system.build.diskoScript}") # verify that we can destroy and recreate again
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${nodes.machine.system.build.formatScript}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}

${postDisko}
Expand Down
55 changes: 33 additions & 22 deletions lib/types/btrfs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ let
swapCreate = mountpoint: swap:
lib.concatMapStringsSep
"\n"
(file: ''btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}"'')
(file: ''
if ! test -e "${mountpoint}/${file.path}"; then
btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}"
fi
'')
(lib.attrValues swap);

in
Expand Down Expand Up @@ -112,26 +116,33 @@ in
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
mkfs.btrfs ${config.device} ${toString config.extraArgs}
${lib.optionalString (config.swap != {}) ''
(
MNTPOINT=$(mktemp -d)
mount ${device} "$MNTPOINT" -o subvol=/
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
${swapCreate "$MNTPOINT" config.swap}
)
''}
${lib.concatMapStrings (subvol: ''
(
MNTPOINT=$(mktemp -d)
mount ${config.device} "$MNTPOINT" -o subvol=/
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
SUBVOL_ABS_PATH="$MNTPOINT/${subvol.name}"
mkdir -p "$(dirname "$SUBVOL_ABS_PATH")"
btrfs subvolume create "$SUBVOL_ABS_PATH" ${toString subvol.extraArgs}
${swapCreate "$SUBVOL_ABS_PATH" subvol.swap}
)
'') (lib.attrValues config.subvolumes)}
# create the filesystem only if the device seems empty
if ! (blkid '${config.device}' -o export | grep -q '^TYPE='); then
mkfs.btrfs "${config.device}" ${toString config.extraArgs}
fi
if (blkid "${config.device}" -o export | grep -q '^TYPE=btrfs$'); then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that this is causing syntax error near unexpected token `fi' when formatting a btrfs filesystem without any swap or subvolume configuration.

I guess this all should be gaurded by config.swap & config.subvolumes being set? It's a bit annoying bash doesn't support empty if statements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplest fix would be echo -n "" in the first line.

${lib.optionalString (config.swap != {}) ''
(
MNTPOINT=$(mktemp -d)
mount ${device} "$MNTPOINT" -o subvol=/
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
${swapCreate "$MNTPOINT" config.swap}
)
''}
${lib.concatMapStrings (subvol: ''
(
MNTPOINT=$(mktemp -d)
mount ${config.device} "$MNTPOINT" -o subvol=/
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
SUBVOL_ABS_PATH="$MNTPOINT/${subvol.name}"
mkdir -p "$(dirname "$SUBVOL_ABS_PATH")"
if ! btrfs subvolume show "$SUBVOL_ABS_PATH" > /dev/null 2>&1; then
btrfs subvolume create "$SUBVOL_ABS_PATH" ${toString subvol.extraArgs}
fi
${swapCreate "$SUBVOL_ABS_PATH" subvol.swap}
)
'') (lib.attrValues config.subvolumes)}
fi
'';
};
_mount = diskoLib.mkMountOption {
Expand Down Expand Up @@ -206,7 +217,7 @@ in
readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs:
[ pkgs.btrfs-progs pkgs.coreutils ];
[ pkgs.btrfs-progs pkgs.coreutils pkgs.gnugrep ];
description = "Packages";
};
};
Expand Down
10 changes: 6 additions & 4 deletions lib/types/filesystem.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
mkfs.${config.format} \
${toString config.extraArgs} \
${config.device}
if ! (blkid '${config.device}' | grep -q 'TYPE='); then
mkfs.${config.format} \
${toString config.extraArgs} \
${config.device}
fi
'';
};
_mount = diskoLib.mkMountOption {
Expand Down Expand Up @@ -79,7 +81,7 @@
readOnly = true;
# type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs:
[ pkgs.util-linux ] ++ (
[ pkgs.util-linux pkgs.gnugrep ] ++ (
# TODO add many more
if (config.format == "xfs") then [ pkgs.xfsprogs ]
else if (config.format == "btrfs") then [ pkgs.btrfs-progs ]
Expand Down
60 changes: 35 additions & 25 deletions lib/types/gpt.nix
Original file line number Diff line number Diff line change
Expand Up @@ -153,34 +153,44 @@ in
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
${lib.concatStrings (map (partition: ''
sgdisk \
--align-end \
--new=${toString partition._index}:${partition.start}:${partition.end} \
--change-name=${toString partition._index}:${partition.label} \
--typecode=${toString partition._index}:${partition.type} \
${config.device}
# ensure /dev/disk/by-path/..-partN exists before continuing
partprobe ${config.device}
udevadm trigger --subsystem-match=block
udevadm settle
${lib.optionalString (partition.content != null) partition.content._create}
'') sortedPartitions)}
if ! blkid "${config.device}" >/dev/null; then
${lib.concatStrings (map (partition: ''
if sgdisk \
--info=${toString partition._index} \
${config.device} > /dev/null 2>&1
then
sgdisk \
--align-end \
--new=${toString partition._index}:${partition.start}:${partition.end} \
--change-name=${toString partition._index}:${partition.label} \
--typecode=${toString partition._index}:${partition.type} \
${config.device}
# ensure /dev/disk/by-path/..-partN exists before continuing
partprobe ${config.device}
udevadm trigger --subsystem-match=block
udevadm settle
fi
'') sortedPartitions)}

${
lib.optionalString (sortedHybridPartitions != [])
("sgdisk -h "
+ (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions))
+ (
lib.optionalString (!config.efiGptPartitionFirst) ":EE "
${
lib.optionalString (sortedHybridPartitions != [])
("sgdisk -h "
+ (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions))
+ (
lib.optionalString (!config.efiGptPartitionFirst) ":EE "
)
+ parent.device)
}
${lib.concatMapStrings (p:
p.hybrid._create
)
+ parent.device)
}
${lib.concatMapStrings (p:
p.hybrid._create
)
sortedHybridPartitions}
sortedHybridPartitions
}
fi

${lib.concatStrings (map (partition: ''
${lib.optionalString (partition.content != null) partition.content._create}
'') sortedPartitions)}
'';
};
_mount = diskoLib.mkMountOption {
Expand Down
44 changes: 23 additions & 21 deletions lib/types/luks.nix
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,28 @@ in
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
${lib.optionalString config.askPassword ''
set +x
askPassword() {
echo "Enter password for ${config.device}: "
IFS= read -r -s password
echo "Enter password for ${config.device} again to be safe: "
IFS= read -r -s password_check
export password
[ "$password" = "$password_check" ]
}
until askPassword; do
echo "Passwords did not match, please try again."
done
set -x
''}
cryptsetup -q luksFormat ${config.device} ${toString config.extraFormatArgs} ${keyFileArgs}
${cryptsetupOpen} --persistent
${toString (lib.forEach config.additionalKeyFiles (keyFile: ''
cryptsetup luksAddKey ${config.device} ${keyFile} ${keyFileArgs}
''))}
if ! blkid "${config.device}" >/dev/null || ! (blkid "${config.device}" -o export | grep -q '^TYPE='); then
${lib.optionalString config.askPassword ''
set +x
askPassword() {
echo "Enter password for ${config.device}: "
IFS= read -r -s password
echo "Enter password for ${config.device} again to be safe: "
IFS= read -r -s password_check
export password
[ "$password" = "$password_check" ]
}
until askPassword; do
echo "Passwords did not match, please try again."
done
set -x
''}
cryptsetup -q luksFormat ${config.device} ${toString config.extraFormatArgs} ${keyFileArgs}
${cryptsetupOpen} --persistent
${toString (lib.forEach config.additionalKeyFiles (keyFile: ''
cryptsetup luksAddKey ${config.device} ${keyFile} ${keyFileArgs}
''))}
fi
${lib.optionalString (config.content != null) config.content._create}
'';
};
Expand Down Expand Up @@ -176,7 +178,7 @@ in
internal = true;
readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: [ pkgs.cryptsetup ] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs));
default = pkgs: [ pkgs.gnugrep pkgs.cryptsetup ] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs));
description = "Packages";
};
};
Expand Down
6 changes: 4 additions & 2 deletions lib/types/lvm_pv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
pvcreate ${config.device}
if ! (blkid '${config.device}' | grep -q 'TYPE='); then
pvcreate ${config.device}
fi
echo "${config.device}" >>"$disko_devices_dir"/lvm_${config.vg}
'';
};
Expand All @@ -49,7 +51,7 @@
internal = true;
readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: [ pkgs.lvm2 ];
default = pkgs: [ pkgs.gnugrep pkgs.lvm2 ];
description = "Packages";
};
};
Expand Down
25 changes: 16 additions & 9 deletions lib/types/lvm_vg.nix
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,23 @@
in
''
readarray -t lvm_devices < <(cat "$disko_devices_dir"/lvm_${config.name})
vgcreate ${config.name} \
"''${lvm_devices[@]}"
if ! vgdisplay "${config.name}" >/dev/null; then
vgcreate ${config.name} \
"''${lvm_devices[@]}"
fi
${lib.concatMapStrings (lv: ''
if ! lvdisplay '${config.name}/${lv.name}'; then
lvcreate \
--yes \
${if lib.hasInfix "%" lv.size then "-l" else "-L"} ${lv.size} \
-n ${lv.name} \
${lib.optionalString (lv.lvm_type != null) "--type=${lv.lvm_type}"} \
${toString lv.extraArgs} \
${config.name}
fi
'') sortedLvs}

${lib.concatMapStrings (lv: ''
lvcreate \
--yes \
${if lib.hasInfix "%" lv.size then "-l" else "-L"} ${lv.size} \
-n ${lv.name} \
${lib.optionalString (lv.lvm_type != null) "--type=${lv.lvm_type}"} \
${toString lv.extraArgs} \
${config.name}
${lib.optionalString (lv.content != null) lv.content._create}
'') sortedLvs}
'';
Expand Down
28 changes: 15 additions & 13 deletions lib/types/mdadm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,21 @@
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
readarray -t disk_devices < <(cat "$disko_devices_dir"/raid_${config.name})
echo 'y' | mdadm --create /dev/md/${config.name} \
--level=${toString config.level} \
--raid-devices="$(wc -l "$disko_devices_dir"/raid_${config.name} | cut -f 1 -d " ")" \
--metadata=${config.metadata} \
--force \
--homehost=any \
"''${disk_devices[@]}"
partprobe /dev/md/${config.name}
udevadm trigger --subsystem-match=block
udevadm settle
# for some reason mdadm devices spawn with an existing partition table, so we need to wipe it
sgdisk --zap-all /dev/md/${config.name}
if ! test -e /dev/md/${config.name}; then
readarray -t disk_devices < <(cat "$disko_devices_dir"/raid_${config.name})
echo 'y' | mdadm --create /dev/md/${config.name} \
--level=${toString config.level} \
--raid-devices="$(wc -l "$disko_devices_dir"/raid_${config.name} | cut -f 1 -d " ")" \
--metadata=${config.metadata} \
--force \
--homehost=any \
"''${disk_devices[@]}"
partprobe /dev/md/${config.name}
udevadm trigger --subsystem-match=block
udevadm settle
# for some reason mdadm devices spawn with an existing partition table, so we need to wipe it
sgdisk --zap-all /dev/md/${config.name}
fi
${lib.optionalString (config.content != null) config.content._create}
'';
};
Expand Down
8 changes: 5 additions & 3 deletions lib/types/swap.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
mkswap \
${toString config.extraArgs} \
${config.device}
if ! blkid "${config.device}" -o export | grep -q '^TYPE='; then
mkswap \
${toString config.extraArgs} \
${config.device}
fi
'';
};
_mount = diskoLib.mkMountOption {
Expand Down
Loading