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