feat(ops/auto-deploy): Support auto-deploy

Automatically rebuild the current system's NixOS config from the latest checkout
of depot.

Change-Id: I23aa7af50e16e985ac34df214e0905e770316e5e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/4390
Reviewed-by: wpcarro <wpcarro@gmail.com>
Reviewed-by: zseri <zseri.devel@ytrizja.de>
Reviewed-by: grfn <grfn@gws.fyi>
Autosubmit: wpcarro <wpcarro@gmail.com>
Tested-by: BuildkiteCI
This commit is contained in:
William Carroll 2021-12-16 19:49:23 -05:00 committed by clbot
parent 1d10adb67c
commit 80ef71e995
4 changed files with 103 additions and 3 deletions

View file

@ -0,0 +1,92 @@
# Defines a service for automatically and periodically calling depot's
# rebuild-system on a NixOS machine.
{ depot, config, lib, pkgs, ... }:
let
cfg = config.services.depot.auto-deploy;
description = "to automatically rebuild the current system's NixOS config from the latest checkout of depot";
rebuild-system = depot.ops.nixos.rebuildSystemWith "$STATE_DIRECTORY/deploy";
deployScript = pkgs.writeShellScript "auto-deploy" ''
set -ueo pipefail
if [[ $EUID -ne 0 ]]; then
echo "Oh no! Only root is allowed to run auto-deploy!" >&2
exit 1
fi
readonly depot=$STATE_DIRECTORY/depot.git
readonly deploy=$STATE_DIRECTORY/deploy
readonly git="git -C $depot"
# find-or-create depot
if [ ! -d $depot ]; then
# cannot use $git here because $depot doesn't exist
git clone --bare ${cfg.git-remote} $depot
fi
function cleanup() {
$git worktree remove $deploy
}
trap cleanup EXIT
$git fetch origin
$git worktree add --force $deploy FETCH_HEAD
# unsure why, but without this switch-to-configuration attempts to install
# NixOS in $STATE_DIRECTORY
(cd / && ${rebuild-system}/bin/rebuild-system)
'';
in {
options.services.depot.auto-deploy = {
enable = lib.mkEnableOption description;
git-remote = lib.mkOption {
type = lib.types.str;
default = "https://cl.tvl.fyi/depot.git";
description = ''
The (possibly remote) repository from which to clone as specified by the
GIT URLS section of `man git-clone`.
'';
};
interval = lib.mkOption {
type = lib.types.str;
example = "1h";
description = ''
Interval between Nix builds, specified in systemd.time(7) format.
'';
};
};
config = lib.mkIf cfg.enable {
systemd.services.auto-deploy = {
inherit description;
script = "${deployScript}";
path = [
pkgs.bash
pkgs.git
];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
# We need to prevent NixOS from interrupting us while it attempts to
# restart systemd units.
restartIfChanged = false;
serviceConfig = {
Type = "oneshot";
StateDirectory = "auto-deploy";
};
};
systemd.timers.auto-deploy = {
inherit description;
wantedBy = [ "multi-user.target" ];
timerConfig = {
OnActiveSec = "1";
OnUnitActiveSec = cfg.interval;
};
};
};
}

View file

@ -8,6 +8,7 @@
{
imports = [
./automatic-gc.nix
./auto-deploy.nix
./tvl-cache.nix
];
}

View file

@ -32,7 +32,9 @@ in rec {
(throw "${hostname} is not a known NixOS host")
(map nixosFor depot.ops.machines.all-systems));
rebuild-system = pkgs.writeShellScriptBin "rebuild-system" ''
rebuild-system = rebuildSystemWith depot.path;
rebuildSystemWith = depotPath: pkgs.writeShellScriptBin "rebuild-system" ''
set -ue
if [[ $EUID -ne 0 ]]; then
echo "Oh no! Only root is allowed to rebuild the system!" >&2
@ -40,9 +42,9 @@ in rec {
fi
echo "Rebuilding NixOS for $HOSTNAME"
system=$(nix-build -E "((import ${toString depot.path} {}).ops.nixos.findSystem \"$HOSTNAME\").system" --no-out-link --show-trace)
system=$(${pkgs.nix}/bin/nix-build -E "((import ${depotPath} {}).ops.nixos.findSystem \"$HOSTNAME\").system" --no-out-link --show-trace)
nix-env -p /nix/var/nix/profiles/system --set $system
${pkgs.nix}/bin/nix-env -p /nix/var/nix/profiles/system --set $system
$system/bin/switch-to-configuration switch
'';

View file

@ -68,6 +68,11 @@ in {
];
};
depot.auto-deploy = {
enable = true;
interval = "1h";
};
journaldriver = {
enable = true;
logStream = "home";