124 lines
4.4 KiB
Nix
124 lines
4.4 KiB
Nix
{ pkgs, ... }:
|
|
|
|
{
|
|
systemd.services.auto-update = {
|
|
description = "Auto-update NixOS configuration";
|
|
path = with pkgs; [
|
|
coreutils
|
|
curl
|
|
git
|
|
jq
|
|
nix
|
|
openssh
|
|
util-linux
|
|
];
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = "root";
|
|
WorkingDirectory = "/etc/commonscomputing-nix";
|
|
TimeoutStartSec = "6h";
|
|
};
|
|
|
|
restartIfChanged = false;
|
|
unitConfig.ConditionPathExists = "/var/lib/knot/.upgrade-verified";
|
|
unitConfig.X-StopOnRemoval = false;
|
|
environment = {
|
|
GIT_TERMINAL_PROMPT = "0";
|
|
GIT_SSH_COMMAND = "${pkgs.openssh}/bin/ssh -o BatchMode=yes -o ConnectTimeout=15";
|
|
};
|
|
|
|
script = ''
|
|
set -euo pipefail
|
|
exec 9>/run/lock/commonscomputing-update.lock
|
|
flock --nonblock 9 || exit 0
|
|
|
|
lock_snapshot="$(${pkgs.coreutils}/bin/mktemp)"
|
|
snapshot_ready=0
|
|
activated=0
|
|
validated=0
|
|
system_profile=/nix/var/nix/profiles/system
|
|
|
|
cleanup() {
|
|
status=$?
|
|
trap - EXIT
|
|
set +e
|
|
if [ "$status" -ne 0 ] && [ "$snapshot_ready" -eq 1 ] && [ "$activated" -eq 0 ]; then
|
|
${pkgs.coreutils}/bin/cp "$lock_snapshot" flake.lock
|
|
fi
|
|
if [ "$status" -ne 0 ] && [ "$activated" -eq 1 ] && [ "$validated" -eq 0 ]; then
|
|
# New binaries may already have migrated persistent state. Never
|
|
# blindly roll back their data format or discard accepted writes.
|
|
rm -f /var/lib/knot/.upgrade-verified
|
|
${pkgs.systemd}/bin/systemctl stop auto-update.timer
|
|
${pkgs.systemd}/bin/systemctl stop knot-rs.service spindle.service
|
|
echo "Activation/health failed: application services and updates stopped; inspect state and retained flake.lock" >&2
|
|
elif [ "$status" -ne 0 ] && [ "$validated" -eq 1 ]; then
|
|
echo "System is healthy, but Git publication failed; retain/reconcile the local lockfile or commit before retrying" >&2
|
|
fi
|
|
${pkgs.coreutils}/bin/rm -f "$lock_snapshot"
|
|
exit "$status"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
if ! git diff --cached --quiet; then
|
|
echo "Refusing to run with staged changes"
|
|
exit 1
|
|
fi
|
|
if ! git diff --quiet -- flake.lock; then
|
|
echo "Refusing to run with preexisting flake.lock changes"
|
|
exit 1
|
|
fi
|
|
if ! git diff --quiet -- '*.nix'; then
|
|
echo "Refusing to deploy uncommitted Nix configuration changes"
|
|
exit 1
|
|
fi
|
|
|
|
git pull --ff-only
|
|
git push --dry-run
|
|
${pkgs.coreutils}/bin/cp flake.lock "$lock_snapshot"
|
|
snapshot_ready=1
|
|
nix flake update
|
|
|
|
echo "Building NixOS toplevel..."
|
|
toplevel="$(${pkgs.nix}/bin/nix build .#nixosConfigurations.asusmini.config.system.build.toplevel --no-link --print-out-paths)"
|
|
|
|
echo "Activating new system..."
|
|
activated=1
|
|
${pkgs.nix}/bin/nix-env -p "$system_profile" --set "$toplevel"
|
|
"$toplevel/bin/switch-to-configuration" switch
|
|
|
|
${pkgs.systemd}/bin/systemctl is-active --quiet knot-rs
|
|
${pkgs.systemd}/bin/systemctl is-active --quiet spindle
|
|
${pkgs.systemd}/bin/systemctl is-active --quiet sshd
|
|
${pkgs.curl}/bin/curl --fail --silent --show-error --max-time 10 --retry 5 --retry-connrefused --retry-delay 1 http://127.0.0.1:5555/xrpc/_health | jq -e '.version | length > 0'
|
|
${pkgs.curl}/bin/curl --fail --silent --show-error --max-time 10 --retry 5 --retry-connrefused --retry-delay 1 http://127.0.0.1:6555/_health | jq -e '.status == "ok"'
|
|
${pkgs.curl}/bin/curl --fail --silent --show-error --max-time 15 https://knot.commonscomputer.com/xrpc/org.tangled.knot.describeKnot | jq -e '.did == "did:web:knot.commonscomputer.com" and .contact.email == "pds@email.commonscomputer.com"'
|
|
validated=1
|
|
snapshot_ready=0
|
|
|
|
if ! git diff --quiet -- flake.lock; then
|
|
git add flake.lock
|
|
git commit -m "auto-update: flake inputs $(${pkgs.coreutils}/bin/date -Iseconds)"
|
|
fi
|
|
git push
|
|
|
|
echo "Auto-update completed successfully"
|
|
'';
|
|
};
|
|
|
|
systemd.timers.auto-update = {
|
|
enable = true;
|
|
description = "Auto-update timer";
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnCalendar = "weekly"; # Run weekly, adjust as needed
|
|
Persistent = true; # Run on boot if missed
|
|
RandomizedDelaySec = "1h"; # Add some randomness
|
|
};
|
|
unitConfig.ConditionPathExists = "/var/lib/knot/.upgrade-verified";
|
|
};
|
|
}
|