modules/tmproot: Make persistence optional

This commit is contained in:
Jack O'Sullivan 2022-02-13 18:36:57 +00:00
parent 7dec8bb56b
commit e306da7ce6
3 changed files with 108 additions and 85 deletions

View File

@ -1,7 +1,7 @@
{ lib, extendModules, modulesPath, baseModules, options, config, ... }:
let
inherit (lib) recursiveUpdate mkOption;
inherit (lib.my) mkBoolOpt';
inherit (lib) recursiveUpdate mkOption mkDefault;
inherit (lib.my) mkBoolOpt' dummyOption;
cfg = config.my.build;
@ -17,7 +17,8 @@ let
};
in
{
options.my = with lib.types; {
options = with lib.types; {
my = {
boot.isDevVM = mkBoolOpt' false "Whether the system is a development VM.";
build = options.system.build;
asDevVM = mkOption {
@ -28,8 +29,19 @@ in
};
};
config.my.build = {
# Forward declare options that won't exist until the VM module is actually imported
virtualisation = {
diskImage = dummyOption;
};
};
config = {
virtualisation = {
diskImage = mkDefault "./.vms/${config.system.name}.qcow2";
};
my.build = {
# The meta.mainProgram should probably be set upstream but oh well...
devVM = recursiveUpdate config.my.asDevVM.system.build.vm { meta.mainProgram = "run-${config.system.name}-vm"; };
};
};
}

View File

@ -1,9 +1,10 @@
{ lib, pkgs, config, ... }:
let
inherit (lib) concatStringsSep concatMap concatMapStringsSep mkIf mkDefault mkMerge mkVMOverride;
inherit (lib.my) mkOpt' mkBoolOpt' mkVMOverride' dummyOption;
inherit (lib) optionalString concatStringsSep concatMap concatMapStringsSep mkIf mkDefault mkMerge mkVMOverride;
inherit (lib.my) mkOpt' mkBoolOpt' mkVMOverride';
cfg = config.my.tmproot;
enablePersistence = cfg.persistDir != null;
showUnsaved =
''
@ -56,27 +57,18 @@ in
options = with lib.types; {
my.tmproot = {
enable = mkBoolOpt' true "Whether to enable tmproot.";
persistDir = mkOpt' str "/persist" "Path where persisted files are stored.";
persistDir = mkOpt' (nullOr str) "/persist" "Path where persisted files are stored.";
size = mkOpt' str "2G" "Size of tmpfs root";
unsaved = {
showMotd = mkBoolOpt' true "Whether to show unsaved files with `dynamic-motd`.";
ignore = mkOpt' (listOf str) [ ] "Path prefixes to ignore if unsaved.";
};
};
# Forward declare options that won't exist until the VM module is actually imported
virtualisation = {
diskImage = dummyOption;
};
};
config = mkIf cfg.enable (mkMerge [
{
assertions = [
{
assertion = config.fileSystems ? "${cfg.persistDir}";
message = "The 'fileSystems' option does not specify your persistence file system (${cfg.persistDir}).";
}
{
# I mean you probably _could_, but if you're doing tmproot... come on
assertion = !config.users.mutableUsers;
@ -112,6 +104,51 @@ in
(pkgs.writeScriptBin "tmproot-unsaved" showUnsaved)
];
my.dynamic-motd.script = mkIf cfg.unsaved.showMotd
''
tmprootUnsaved() {
local count="$(tmproot-unsaved | wc -l)"
[ $count -eq 0 ] && return
echo
echo -e "\t\e[31;1;4mWarning:\e[0m $count file(s) on / will be lost on shutdown!"
echo -e '\tTo see them, run `tmproot-unsaved` as root.'
${optionalString enablePersistence ''
echo -e '\tAdd these files to `environment.persistence."${cfg.persistDir}"` to keep them!'
''}
echo -e "\tIf they don't need to be kept, add them to \`my.tmproot.unsaved.ignore\`."
echo
}
tmprootUnsaved
'';
fileSystems."/" = rootDef;
}
(mkIf config.networking.resolvconf.enable {
my.tmproot.unsaved.ignore = [ "/etc/resolv.conf" ];
})
(mkIf config.security.doas.enable {
my.tmproot.unsaved.ignore = [ "/etc/doas.conf" ];
})
(mkIf config.my.boot.isDevVM {
my.tmproot.unsaved.ignore = [ "/nix" ];
fileSystems = mkVMOverride {
"/" = mkVMOverride' rootDef;
};
})
(mkIf enablePersistence (mkMerge [
{
assertions = [
{
assertion = config.fileSystems ? "${cfg.persistDir}";
message = "The 'fileSystems' option does not specify your persistence file system (${cfg.persistDir}).";
}
];
# Catch non-existent source directories that are needed for boot (see `pathsNeededForBoot` in
# nixos/lib/util.nix). We do this by monkey-patching the `waitDevice` function that would otherwise hang.
boot.initrd.postDeviceCommands =
@ -154,25 +191,6 @@ in
];
};
my.dynamic-motd.script = mkIf cfg.unsaved.showMotd
''
tmprootUnsaved() {
local count="$(tmproot-unsaved | wc -l)"
[ $count -eq 0 ] && return
echo
echo -e "\t\e[31;1;4mWarning:\e[0m $count file(s) on / will be lost on shutdown!"
echo -e '\tTo see them, run `tmproot-unsaved` as root.'
echo -e '\tAdd these files to `environment.persistence."${cfg.persistDir}"` to keep them!'
echo -e '\tOtherwise, they can be ignored by adding to `my.tmproot.unsaved.ignore`.'
echo
}
tmprootUnsaved
'';
fileSystems."/" = rootDef;
virtualisation = {
diskImage = "./.vms/${config.system.name}-persist.qcow2";
};
@ -181,17 +199,8 @@ in
environment.persistence."${cfg.persistDir}".files =
concatMap (k: [ k.path "${k.path}.pub" ]) config.services.openssh.hostKeys;
})
(mkIf config.networking.resolvconf.enable {
my.tmproot.unsaved.ignore = [ "/etc/resolv.conf" ];
})
(mkIf config.security.doas.enable {
my.tmproot.unsaved.ignore = [ "/etc/doas.conf" ];
})
(mkIf config.my.boot.isDevVM {
my.tmproot.unsaved.ignore = [ "/nix" ];
fileSystems = mkVMOverride {
"/" = mkVMOverride' rootDef;
# Hijack the "root" device for persistence in the VM
"${cfg.persistDir}" = {
device = config.virtualisation.bootDevice;
@ -199,5 +208,6 @@ in
};
};
})
]))
]);
}

View File

@ -1,13 +1,14 @@
{ lib, pkgsFlakes, inputs, modules }:
let
inherit (builtins) attrValues mapAttrs;
inherit (lib) mkDefault;
inherit (lib) optionals mkDefault;
mkSystem =
name: {
system,
nixpkgs ? "unstable",
config,
docCustom ? true,
}:
let
pkgsFlake = pkgsFlakes.${nixpkgs};
@ -31,8 +32,8 @@ let
inputs.impermanence.nixosModule
inputs.agenix.nixosModules.age
inputs.home-manager.nixosModule
] ++ modules;
modules = [
] ++ (optionals docCustom modules);
modules = (optionals (!docCustom) modules) ++ [
{
_module.args = { inherit system inputs; };
system.name = name;