summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/nixos/personal/default.nix1
-rw-r--r--modules/nixos/personal/nix.nix164
-rw-r--r--modules/nixos/personal/system.nix220
3 files changed, 221 insertions, 164 deletions
diff --git a/modules/nixos/personal/default.nix b/modules/nixos/personal/default.nix
index 064260a..dfc7291 100644
--- a/modules/nixos/personal/default.nix
+++ b/modules/nixos/personal/default.nix
@@ -7,6 +7,7 @@
./monitoring.nix
./networking
./nix.nix
+ ./system.nix
./user.nix
];
}
diff --git a/modules/nixos/personal/nix.nix b/modules/nixos/personal/nix.nix
index cab9128..17471c2 100644
--- a/modules/nixos/personal/nix.nix
+++ b/modules/nixos/personal/nix.nix
@@ -5,72 +5,10 @@
...
}: let
cfg = config.personal.nix;
- hasFlake = cfg.flake != null;
- hasFlakeInputs = cfg.autoUpgrade.autoUpdateInputs != [];
- checkNetwork = {
- path = [pkgs.unixtools.ping];
- # Check network connectivity
- preStart = "(${lib.concatMapStringsSep " && " (host: "ping -c 1 ${host}") cfg.autoUpgrade.checkHosts}) || kill -s SIGUSR1 $$";
- unitConfig = {
- StartLimitIntervalSec = 300;
- StartLimitBurst = 5;
- };
- serviceConfig = {
- Restart = "on-abort";
- RestartSec = 30;
- };
- };
in {
options.personal.nix = {
enable = lib.mkEnableOption "nix configuration";
- autoUpgrade = {
- enable = lib.mkEnableOption "automatic system and nixpkgs upgrade";
- autoUpdateInputs = lib.mkOption {
- type = with lib.types; listOf str;
- default = ["nixpkgs" "my-nixpkgs/nur" "nixos-hardware"];
- };
- checkHosts = lib.mkOption {
- type = with lib.types; listOf str;
- default = with builtins; concatMap (match "https://([^/]*)/?") config.nix.settings.substituters;
- };
- };
- flake = lib.mkOption {
- type = with lib.types; nullOr str;
- default = null;
- };
gc.enable = lib.mkEnableOption "garbage collection";
- remoteBuilds = {
- enable = lib.mkEnableOption "remote builds";
- machines.hephaistos = {
- enable = lib.mkEnableOption "hephaistos remote builder";
- domain = lib.mkOption {
- type = lib.types.str;
- };
- user = lib.mkOption {
- type = lib.types.str;
- default = "nixremote";
- };
- protocol = lib.mkOption {
- type = lib.types.str;
- # Nix custom ssh-variant that avoids lots of "trusted-users" settings pain
- default = "ssh-ng";
- };
- speedFactor = lib.mkOption {
- type =
- lib.types.int;
- default = 8;
- };
- require = lib.mkOption {
- type =
- lib.types.bool;
- default = true;
- description = ''
- Whether this remote builder is required to build the configuration.
- If so, network connectivity to this remote builder will be checked prior to building.
- '';
- };
- };
- };
};
config = lib.mkIf cfg.enable (lib.mkMerge [
@@ -129,107 +67,5 @@ in {
};
};
})
-
- (lib.mkIf cfg.autoUpgrade.enable {
- personal.boot.unattendedReboot = lib.mkIf config.system.autoUpgrade.allowReboot true;
- system.autoUpgrade = {
- enable = true;
- flags = lib.optional (!hasFlake) "--upgrade-all";
- };
- systemd.services.nixos-upgrade = lib.mkMerge [
- checkNetwork
- {
- path = [config.nix.package];
- preStart = lib.mkAfter (lib.optionalString hasFlake ''
- echo "Downloading flake inputs..."
- nix flake archive ${cfg.flake}
- ''
- + ''
- echo "Evaluating configuration..."
- ${config.system.build.nixos-rebuild}/bin/nixos-rebuild dry-build ${toString config.system.autoUpgrade.flags}
- '');
- personal.monitor = true;
- }
- (let
- luksCfg = config.boot.initrd.luks.devices;
- cryptExists = luksCfg ? crypt;
- cryptCfg = luksCfg.crypt;
- in
- lib.mkIf (cryptExists && config.system.autoUpgrade.allowReboot) {
- path = [pkgs.cryptsetup];
- script = lib.mkAfter ''
- cryptsetup --verbose luksAddKey --key-file /etc/luks/keys/master ${cryptCfg.device} /etc/luks/keys/tmp
- '';
- serviceConfig.TimeoutStopSec = "infinity";
- postStop = ''
- # if a reboot due to nixos-upgrade happens,
- # it should occur within a minute
- sleep 60
- # if no reboot has happened,
- # disable any leftover keyfile
- while cryptsetup --verbose luksRemoveKey ${cryptCfg.device} --key-file /etc/luks/keys/tmp
- do
- :
- done
- '';
- })
- ];
- })
-
- (lib.mkIf hasFlake {
- system.autoUpgrade.flake = cfg.flake;
- systemd.services.flake-update = lib.mkIf hasFlakeInputs (lib.mkMerge [
- checkNetwork
- {
- unitConfig.Description = "Update flake inputs";
- serviceConfig = {
- ExecStart = "${config.nix.package}/bin/nix flake update --commit-lock-file --flake ${cfg.flake} " + lib.concatStringsSep " " cfg.autoUpgrade.autoUpdateInputs;
- Type = "oneshot"; # Ensure that it finishes before starting nixos-upgrade
- };
- before = ["nixos-upgrade.service"];
- requiredBy = ["nixos-upgrade.service"];
- path = [pkgs.git];
- personal.monitor = true;
- }
- ]);
-
- programs.git = lib.mkIf (lib.hasPrefix "git+file" cfg.flake) {
- enable = true;
- config.user = lib.mkDefault {
- name = "Root user of ${config.networking.hostName}";
- email = "root@${config.networking.hostName}";
- };
- };
- })
-
- (lib.mkIf cfg.remoteBuilds.enable (with cfg.remoteBuilds.machines.hephaistos; {
- nix = {
- distributedBuilds = true;
- settings.builders-use-substitutes = true;
- buildMachines = lib.optional enable {
- inherit protocol speedFactor;
- hostName = "hephaistos.${domain}";
- system = "x86_64-linux";
- maxJobs = 8;
- supportedFeatures = ["nixos-test" "benchmark" "big-parallel" "kvm" "recursive-nix"];
- mandatoryFeatures = [];
- };
- };
-
- personal.nix.autoUpgrade.checkHosts = lib.mkOptionDefault (lib.optional require "hephaistos.${domain}");
-
- programs.ssh = {
- extraConfig = lib.optionalString enable ''
- Host hephaistos.${domain}
- # Prevent using ssh-agent or another keyfile, useful for testing
- IdentitiesOnly yes
- IdentityFile /etc/ssh/${user}
- # The weakly privileged user on the remote builder
- # If not set, 'root' is used – which will hopefully fail
- User ${user}
- '';
- knownHosts."hephaistos.${domain}".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvtqi8tziBuviUV8LDK2ddQQUbHdJYB02dgWTK5Olxq";
- };
- }))
]);
}
diff --git a/modules/nixos/personal/system.nix b/modules/nixos/personal/system.nix
new file mode 100644
index 0000000..3bd3716
--- /dev/null
+++ b/modules/nixos/personal/system.nix
@@ -0,0 +1,220 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ cfg = config.personal.system;
+ cfgRemote = cfg.autoUpgrade.remoteBuilding;
+ cfgNix = config.nix;
+ cfgLuks = config.boot.initrd.luks.devices;
+
+ name = config.networking.hostName;
+in {
+ options.personal.system = {
+ flake = lib.mkOption {
+ type = with lib.types; nullOr str;
+ default = null;
+ };
+ autoUpgrade = {
+ enable = lib.mkEnableOption "automatic system and nixpkgs upgrade";
+ autoUpdateInputs = lib.mkOption {
+ type = with lib.types; listOf str;
+ default = ["nixpkgs" "my-nixpkgs/nur" "nixos-hardware"];
+ };
+ checkHosts = lib.mkOption {
+ type = with lib.types; listOf str;
+ default = with builtins; concatMap (match "https://([^/]*)/?") cfgNix.settings.substituters;
+ };
+ remoteBuilding = {
+ enable = lib.mkEnableOption "remote building of the system configuration";
+ builder = {
+ hostName = lib.mkOption {
+ type = lib.types.str;
+ default = "hephaistos";
+ };
+ domain = lib.mkOption {type = lib.types.str;};
+ user = lib.mkOption {
+ type = lib.types.str;
+ default = name;
+ };
+ protocol = lib.mkOption {
+ type = lib.types.str;
+ # Nix custom ssh-variant that avoids lots of "trusted-users" settings pain
+ default = "ssh-ng";
+ };
+ speedFactor = lib.mkOption {
+ type =
+ lib.types.int;
+ default = 8;
+ };
+ };
+ };
+ };
+ };
+
+ config = let
+ hasFlake = cfg.flake != null;
+ hasFlakeInputs = cfg.autoUpgrade.autoUpdateInputs != [];
+
+ reboot = config.system.autoUpgrade.allowReboot;
+ nixosRebuild = "nixos-rebuild ${toString config.system.autoUpgrade.flags}";
+
+ remoteBuilder = with cfgRemote.builder; "${hostName}.${domain}";
+
+ checkNetwork = {
+ path = [pkgs.unixtools.ping];
+ # Check network connectivity
+ preStart = "(${lib.concatMapStringsSep " && " (host: "ping -c 1 ${host}") cfg.autoUpgrade.checkHosts}) || kill -s SIGUSR1 $$";
+ unitConfig = {
+ StartLimitIntervalSec = 300;
+ StartLimitBurst = 5;
+ };
+ serviceConfig = {
+ Restart = "on-abort";
+ RestartSec = 30;
+ };
+ };
+ in
+ lib.mkMerge [
+ (lib.mkIf hasFlake {
+ system.autoUpgrade.flake = cfg.flake;
+ systemd.services.flake-update = lib.mkIf hasFlakeInputs (lib.mkMerge [
+ checkNetwork
+ {
+ description = "Update flake inputs";
+ serviceConfig.Type = "oneshot";
+ script = "nix flake update --commit-lock-file --flake ${cfg.flake} " + lib.concatStringsSep " " cfg.autoUpgrade.autoUpdateInputs;
+ before = ["nixos-upgrade.service"];
+ requiredBy = ["nixos-upgrade.service"];
+ path = [pkgs.git cfgNix.package];
+ personal.monitor = true;
+ }
+ ]);
+
+ programs.git = lib.mkIf (lib.hasPrefix "git+file" cfg.flake) {
+ enable = true;
+ config.user = lib.mkDefault {
+ name = "Root user of ${name}";
+ email = "root@${name}";
+ };
+ };
+ })
+
+ (
+ lib.mkIf (cfg.autoUpgrade.enable && cfgRemote.enable) {
+ assertions = [
+ {
+ assertion = hasFlake && lib.hasPrefix "git+file://" cfg.flake;
+ message = "Auto remote upgrade is only supported when the system is specified by a flake with path of the shape 'git+file://...'";
+ }
+ ];
+
+ personal.system.autoUpgrade.checkHosts = lib.mkOptionDefault [remoteBuilder];
+
+ programs.ssh = {
+ extraConfig = ''
+ Host ${remoteBuilder}
+ IdentitiesOnly yes
+ IdentityFile /etc/ssh/remoteBuilder
+ User ${cfgRemote.builder.user}
+ '';
+ knownHosts."${remoteBuilder}".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvtqi8tziBuviUV8LDK2ddQQUbHdJYB02dgWTK5Olxq";
+ };
+ }
+ )
+
+ (lib.mkIf cfg.autoUpgrade.enable {
+ personal.boot.unattendedReboot = lib.mkIf reboot true;
+ system.autoUpgrade = {
+ enable = true;
+ flags = lib.optional (!hasFlake) "--upgrade-all";
+ };
+ systemd.services.nixos-upgrade = lib.mkMerge [
+ checkNetwork
+ {
+ path =
+ lib.optional reboot pkgs.coreutils
+ ++ [
+ (
+ if cfgRemote.enable
+ then cfgNix.package
+ else pkgs.nixos-rebuild
+ )
+ ]
+ ++ lib.optional (reboot && cfgLuks ? crypt) pkgs.cryptsetup;
+ personal.monitor = true;
+ script = lib.mkForce (lib.concatStrings [
+ ''
+ ## build configuration
+ ''
+ (
+ let
+ in
+ if cfgRemote.enable
+ then ''
+ # update remote flake
+ pushd ${lib.removePrefix "git+file://" cfg.flake}
+ git push --force ${cfgRemote.builder.hostName} master
+ popd
+ # build remotely
+ config=$(ssh ${remoteBuilder} -- \
+ 'nix build --print-out-paths \
+ git+file://$(pwd)/nixos-configuration#nixosConfigurations.${name}.config.system.build.toplevel')
+ # copy result locally
+ nix-copy-closure --from ${remoteBuilder} "$config"
+ # create new generation
+ nix-env --profile /nix/var/nix/profiles/system \
+ --set "$config"
+
+ switch="$config/bin/switch-to-configuration"
+ ''
+ else ''
+ switch="${nixosRebuild}"
+ ''
+ )
+ ''
+ ## check whether a reboot is necessary"
+ ''
+ (
+ if reboot
+ then ''
+ $switch boot
+ booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})"
+ built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
+ reboot="$([ "$booted" = "$built" ] || echo true)"
+ ''
+ else ''
+ reboot=""
+ ''
+ )
+ ''
+ ## switch to new configuration
+ ''
+ (let
+ ifcrypt = lib.optionalString (cfgLuks ? crypt);
+ crypt = cfgLuks.crypt.device;
+ luksKey = x: "/etc/luks/keys/" + x;
+ in ''
+ if [ "$reboot" ]
+ then
+ ${ifcrypt ''
+ cryptsetup luksAddKey ${crypt} ${luksKey "tmp"} \
+ --key-file ${luksKey "master"} \
+ --verbose
+ ''}
+ shutdown -r now ${ifcrypt ''
+ || cryptsetup luksRemoveKey ${crypt} \
+ --key-file ${luksKey "tmp"} \
+ --verbose
+ ''}
+ else
+ $switch switch
+ fi
+ '')
+ ]);
+ }
+ ];
+ })
+ ];
+}