{ config, lib, pkgs, ... }: { options.c3d2.autoUpdate = with lib; mkOption { description = '' Enables a timer that periodically checks hydra.hq.c3d2.de for the last build of the local system, and switches to it if it is different. Also enables periodical /nix/store GC. ''; type = types.bool; default = false; }; config = { # the presence of this .service file signifies that the system is # autoupdate-enabled. it is checked to prevent autoupdating back # to a system without autoupdate when deploying with autoupdate # for the first time. systemd.services.autoupdate = lib.mkIf config.c3d2.autoUpdate { wantedBy = [ "multi-user.target" ]; path = with pkgs; [ nix nettools curl jq ]; serviceConfig = { Type = "oneshot"; # switch-to-configuration may not return. HACK: cap running # time so that the timer can be scheduled again. TimeoutStartSec = "30min"; }; script = '' OLD=$(readlink /run/current-system) echo Current system: $(basename $OLD) NEW=$(curl -sLH "Accept: application/json" https://hydra.hq.c3d2.de/job/c3d2/nix-config/${config.networking.hostName}/latest | jq -er .buildoutputs.out.path) if [ -z "$NEW" ] || [ "$NEW" = "null" ]; then echo "Unable to obtain updated system" exit 1 fi echo New system: $(basename $NEW) if [ "$OLD" != "$NEW" ]; then echo "Fetching new system built by https://hydra.hq.c3d2.de/jobset/c3d2/nix-config" # this should fetch the new system from the binary cache nix copy --from https://nix-cache.hq.c3d2.de "$NEW" if [ -e "$NEW/etc/systemd/system/autoupdate.timer" ]; then echo "Switch to the new system..." nix-env -p /nix/var/nix/profiles/system --set $NEW "$NEW/bin/switch-to-configuration" switch else echo "New system is not yet autoupdate-enabled. Refusing to switch into a dead end." fi else echo "No update required" fi ''; # don't let the switch kill this service, aborting the switch restartIfChanged = false; unitConfig.X-StopOnRemoval = false; # create timer startAt = "hourly"; }; nix = { # Show a diff when activating a new system except for microvms which handle this seperately diffSystem = config.c3d2.deployment.server or "" == ""; gc = lib.mkIf config.c3d2.autoUpdate { automatic = true; randomizedDelaySec = "6h"; options = "--delete-older-than 21d"; }; }; environment.systemPackages = [ ( # Provide a manual updating script that fetches the latest # updated+built system from Hydra pkgs.writeScriptBin "update-from-hydra" '' #! ${pkgs.runtimeShell} -e OLD=$(readlink /run/current-system) echo Current system: $(basename $OLD) NEW=$(curl -sLH "Accept: application/json" https://hydra.hq.c3d2.de/job/c3d2/nix-config/${config.networking.hostName}/latest | ${pkgs.jq}/bin/jq -er .buildoutputs.out.path) if [ -z "$NEW" ] || [ "$NEW" = "null" ]; then echo "Unable to obtain updated system" exit 1 fi echo New system: $(basename $NEW) if [ "$OLD" != "$NEW" ]; then echo "Fetching new system built by https://hydra.hq.c3d2.de/jobset/c3d2/nix-config" # this should fetch the new system from the binary cache nix copy --from https://nix-cache.hq.c3d2.de "$NEW" echo "Switch to the new system..." nix-env -p /nix/var/nix/profiles/system --set $NEW "$NEW/bin/switch-to-configuration" switch else echo "No update required" fi '' ) ]; }; }