at 21.11-pre 4.5 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.strings.isCoercibleToString x && builtins.substring 0 1 (toString 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 = lib.types.str; 41 42 description = '' 43 Attribute of `nixFile` that builds the current system. 44 ''; 45 }; 46 47 nixArgs = lib.mkOption { 48 type = lib.types.attrs; 49 50 default = { }; 51 52 description = '' 53 Arguments to `nix-build` passed as `--argstr` or `--arg` depending on 54 the type. 55 ''; 56 }; 57 58 switchCommand = lib.mkOption { 59 type = lib.types.enum [ "boot" "switch" "dry-activate" "test" ]; 60 61 default = "switch"; 62 63 description = '' 64 The `switch-to-configuration` subcommand used. 65 ''; 66 }; 67 68 repository = lib.mkOption { 69 type = with lib.types; oneOf [ path str ]; 70 71 description = '' 72 The repository to fetch from. Must be properly formatted for git. 73 74 If this value is set to a path (must begin with `/`) then it's 75 assumed that the repository is local and the resulting service 76 won't wait for the network to be up. 77 78 If the repository will be fetched over SSH, you must add an 79 entry to `programs.ssh.knownHosts` for the SSH host for the fetch 80 to be successful. 81 ''; 82 }; 83 84 sshKeyFile = lib.mkOption { 85 type = with lib.types; nullOr path; 86 87 default = null; 88 89 description = '' 90 Path to SSH private key used to fetch private repositories over 91 SSH. 92 ''; 93 }; 94 95 branch = lib.mkOption { 96 type = lib.types.str; 97 98 default = "master"; 99 100 description = '' 101 Branch to track 102 103 Technically speaking any ref can be specified here, as this is 104 passed directly to a `git fetch`, but for the use-case of 105 continuous deployment you're likely to want to specify a branch. 106 ''; 107 }; 108 109 startAt = lib.mkOption { 110 type = with lib.types; either str (listOf str); 111 112 default = "hourly"; 113 114 description = '' 115 The schedule on which to run the `self-deploy` service. Format 116 specified by `systemd.time 7`. 117 118 This value can also be a list of `systemd.time 7` formatted 119 strings, in which case the service will be started on multiple 120 schedules. 121 ''; 122 }; 123 }; 124 125 config = lib.mkIf cfg.enable { 126 systemd.services.self-deploy = { 127 wantedBy = [ "multi-user.target" ]; 128 129 requires = lib.mkIf (!(isPathType cfg.repository)) [ "network-online.target" ]; 130 131 environment.GIT_SSH_COMMAND = lib.mkIf (!(isNull cfg.sshKeyFile)) 132 "${pkgs.openssh}/bin/ssh -i ${lib.escapeShellArg cfg.sshKeyFile}"; 133 134 restartIfChanged = false; 135 136 path = with pkgs; [ 137 git 138 nix 139 systemd 140 ]; 141 142 script = '' 143 if [ ! -e ${repositoryDirectory} ]; then 144 mkdir --parents ${repositoryDirectory} 145 git init ${repositoryDirectory} 146 fi 147 148 ${gitWithRepo} fetch ${lib.escapeShellArg cfg.repository} ${lib.escapeShellArg cfg.branch} 149 150 ${gitWithRepo} checkout FETCH_HEAD 151 152 nix-build${renderNixArgs cfg.nixArgs} ${lib.cli.toGNUCommandLineShell { } { 153 attr = cfg.nixAttribute; 154 out-link = outPath; 155 }} ${lib.escapeShellArg "${repositoryDirectory}${cfg.nixFile}"} 156 157 ${lib.optionalString (cfg.switchCommand != "test") 158 "nix-env --profile /nix/var/nix/profiles/system --set ${outPath}"} 159 160 ${outPath}/bin/switch-to-configuration ${cfg.switchCommand} 161 162 rm ${outPath} 163 164 ${gitWithRepo} gc --prune=all 165 166 ${lib.optionalString (cfg.switchCommand == "boot") "systemctl reboot"} 167 ''; 168 }; 169 }; 170}