Merge pull request #290730 from nikstur/qemu-vm-refactoring
qemu-vm.nix refactoring
This commit is contained in:
commit
a62c421981
nixos
@ -393,7 +393,7 @@ in
|
|||||||
The path (inside the VM) to the device containing the EFI System Partition (ESP).
|
The path (inside the VM) to the device containing the EFI System Partition (ESP).
|
||||||
|
|
||||||
If you are *not* booting from a UEFI firmware, this value is, by
|
If you are *not* booting from a UEFI firmware, this value is, by
|
||||||
default, `null`. The ESP is mounted under `/boot`.
|
default, `null`. The ESP is mounted to `boot.loader.efi.efiSysMountpoint`.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1054,38 +1054,6 @@ in
|
|||||||
|
|
||||||
boot.loader.supportsInitrdSecrets = mkIf (!cfg.useBootLoader) (mkVMOverride false);
|
boot.loader.supportsInitrdSecrets = mkIf (!cfg.useBootLoader) (mkVMOverride false);
|
||||||
|
|
||||||
boot.initrd.postMountCommands = lib.mkIf (!config.boot.initrd.systemd.enable)
|
|
||||||
''
|
|
||||||
# Mark this as a NixOS machine.
|
|
||||||
mkdir -p $targetRoot/etc
|
|
||||||
echo -n > $targetRoot/etc/NIXOS
|
|
||||||
|
|
||||||
# Fix the permissions on /tmp.
|
|
||||||
chmod 1777 $targetRoot/tmp
|
|
||||||
|
|
||||||
mkdir -p $targetRoot/boot
|
|
||||||
|
|
||||||
${optionalString cfg.writableStore ''
|
|
||||||
echo "mounting overlay filesystem on /nix/store..."
|
|
||||||
mkdir -p -m 0755 $targetRoot/nix/.rw-store/store $targetRoot/nix/.rw-store/work $targetRoot/nix/store
|
|
||||||
mount -t overlay overlay $targetRoot/nix/store \
|
|
||||||
-o lowerdir=$targetRoot/nix/.ro-store,upperdir=$targetRoot/nix/.rw-store/store,workdir=$targetRoot/nix/.rw-store/work || fail
|
|
||||||
''}
|
|
||||||
'';
|
|
||||||
|
|
||||||
systemd.tmpfiles.settings."10-qemu-vm" = lib.mkIf config.boot.initrd.systemd.enable {
|
|
||||||
"/etc/NIXOS".f = {
|
|
||||||
mode = "0644";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
};
|
|
||||||
"${config.boot.loader.efi.efiSysMountPoint}".d = {
|
|
||||||
mode = "0644";
|
|
||||||
user = "root";
|
|
||||||
group = "root";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# After booting, register the closure of the paths in
|
# After booting, register the closure of the paths in
|
||||||
# `virtualisation.additionalPaths' in the Nix database in the VM. This
|
# `virtualisation.additionalPaths' in the Nix database in the VM. This
|
||||||
# allows Nix operations to work in the VM. The path to the
|
# allows Nix operations to work in the VM. The path to the
|
||||||
@ -1101,8 +1069,7 @@ in
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
boot.initrd.availableKernelModules =
|
boot.initrd.availableKernelModules =
|
||||||
optional cfg.writableStore "overlay"
|
optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
|
||||||
++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
|
|
||||||
++ optional (cfg.tpm.enable) "tpm_tis";
|
++ optional (cfg.tpm.enable) "tpm_tis";
|
||||||
|
|
||||||
virtualisation.additionalPaths = [ config.system.build.toplevel ];
|
virtualisation.additionalPaths = [ config.system.build.toplevel ];
|
||||||
@ -1110,7 +1077,9 @@ in
|
|||||||
virtualisation.sharedDirectories = {
|
virtualisation.sharedDirectories = {
|
||||||
nix-store = mkIf cfg.mountHostNixStore {
|
nix-store = mkIf cfg.mountHostNixStore {
|
||||||
source = builtins.storeDir;
|
source = builtins.storeDir;
|
||||||
target = "/nix/store";
|
# Always mount this to /nix/.ro-store because we never want to actually
|
||||||
|
# write to the host Nix Store.
|
||||||
|
target = "/nix/.ro-store";
|
||||||
securityModel = "none";
|
securityModel = "none";
|
||||||
};
|
};
|
||||||
xchg = {
|
xchg = {
|
||||||
@ -1220,10 +1189,7 @@ in
|
|||||||
virtualisation.fileSystems = let
|
virtualisation.fileSystems = let
|
||||||
mkSharedDir = tag: share:
|
mkSharedDir = tag: share:
|
||||||
{
|
{
|
||||||
name =
|
name = share.target;
|
||||||
if tag == "nix-store" && cfg.writableStore
|
|
||||||
then "/nix/.ro-store"
|
|
||||||
else share.target;
|
|
||||||
value.device = tag;
|
value.device = tag;
|
||||||
value.fsType = "9p";
|
value.fsType = "9p";
|
||||||
value.neededForBoot = true;
|
value.neededForBoot = true;
|
||||||
@ -1248,7 +1214,17 @@ in
|
|||||||
# Sync with systemd's tmp.mount;
|
# Sync with systemd's tmp.mount;
|
||||||
options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmp.tmpfsSize}" ];
|
options = [ "mode=1777" "strictatime" "nosuid" "nodev" "size=${toString config.boot.tmp.tmpfsSize}" ];
|
||||||
};
|
};
|
||||||
"/nix/${if cfg.writableStore then ".ro-store" else "store"}" = lib.mkIf cfg.useNixStoreImage {
|
"/nix/store" = lib.mkIf (cfg.useNixStoreImage || cfg.mountHostNixStore) (if cfg.writableStore then {
|
||||||
|
overlay = {
|
||||||
|
lowerdir = [ "/nix/.ro-store" ];
|
||||||
|
upperdir = "/nix/.rw-store/upper";
|
||||||
|
workdir = "/nix/.rw-store/work";
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
device = "/nix/.ro-store";
|
||||||
|
options = [ "bind" ];
|
||||||
|
});
|
||||||
|
"/nix/.ro-store" = lib.mkIf cfg.useNixStoreImage {
|
||||||
device = "/dev/disk/by-label/${nixStoreFilesystemLabel}";
|
device = "/dev/disk/by-label/${nixStoreFilesystemLabel}";
|
||||||
neededForBoot = true;
|
neededForBoot = true;
|
||||||
options = [ "ro" ];
|
options = [ "ro" ];
|
||||||
@ -1258,40 +1234,13 @@ in
|
|||||||
options = [ "mode=0755" ];
|
options = [ "mode=0755" ];
|
||||||
neededForBoot = true;
|
neededForBoot = true;
|
||||||
};
|
};
|
||||||
"/boot" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) {
|
"${config.boot.loader.efi.efiSysMountPoint}" = lib.mkIf (cfg.useBootLoader && cfg.bootPartition != null) {
|
||||||
device = cfg.bootPartition;
|
device = cfg.bootPartition;
|
||||||
fsType = "vfat";
|
fsType = "vfat";
|
||||||
noCheck = true; # fsck fails on a r/o filesystem
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.initrd.systemd = lib.mkIf (config.boot.initrd.systemd.enable && cfg.writableStore) {
|
|
||||||
mounts = [{
|
|
||||||
where = "/sysroot/nix/store";
|
|
||||||
what = "overlay";
|
|
||||||
type = "overlay";
|
|
||||||
options = "lowerdir=/sysroot/nix/.ro-store,upperdir=/sysroot/nix/.rw-store/store,workdir=/sysroot/nix/.rw-store/work";
|
|
||||||
wantedBy = ["initrd-fs.target"];
|
|
||||||
before = ["initrd-fs.target"];
|
|
||||||
requires = ["rw-store.service"];
|
|
||||||
after = ["rw-store.service"];
|
|
||||||
unitConfig.RequiresMountsFor = "/sysroot/nix/.ro-store";
|
|
||||||
}];
|
|
||||||
services.rw-store = {
|
|
||||||
before = [ "shutdown.target" ];
|
|
||||||
conflicts = [ "shutdown.target" ];
|
|
||||||
unitConfig = {
|
|
||||||
DefaultDependencies = false;
|
|
||||||
RequiresMountsFor = "/sysroot/nix/.rw-store";
|
|
||||||
};
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
ExecStart = "/bin/mkdir -p -m 0755 /sysroot/nix/.rw-store/store /sysroot/nix/.rw-store/work /sysroot/nix/store";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
swapDevices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) [ ];
|
swapDevices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) [ ];
|
||||||
boot.initrd.luks.devices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) {};
|
boot.initrd.luks.devices = (if cfg.useDefaultFilesystems then mkVMOverride else mkDefault) {};
|
||||||
|
|
||||||
|
@ -804,6 +804,7 @@ in {
|
|||||||
qemu-vm-restrictnetwork = handleTest ./qemu-vm-restrictnetwork.nix {};
|
qemu-vm-restrictnetwork = handleTest ./qemu-vm-restrictnetwork.nix {};
|
||||||
qemu-vm-volatile-root = runTest ./qemu-vm-volatile-root.nix;
|
qemu-vm-volatile-root = runTest ./qemu-vm-volatile-root.nix;
|
||||||
qemu-vm-external-disk-image = runTest ./qemu-vm-external-disk-image.nix;
|
qemu-vm-external-disk-image = runTest ./qemu-vm-external-disk-image.nix;
|
||||||
|
qemu-vm-store = runTest ./qemu-vm-store.nix;
|
||||||
qgis = handleTest ./qgis.nix { qgisPackage = pkgs.qgis; };
|
qgis = handleTest ./qgis.nix { qgisPackage = pkgs.qgis; };
|
||||||
qgis-ltr = handleTest ./qgis.nix { qgisPackage = pkgs.qgis-ltr; };
|
qgis-ltr = handleTest ./qgis.nix { qgisPackage = pkgs.qgis-ltr; };
|
||||||
qownnotes = handleTest ./qownnotes.nix {};
|
qownnotes = handleTest ./qownnotes.nix {};
|
||||||
|
71
nixos/tests/qemu-vm-store.nix
Normal file
71
nixos/tests/qemu-vm-store.nix
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
{ lib, ... }: {
|
||||||
|
|
||||||
|
name = "qemu-vm-store";
|
||||||
|
|
||||||
|
meta.maintainers = with lib.maintainers; [ nikstur ];
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
sharedWritable = {
|
||||||
|
virtualisation.writableStore = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
sharedReadOnly = {
|
||||||
|
virtualisation.writableStore = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
imageWritable = {
|
||||||
|
virtualisation.useNixStoreImage = true;
|
||||||
|
virtualisation.writableStore = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
imageReadOnly = {
|
||||||
|
virtualisation.useNixStoreImage = true;
|
||||||
|
virtualisation.writableStore = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
fullDisk = {
|
||||||
|
virtualisation.useBootLoader = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
build_derivation = """
|
||||||
|
nix-build --option substitute false -E 'derivation {
|
||||||
|
name = "t";
|
||||||
|
builder = "/bin/sh";
|
||||||
|
args = ["-c" "echo something > $out"];
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
preferLocalBuild = true;
|
||||||
|
}'
|
||||||
|
"""
|
||||||
|
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
with subtest("Nix Store is writable"):
|
||||||
|
sharedWritable.succeed(build_derivation)
|
||||||
|
imageWritable.succeed(build_derivation)
|
||||||
|
fullDisk.succeed(build_derivation)
|
||||||
|
|
||||||
|
with subtest("Nix Store is read only"):
|
||||||
|
sharedReadOnly.fail(build_derivation)
|
||||||
|
imageReadOnly.fail(build_derivation)
|
||||||
|
|
||||||
|
# Checking whether the fs type is 9P is just a proxy to test whether the
|
||||||
|
# Nix Store is shared. If we switch to a different technology (e.g.
|
||||||
|
# virtiofs) for sharing, we need to adjust these tests.
|
||||||
|
|
||||||
|
with subtest("Nix store is shared from the host via 9P"):
|
||||||
|
sharedWritable.succeed("findmnt --kernel --type 9P /nix/.ro-store")
|
||||||
|
sharedReadOnly.succeed("findmnt --kernel --type 9P /nix/.ro-store")
|
||||||
|
|
||||||
|
with subtest("Nix store is not shared via 9P"):
|
||||||
|
imageWritable.fail("findmnt --kernel --type 9P /nix/.ro-store")
|
||||||
|
imageReadOnly.fail("findmnt --kernel --type 9P /nix/.ro-store")
|
||||||
|
|
||||||
|
with subtest("Nix store is not mounted separately"):
|
||||||
|
rootDevice = fullDisk.succeed("stat -c %d /")
|
||||||
|
nixStoreDevice = fullDisk.succeed("stat -c %d /nix/store")
|
||||||
|
assert rootDevice == nixStoreDevice, "Nix store is mounted separately from the root fs"
|
||||||
|
'';
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user