at 24.11-pre 4.7 kB view raw
1{ config, lib, pkgs, ... }: 2 3let 4 cfg = config.services.self-deploy; 5 6 workingDirectory = "/var/lib/nixos-self-deploy"; 7 repositoryDirectory = "${workingDirectory}/repo"; 8 outPath = "${workingDirectory}/system"; 9 10 gitWithRepo = "git -C ${repositoryDirectory}"; 11 12 renderNixArgs = args: 13 let 14 toArg = key: value: 15 if builtins.isString value 16 then " --argstr ${lib.escapeShellArg key} ${lib.escapeShellArg value}" 17 else " --arg ${lib.escapeShellArg key} ${lib.escapeShellArg (toString value)}"; 18 in 19 lib.concatStrings (lib.mapAttrsToList toArg args); 20 21 isPathType = x: lib.types.path.check x; 22 23in 24{ 25 options.services.self-deploy = { 26 enable = lib.mkEnableOption "self-deploy"; 27 28 nixFile = lib.mkOption { 29 type = lib.types.path; 30 31 default = "/default.nix"; 32 33 description = '' 34 Path to nix file in repository. Leading '/' refers to root of 35 git repository. 36 ''; 37 }; 38 39 nixAttribute = lib.mkOption { 40 type = with lib.types; nullOr str; 41 42 default = null; 43 44 description = '' 45 Attribute of `nixFile` that builds the current system. 46 ''; 47 }; 48 49 nixArgs = lib.mkOption { 50 type = lib.types.attrs; 51 52 default = { }; 53 54 description = '' 55 Arguments to `nix-build` passed as `--argstr` or `--arg` depending on 56 the type. 57 ''; 58 }; 59 60 switchCommand = lib.mkOption { 61 type = lib.types.enum [ "boot" "switch" "dry-activate" "test" ]; 62 63 default = "switch"; 64 65 description = '' 66 The `switch-to-configuration` subcommand used. 67 ''; 68 }; 69 70 repository = lib.mkOption { 71 type = with lib.types; oneOf [ path str ]; 72 73 description = '' 74 The repository to fetch from. Must be properly formatted for git. 75 76 If this value is set to a path (must begin with `/`) then it's 77 assumed that the repository is local and the resulting service 78 won't wait for the network to be up. 79 80 If the repository will be fetched over SSH, you must add an 81 entry to `programs.ssh.knownHosts` for the SSH host for the fetch 82 to be successful. 83 ''; 84 }; 85 86 sshKeyFile = lib.mkOption { 87 type = with lib.types; nullOr path; 88 89 default = null; 90 91 description = '' 92 Path to SSH private key used to fetch private repositories over 93 SSH. 94 ''; 95 }; 96 97 branch = lib.mkOption { 98 type = lib.types.str; 99 100 default = "master"; 101 102 description = '' 103 Branch to track 104 105 Technically speaking any ref can be specified here, as this is 106 passed directly to a `git fetch`, but for the use-case of 107 continuous deployment you're likely to want to specify a branch. 108 ''; 109 }; 110 111 startAt = lib.mkOption { 112 type = with lib.types; either str (listOf str); 113 114 default = "hourly"; 115 116 description = '' 117 The schedule on which to run the `self-deploy` service. Format 118 specified by `systemd.time 7`. 119 120 This value can also be a list of `systemd.time 7` formatted 121 strings, in which case the service will be started on multiple 122 schedules. 123 ''; 124 }; 125 }; 126 127 config = lib.mkIf cfg.enable { 128 systemd.services.self-deploy = rec { 129 inherit (cfg) startAt; 130 131 serviceConfig.Type = "oneshot"; 132 133 requires = lib.mkIf (!(isPathType cfg.repository)) [ "network-online.target" ]; 134 135 after = requires; 136 137 environment.GIT_SSH_COMMAND = lib.mkIf (cfg.sshKeyFile != null) 138 "${pkgs.openssh}/bin/ssh -i ${lib.escapeShellArg cfg.sshKeyFile}"; 139 140 restartIfChanged = false; 141 142 path = with pkgs; [ 143 git 144 gnutar 145 gzip 146 nix 147 ] ++ lib.optionals (cfg.switchCommand == "boot") [ systemd ]; 148 149 script = '' 150 if [ ! -e ${repositoryDirectory} ]; then 151 mkdir --parents ${repositoryDirectory} 152 git init ${repositoryDirectory} 153 fi 154 155 ${gitWithRepo} fetch ${lib.escapeShellArg cfg.repository} ${lib.escapeShellArg cfg.branch} 156 157 ${gitWithRepo} checkout FETCH_HEAD 158 159 nix-build${renderNixArgs cfg.nixArgs} ${lib.cli.toGNUCommandLineShell { } { 160 attr = cfg.nixAttribute; 161 out-link = outPath; 162 }} ${lib.escapeShellArg "${repositoryDirectory}${cfg.nixFile}"} 163 164 ${lib.optionalString (cfg.switchCommand != "test") 165 "nix-env --profile /nix/var/nix/profiles/system --set ${outPath}"} 166 167 ${outPath}/bin/switch-to-configuration ${cfg.switchCommand} 168 169 rm ${outPath} 170 171 ${gitWithRepo} gc --prune=all 172 173 ${lib.optionalString (cfg.switchCommand == "boot") "systemctl reboot"} 174 ''; 175 }; 176 }; 177}