]> git.scottworley.com Git - nixos-qemu-vm-isolation/blob - modules/qemu-vm-isolation.nix
5467f29a366de753f2714a6001762d2ae821999b
[nixos-qemu-vm-isolation] / modules / qemu-vm-isolation.nix
1 { config, lib, modulesPath, pkgs, ... }:
2 let
3 inherit (lib)
4 escapeShellArg mkForce mkIf mkMerge mkOption mkVMOverride optional;
5
6 cfg = config.virtualisation.qemu.isolation;
7
8 storeMountPath = if config.virtualisation.writableStore then
9 "/nix/.ro-store"
10 else
11 "/nix/store";
12
13 hostPkgs = config.virtualisation.host.pkgs;
14
15 storeContents =
16 hostPkgs.closureInfo { rootPaths = config.virtualisation.additionalPaths; };
17
18 nixStoreImages = {
19 ext4 = "${
20 import (modulesPath + "/../lib/make-disk-image.nix") {
21 inherit pkgs config lib;
22 additionalPaths = [ storeContents ];
23 onlyNixStore = true;
24 label = "nix-store";
25 partitionTableType = "none";
26 installBootLoader = false;
27 diskSize = "auto";
28 additionalSpace = "0M";
29 copyChannel = false;
30 }
31 }/nixos.img";
32 erofs = "${
33 hostPkgs.runCommand "nix-store-image" { } ''
34 mkdir $out
35 ${hostPkgs.gnutar}/bin/tar --create \
36 --absolute-names \
37 --verbatim-files-from \
38 --transform 'flags=rSh;s|/nix/store/||' \
39 --files-from ${storeContents}/store-paths \
40 | ${hostPkgs.erofs-utils}/bin/mkfs.erofs \
41 --force-uid=0 \
42 --force-gid=0 \
43 -L nix-store \
44 -U eb176051-bd15-49b7-9e6b-462e0b467019 \
45 -T 0 \
46 --tar=f \
47 $out/nix-store.img
48 ''
49 }/nix-store.img";
50 squashfs =
51 "${hostPkgs.callPackage (modulesPath + "/../lib/make-squashfs.nix") {
52 squashfsTools = hostPkgs.squashfsTools.overrideAttrs (old: {
53 # We patch in support for squashfs labels because
54 # https://github.com/NixOS/nixpkgs/pull/236656 requires filesystems to have labels and
55 # https://github.com/plougher/squashfs-tools/issues/59 squashfs doesn't support labels
56 patches = (old.patches or []) ++ [ ./squashfs-tools-label.patch ];
57 buildInputs = (old.buildInputs or []) ++ [ hostPkgs.makeWrapper ];
58 postInstall = (old.postInstall or "") + ''
59 wrapProgram "$out/bin/mksquashfs" \
60 --append-flags "-label nix-store"
61 '';
62 });
63 storeContents = config.virtualisation.additionalPaths;
64 }}";
65 };
66
67 in {
68 options = {
69 virtualisation.qemu.isolation.nixStoreFilesystemType = mkOption {
70 description = ''
71 What filesystem to use for the guest's Nix store.
72
73 erofs is more compact than ext4, but less mature.
74
75 squashfs is best, but requires patches to set the filesystem label.
76 '';
77 type = lib.types.enum [ "ext4" "erofs" "squashfs" ];
78 default = "ext4";
79 };
80 };
81 config = mkMerge [
82 {
83 boot.initrd.kernelModules =
84 optional (cfg.nixStoreFilesystemType == "erofs") "erofs";
85
86 nixpkgs.overlays = optional (cfg.nixStoreFilesystemType == "squashfs")
87 (final: prev: {
88 util-linux = prev.util-linux.overrideAttrs (old: {
89 # We patch in support for squashfs labels because
90 # https://github.com/NixOS/nixpkgs/pull/236656 requires filesystems to have labels and
91 # https://github.com/plougher/squashfs-tools/issues/59 squashfs doesn't support labels
92 patches = (old.patches or [ ]) ++ [ ./util-linux-squashfs-label.patch ];
93 });
94 });
95
96 fileSystems = mkVMOverride {
97 "${storeMountPath}" = {
98 fsType = cfg.nixStoreFilesystemType;
99 options = [ "ro" ];
100 neededForBoot = true;
101 label = "nix-store";
102 };
103 };
104
105 system.build.nixStoreImage =
106 nixStoreImages."${cfg.nixStoreFilesystemType}";
107
108 virtualisation = {
109
110 sharedDirectories = mkForce { };
111
112 qemu.drives = [{
113 file = config.system.build.nixStoreImage;
114 driveExtraOpts = {
115 format = "raw";
116 read-only = "on";
117 werror = "report";
118 };
119 }];
120
121 };
122 }
123 (mkIf (cfg.nixStoreFilesystemType == "ext4") {
124 # We use this to disable fsck runs on the ext4 nix store image because stage-1
125 # fsck crashes (maybe because the device is read-only?), halting boot.
126 boot.initrd.checkJournalingFS = false;
127 })
128 ];
129 }