Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

services: move out function and create setup hook

+303 -263
+9 -2
flake.nix
··· 13 13 { ... }: 14 14 { 15 15 imports = [ 16 + ./nix/lib.nix 16 17 ./nix/flake-module.nix 17 18 ./nix/legacy-flake-module.nix 18 19 inputs.process-compose-flake.flakeModule ··· 105 106 }; 106 107 }; 107 108 108 - packages = { 109 + packages = rec { 109 110 seed-ci = pkgs.callPackage ./nix/packages/seed-ci.nix { }; 111 + 110 112 client = pkgs.callPackage ./nix/packages/client.nix { 111 113 buildGoModule = pkgs.buildGo123Module; 112 114 inherit version; 113 115 }; 116 + 114 117 server = pkgs.callPackage ./nix/packages/server.nix { 115 118 inherit 116 119 beamPackages 117 120 elixir 118 - inputs 119 121 version 122 + sowerServicesHook 120 123 ; 124 + 125 + sowerLib = self.lib; 121 126 }; 127 + 128 + sowerServicesHook = pkgs.callPackage ./nix/packages/services-hook.nix { }; 122 129 }; 123 130 124 131 process-compose.devServices =
+241
nix/lib.nix
··· 1 + { 2 + inputs, 3 + ... 4 + }: 5 + { 6 + flake.lib.generateUnitFiles = 7 + { 8 + pkgs, 9 + config, 10 + }: 11 + let 12 + moduler = pkgs.lib.evalModules { 13 + modules = [ 14 + { 15 + config._module.args = { 16 + inherit pkgs; 17 + }; 18 + } 19 + ( 20 + { 21 + config, 22 + lib, 23 + ... 24 + }: 25 + let 26 + utils = import "${inputs.nixpkgs}/nixos/lib/utils.nix" { 27 + inherit config lib pkgs; 28 + }; 29 + 30 + inherit (utils) systemdUtils; 31 + 32 + inherit (systemdUtils.lib) 33 + targetToUnit 34 + serviceToUnit 35 + socketToUnit 36 + timerToUnit 37 + mountToUnit 38 + automountToUnit 39 + ; 40 + 41 + inherit (lib) 42 + listToAttrs 43 + literalExpression 44 + mkEnableOption 45 + mkOption 46 + mkPackageOption 47 + types 48 + mapAttrs' 49 + ; 50 + 51 + cfg = config.systemd; 52 + in 53 + { 54 + options = { 55 + service-units = lib.mkOption { 56 + # TODO type this 57 + }; 58 + 59 + systemd = { 60 + package = mkPackageOption pkgs "systemd" { }; 61 + 62 + enableStrictShellChecks = mkEnableOption "" // { 63 + description = "Whether to run shellcheck on the generated scripts for systemd units."; 64 + }; 65 + 66 + units = mkOption { 67 + description = "Definition of systemd units; see {manpage}`systemd.unit(5)`."; 68 + default = { }; 69 + type = systemdUtils.types.units; 70 + }; 71 + 72 + packages = mkOption { 73 + default = [ ]; 74 + type = types.listOf types.package; 75 + example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]"; 76 + description = "Packages providing systemd units and hooks."; 77 + }; 78 + 79 + targets = mkOption { 80 + default = { }; 81 + type = systemdUtils.types.targets; 82 + description = "Definition of systemd target units; see {manpage}`systemd.target(5)`"; 83 + }; 84 + 85 + services = mkOption { 86 + default = { }; 87 + type = systemdUtils.types.services; 88 + description = "Definition of systemd service units; see {manpage}`systemd.service(5)`."; 89 + }; 90 + 91 + sockets = mkOption { 92 + default = { }; 93 + type = systemdUtils.types.sockets; 94 + description = "Definition of systemd socket units; see {manpage}`systemd.socket(5)`."; 95 + }; 96 + 97 + timers = mkOption { 98 + default = { }; 99 + type = systemdUtils.types.timers; 100 + description = "Definition of systemd timer units; see {manpage}`systemd.timer(5)`."; 101 + }; 102 + 103 + paths = mkOption { 104 + default = { }; 105 + type = systemdUtils.types.paths; 106 + description = "Definition of systemd path units; see {manpage}`systemd.path(5)`."; 107 + }; 108 + 109 + mounts = mkOption { 110 + default = [ ]; 111 + type = systemdUtils.types.mounts; 112 + description = '' 113 + Definition of systemd mount units; see {manpage}`systemd.mount(5)`. 114 + 115 + This is a list instead of an attrSet, because systemd mandates 116 + the names to be derived from the `where` attribute. 117 + ''; 118 + }; 119 + 120 + automounts = mkOption { 121 + default = [ ]; 122 + type = systemdUtils.types.automounts; 123 + description = '' 124 + Definition of systemd automount units; see {manpage}`systemd.automount(5)`. 125 + 126 + This is a list instead of an attrSet, because systemd mandates 127 + the names to be derived from the `where` attribute. 128 + ''; 129 + }; 130 + 131 + defaultUnit = mkOption { 132 + default = "multi-user.target"; 133 + type = types.str; 134 + description = '' 135 + Default unit started when the system boots; see {manpage}`systemd.special(7)`. 136 + ''; 137 + }; 138 + 139 + ctrlAltDelUnit = mkOption { 140 + default = "reboot.target"; 141 + type = types.str; 142 + example = "poweroff.target"; 143 + description = '' 144 + Target that should be started when Ctrl-Alt-Delete is pressed; 145 + see {manpage}`systemd.special(7)`. 146 + ''; 147 + }; 148 + 149 + globalEnvironment = mkOption { 150 + type = 151 + with types; 152 + attrsOf ( 153 + nullOr (oneOf [ 154 + str 155 + path 156 + package 157 + ]) 158 + ); 159 + default = { }; 160 + example = { 161 + TZ = "CET"; 162 + }; 163 + description = '' 164 + Environment variables passed to *all* systemd units. 165 + ''; 166 + }; 167 + 168 + }; 169 + }; 170 + 171 + config = { 172 + systemd = { 173 + package = pkgs.systemd; 174 + defaultUnit = "default.target"; 175 + ctrlAltDelUnit = "reboot.target"; 176 + 177 + units = 178 + let 179 + withName = cfgToUnit: cfg: lib.nameValuePair cfg.name (cfgToUnit cfg); 180 + in 181 + mapAttrs' (_: withName serviceToUnit) cfg.services 182 + // mapAttrs' (_: withName socketToUnit) cfg.sockets 183 + // mapAttrs' (_: withName targetToUnit) cfg.targets 184 + // mapAttrs' (_: withName timerToUnit) cfg.timers 185 + // listToAttrs (map (withName mountToUnit) cfg.mounts) 186 + // listToAttrs (map (withName automountToUnit) cfg.automounts); 187 + }; 188 + }; 189 + 190 + } 191 + ) 192 + ( 193 + { 194 + config, 195 + lib, 196 + pkgs, 197 + ... 198 + }: 199 + let 200 + utils = import "${inputs.nixpkgs}/nixos/lib/utils.nix" { 201 + inherit config lib pkgs; 202 + }; 203 + upstreamUnits = [ 204 + "basic.target" 205 + ]; 206 + 207 + upstreamWants = [ 208 + "multi-user.target.wants" 209 + ]; 210 + 211 + system-units = utils.systemdUtils.lib.generateUnits { 212 + type = "system"; 213 + inherit (config.systemd) units; 214 + inherit upstreamUnits upstreamWants; 215 + packages = [ ]; 216 + }; 217 + in 218 + { 219 + config = { 220 + service-units = pkgs.runCommand "service-units" { } '' 221 + cp -R ${system-units} $out 222 + chmod +w -R $out 223 + find $out -xtype l -delete 224 + find $out -type d -empty -delete 225 + for unit in ${builtins.toString upstreamUnits}; do 226 + rm $out/$unit 227 + done 228 + ''; 229 + }; 230 + } 231 + ) 232 + { 233 + systemd = config; 234 + } 235 + ]; 236 + class = "sower_services"; 237 + }; 238 + 239 + in 240 + moduler.config.service-units; 241 + }
+10 -261
nix/packages/server.nix
··· 1 1 { 2 - inputs, 3 2 lib, 3 + sowerLib, 4 4 pkgs, 5 5 callPackages, 6 6 beamPackages, ··· 10 10 tailwindcss, 11 11 stdenv, 12 12 version, 13 + sowerServicesHook, 13 14 }: 14 15 let 15 16 arch = if stdenv.isAarch64 then "arm64" else "x64"; 16 17 os = if stdenv.isDarwin then "darwin" else "linux"; 17 - pkgs' = pkgs; 18 - 19 - generateUnitFiles = 20 - { 21 - pkgs, 22 - config, 23 - }: 24 - let 25 - moduler = lib.evalModules { 26 - modules = [ 27 - { 28 - config._module.args = { 29 - inherit pkgs; 30 - }; 31 - } 32 - ( 33 - { 34 - config, 35 - lib, 36 - ... 37 - }: 38 - let 39 - utils = import "${inputs.nixpkgs}/nixos/lib/utils.nix" { 40 - inherit config lib pkgs; 41 - }; 42 - 43 - inherit (utils) systemdUtils; 44 - 45 - inherit (systemdUtils.lib) 46 - generateUnits 47 - targetToUnit 48 - serviceToUnit 49 - socketToUnit 50 - timerToUnit 51 - pathToUnit 52 - mountToUnit 53 - automountToUnit 54 - sliceToUnit 55 - ; 56 - 57 - inherit (lib) 58 - listToAttrs 59 - literalExpression 60 - mkEnableOption 61 - mkOption 62 - mkPackageOption 63 - types 64 - mapAttrs' 65 - ; 66 - 67 - cfg = config.systemd; 68 - in 69 - { 70 - options = { 71 - service-units = lib.mkOption { 72 - # TODO type this 73 - }; 74 - 75 - systemd = { 76 - package = mkPackageOption pkgs "systemd" { }; 77 - 78 - enableStrictShellChecks = mkEnableOption "" // { 79 - description = "Whether to run shellcheck on the generated scripts for systemd units."; 80 - }; 81 - 82 - units = mkOption { 83 - description = "Definition of systemd units; see {manpage}`systemd.unit(5)`."; 84 - default = { }; 85 - type = systemdUtils.types.units; 86 - }; 87 - 88 - packages = mkOption { 89 - default = [ ]; 90 - type = types.listOf types.package; 91 - example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]"; 92 - description = "Packages providing systemd units and hooks."; 93 - }; 94 - 95 - targets = mkOption { 96 - default = { }; 97 - type = systemdUtils.types.targets; 98 - description = "Definition of systemd target units; see {manpage}`systemd.target(5)`"; 99 - }; 100 - 101 - services = mkOption { 102 - default = { }; 103 - type = systemdUtils.types.services; 104 - description = "Definition of systemd service units; see {manpage}`systemd.service(5)`."; 105 - }; 106 - 107 - sockets = mkOption { 108 - default = { }; 109 - type = systemdUtils.types.sockets; 110 - description = "Definition of systemd socket units; see {manpage}`systemd.socket(5)`."; 111 - }; 112 - 113 - timers = mkOption { 114 - default = { }; 115 - type = systemdUtils.types.timers; 116 - description = "Definition of systemd timer units; see {manpage}`systemd.timer(5)`."; 117 - }; 118 - 119 - paths = mkOption { 120 - default = { }; 121 - type = systemdUtils.types.paths; 122 - description = "Definition of systemd path units; see {manpage}`systemd.path(5)`."; 123 - }; 124 - 125 - mounts = mkOption { 126 - default = [ ]; 127 - type = systemdUtils.types.mounts; 128 - description = '' 129 - Definition of systemd mount units; see {manpage}`systemd.mount(5)`. 130 - 131 - This is a list instead of an attrSet, because systemd mandates 132 - the names to be derived from the `where` attribute. 133 - ''; 134 - }; 135 - 136 - automounts = mkOption { 137 - default = [ ]; 138 - type = systemdUtils.types.automounts; 139 - description = '' 140 - Definition of systemd automount units; see {manpage}`systemd.automount(5)`. 141 - 142 - This is a list instead of an attrSet, because systemd mandates 143 - the names to be derived from the `where` attribute. 144 - ''; 145 - }; 146 - 147 - defaultUnit = mkOption { 148 - default = "multi-user.target"; 149 - type = types.str; 150 - description = '' 151 - Default unit started when the system boots; see {manpage}`systemd.special(7)`. 152 - ''; 153 - }; 154 - 155 - ctrlAltDelUnit = mkOption { 156 - default = "reboot.target"; 157 - type = types.str; 158 - example = "poweroff.target"; 159 - description = '' 160 - Target that should be started when Ctrl-Alt-Delete is pressed; 161 - see {manpage}`systemd.special(7)`. 162 - ''; 163 - }; 164 - 165 - globalEnvironment = mkOption { 166 - type = 167 - with types; 168 - attrsOf ( 169 - nullOr (oneOf [ 170 - str 171 - path 172 - package 173 - ]) 174 - ); 175 - default = { }; 176 - example = { 177 - TZ = "CET"; 178 - }; 179 - description = '' 180 - Environment variables passed to *all* systemd units. 181 - ''; 182 - }; 183 - 184 - }; 185 - }; 186 - 187 - config = { 188 - systemd = { 189 - package = pkgs.systemd; 190 - defaultUnit = "default.target"; 191 - ctrlAltDelUnit = "reboot.target"; 192 - 193 - units = 194 - let 195 - withName = cfgToUnit: cfg: lib.nameValuePair cfg.name (cfgToUnit cfg); 196 - in 197 - mapAttrs' (_: withName serviceToUnit) cfg.services 198 - // mapAttrs' (_: withName socketToUnit) cfg.sockets 199 - // mapAttrs' (_: withName targetToUnit) cfg.targets 200 - // mapAttrs' (_: withName timerToUnit) cfg.timers 201 - // listToAttrs (map (withName mountToUnit) cfg.mounts) 202 - // listToAttrs (map (withName automountToUnit) cfg.automounts); 203 - }; 204 - }; 205 - 206 - } 207 - ) 208 - ( 209 - { 210 - config, 211 - lib, 212 - pkgs, 213 - ... 214 - }: 215 - let 216 - utils = import "${inputs.nixpkgs}/nixos/lib/utils.nix" { 217 - inherit config lib pkgs; 218 - }; 219 - upstreamUnits = [ 220 - "basic.target" 221 - ]; 222 - 223 - upstreamWants = [ 224 - "multi-user.target.wants" 225 - ]; 226 - 227 - system-units = utils.systemdUtils.lib.generateUnits { 228 - type = "system"; 229 - inherit (config.systemd) units; 230 - inherit upstreamUnits upstreamWants; 231 - packages = [ ]; 232 - }; 233 - in 234 - { 235 - config = { 236 - service-units = pkgs.runCommand "service-units" { } '' 237 - cp -R ${system-units} $out 238 - chmod +w -R $out 239 - find $out -xtype l -delete 240 - find $out -type d -empty -delete 241 - for unit in ${builtins.toString upstreamUnits}; do 242 - rm $out/$unit 243 - done 244 - ''; 245 - }; 246 - } 247 - ) 248 - { 249 - systemd = config; 250 - } 251 - ]; 252 - class = "sower_services"; 253 - }; 254 - 255 - in 256 - moduler.config.service-units; 257 18 in 258 19 beamPackages.mixRelease rec { 259 20 pname = "sower"; ··· 275 36 ]; 276 37 }; 277 38 278 - sowerServices = generateUnitFiles { 39 + nativeBuildInputs = [ sowerServicesHook ]; 40 + 41 + sowerServices = sowerLib.generateUnitFiles { 279 42 inherit pkgs; 280 43 config = { 281 - services.test = { 44 + services.sower = { 282 45 wantedBy = [ 283 - "default.target" 284 - "network-online.target" 285 46 "multi-user.target" 286 47 ]; 48 + 287 49 serviceConfig = { 288 50 Type = "oneshot"; 289 - ExecStart = "PLACEHOLDER_OUT/bin/sower"; 51 + ExecStart = "PLACEHOLDER_OUT/bin/sower start"; 52 + ExecStop = "PLACEHOLDER_OUT/bin/sower stop"; 290 53 }; 291 54 }; 292 - 293 - sockets.test-socket = { 294 - wantedBy = [ "sockets.target" ]; 295 - }; 296 55 }; 297 56 }; 298 57 ··· 342 101 mix assets.deploy --no-deps-check 343 102 ''; 344 103 345 - preInstall = '' 346 - mkdir -p $out/.sower/systemd/system 347 - find ${sowerServices} -mindepth 1 -type d | while read dir; do 348 - cp --recursive $dir $out/.sower/systemd/system/ 349 - done 350 - cp --dereference ${sowerServices}/* $out/.sower/systemd/system || true 351 - find $out/.sower/systemd/ -type f | while read unit; do 352 - chmod +w $unit 353 - sed -i "s,PLACEHOLDER_OUT,$out," $unit 354 - done 355 - ''; 104 + preInstall = ''''; 356 105 357 106 # disabled because requires test deps to work 358 107 # doCheck = true;
+43
nix/packages/services-hook.nix
··· 1 + { 2 + makeSetupHook, 3 + writeScript, 4 + }: 5 + 6 + makeSetupHook 7 + { 8 + name = "sower-services-hook"; 9 + meta = { 10 + description = "Install systemd services from `sowerServices` for use in a sower services package"; 11 + }; 12 + } 13 + ( 14 + writeScript "sower-services-hook.sh" # bash 15 + '' 16 + _sowerServicesHook() { 17 + echo "Installing Sower Services" 18 + 19 + mkdir -p $out/.sower/systemd/system 20 + 21 + # copy over top-level system directories, which likely include links to units 22 + find $sowerServices -mindepth 1 -type d | while read dir; do 23 + cp --recursive $dir $out/.sower/systemd/system/ 24 + done 25 + 26 + # copy the unit files 27 + find $sowerServices -maxdepth 1 -type l | while read unit; do 28 + cp --dereference $unit $out/.sower/systemd/system/ || true 29 + done 30 + 31 + # replace PLACEHOLDER_OUT with package $out 32 + find $out/.sower/systemd/ -type f | while read unit; do 33 + chmod +w $unit 34 + sed -i "s,PLACEHOLDER_OUT,$out," $unit 35 + done 36 + 37 + # delete any empty dirs 38 + find $out/.sower/systemd -type d -empty -delete 39 + } 40 + 41 + preInstallHooks+=(_sowerServicesHook) 42 + '' 43 + )