diff --git a/checks/default.nix b/checks/default.nix index 9a81c910..4113c534 100644 --- a/checks/default.nix +++ b/checks/default.nix @@ -62,6 +62,7 @@ let microvm.writableStoreOverlay = "/nix/.rw-store"; microvm.volumes = [ { image = "nix-store-overlay.img"; + label = "nix-store"; mountPoint = config.microvm.writableStoreOverlay; size = 128; } ]; diff --git a/checks/startup-shutdown.nix b/checks/startup-shutdown.nix index 4cd42ce3..774f9b83 100644 --- a/checks/startup-shutdown.nix +++ b/checks/startup-shutdown.nix @@ -15,6 +15,7 @@ let }; microvm = { volumes = [ { + label = "var"; mountPoint = "/var"; image = "var.img"; size = 32; diff --git a/lib/default.nix b/lib/default.nix index ed6ecd8e..0e299cfc 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -30,21 +30,35 @@ rec { createVolumesScript = pkgs: pkgs.lib.concatMapStringsSep "\n" ( { image + , label , size ? throw "Specify a size for volume ${image} or use autoCreate = false" , fsType ? defaultFsType , autoCreate ? true , ... - }: nixpkgs-lib.optionalString autoCreate '' - PATH=$PATH:${with pkgs; lib.makeBinPath [ coreutils util-linux e2fsprogs ]} + }: pkgs.lib.warnIf + (label != null && !autoCreate) "Volume is not automatically labeled unless autoCreate is true. Volume has to be labeled manually, otherwise it will not be identified" + (let labelOption = + if autoCreate then + (if builtins.elem fsType ["ext2" "ext3" "ext4" "xfs"] then "-L" + else if fsType == "vfat" then "-n" + else (pkgs.lib.warnIf (label != null) + "Will not label volume ${label} with filesystem type ${fsType}. Open an issue on the microvm.nix project to request a fix." + null)) + else null; + labelArgument = + if (labelOption != null && label != null) then "${labelOption} '${label}'" + else ""; + in (nixpkgs-lib.optionalString autoCreate '' + PATH=$PATH:${with pkgs.buildPackages; lib.makeBinPath [ coreutils util-linux e2fsprogs ]} if [ ! -e '${image}' ]; then touch '${image}' # Mark NOCOW chattr +C '${image}' || true fallocate -l${toString size}MiB '${image}' - mkfs.${fsType} '${image}' + mkfs.${fsType} ${pkgs.lib.optionalString (label != null) "-L '${label}'"} '${image}' fi - ''); + '')); buildRunner = import ./runner.nix; diff --git a/nixos-modules/microvm/mounts.nix b/nixos-modules/microvm/mounts.nix index 68f3d813..cfae876b 100644 --- a/nixos-modules/microvm/mounts.nix +++ b/nixos-modules/microvm/mounts.nix @@ -94,11 +94,16 @@ lib.mkIf config.microvm.guest.enable { }; } ( # Volumes - builtins.foldl' (result: { mountPoint, letter, fsType ? defaultFsType, ... }: + builtins.foldl' (result: { label, mountPoint, letter, fsType ? defaultFsType, ... }: result // lib.optionalAttrs (mountPoint != null) { "${mountPoint}" = { inherit fsType; - device = "/dev/vd${letter}"; + # Prioritize identifying a device by label if provided. This + # minimizes the risk of misidentifying a device. + device = if label != null then + "/dev/disk/by-label/${label}" + else + "/dev/vd${letter}"; } // lib.optionalAttrs (mountPoint == config.microvm.writableStoreOverlay) { neededForBoot = true; }; diff --git a/nixos-modules/microvm/options.nix b/nixos-modules/microvm/options.nix index c4e477fe..a458f7dc 100644 --- a/nixos-modules/microvm/options.nix +++ b/nixos-modules/microvm/options.nix @@ -180,6 +180,11 @@ in type = str; description = "Path to disk image on the host"; }; + label = mkOption { + type = nullOr str; + default = null; + description = "Label of the volume, if any. Only applicable if autoCreate is true; otherwise labeling of the volume must be done manually"; + }; mountPoint = mkOption { type = nullOr path; description = "If and where to mount the volume inside the container";