Skip to content

Commit

Permalink
[OPS-1467] Introduce mkActivateScript for user-level systemd services
Browse files Browse the repository at this point in the history
Problem: We have many projects where we deploy similar
approaches with user-level systemd services. We need to reduce duplication.

Solution: create a flexible enough lib to cover all the best practices
  • Loading branch information
karandit committed Oct 12, 2023
1 parent 567820a commit 4fb5f87
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/systemd/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

hardenServices = import ./harden-services.nix;

userLevelServices = import ./user-level-services.nix;
}
88 changes: 88 additions & 0 deletions lib/systemd/user-level-services.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{ nixpkgs
, system ? "x86_64-linux"
, pkgs ? nixpkgs.legacyPackages.${system}, ... }:
let
mkVM = deployConfig: moduleConfig: nixpkgs.lib.nixosSystem {
inherit system;
modules = [ ({ config, pkgs, ... }: {

imports = [ deployConfig.module ];

services.${deployConfig.nixOsServiceName} = {
enable = true;
} // moduleConfig;

}) ];
};

in {
mkActivateScript = activateScriptName:
{ module, nixOsServiceName, primaryService, primaryPortAttrName, auxiliaryServices, oneShotServices}@deployConfig:
{ backupAction ? "", restoreAction ? ""}@hookConfig:
moduleConfig:
let
wantedServices = [deployConfig.primaryService] ++ deployConfig.auxiliaryServices;
allServices = wantedServices ++ deployConfig.oneShotServices;
vm = mkVM deployConfig moduleConfig;
in
pkgs.writeShellScriptBin activateScriptName ''
set -euo pipefail
export XDG_RUNTIME_DIR="/run/user/$UID"
mkdir -v -p "$HOME/.config/systemd/user/default.target.wants"
# Deploy may change DB schema via migration and we should be able
# to restore its state to a point before an update to successfully rollback
# failed deployment
echo Stopping ${deployConfig.primaryService}
systemctl --user stop ${deployConfig.primaryService} || true
echo Backing up the existing state
${hookConfig.backupAction}
${pkgs.lib.concatStringsSep "\n" (builtins.map (service:
''
rm -v -f -- "$HOME/.config/systemd/user/${service}"
ln -v -s ${vm.config.systemd.units.${service}.unit}/${service} "$HOME/.config/systemd/user/${service}"
''
) allServices)}
${pkgs.lib.concatStringsSep "\n" (builtins.map (service:
''
rm -v -f -- "$HOME/.config/systemd/user/default.target.wants/${service}"
ln -v -s "$HOME/.config/systemd/user/${service}" "$HOME/.config/systemd/user/default.target.wants"
''
) wantedServices)}
systemctl --user daemon-reload
rollback() {
exit_code="$?"
if [[ $exit_code -ne 0 ]]; then
echo Activation failed, restoring the previous working state
${hookConfig.restoreAction}
fi
exit "$exit_code"
}
trap rollback EXIT
${pkgs.lib.concatStringsSep "\n" (builtins.map (service:
''
echo Restarting ${service}
systemctl --user restart ${service}
''
) deployConfig.auxiliaryServices)}
echo Restarting ${deployConfig.primaryService}
systemctl --user restart ${deployConfig.primaryService}
# Attempt to get a 200 code for main page
retry_count=0
while [[ "$retry_count" -lt 10 ]]; do
echo "Checking if the server is up, round $((retry_count+1))"
set +e
curl --silent --show-error --fail http://127.0.0.1:${builtins.toString moduleConfig.${primaryPortAttrName}} > /dev/null && exit 0
set -e
retry_count=$((retry_count+1))
sleep 5
done
# If we didn't manage to get 200, fail and cause a rollback
exit 1
'';
}

0 comments on commit 4fb5f87

Please sign in to comment.