{ config, lib, pkgs, ... }: { options.mj.services.deployerbot.main = with lib.types; { enable = lib.mkEnableOption "Enable system updater orchestrator"; deployDerivations = lib.mkOption { type = listOf str; }; deployIfPresent = lib.mkOption { type = listOf (submodule { options = { derivationTarget = lib.mkOption { type = str; }; pingTarget = lib.mkOption { type = str; }; }; }); default = [ ]; }; uidgid = lib.mkOption { type = int; }; repo = lib.mkOption { type = str; }; }; options.mj.services.deployerbot.follower = with lib.types; { enable = lib.mkEnableOption "Allow system to be deployed with deployerbot"; sshAllowSubnets = lib.mkOption { type = listOf str; }; publicKeys = lib.mkOption { type = listOf str; }; uidgid = lib.mkOption { type = int; }; }; config = lib.mkMerge [ ( let cfg = config.mj.services.deployerbot.main; in lib.mkIf cfg.enable { # TODO: git config --global user.email bot@jakstys.lt users.users.deployerbot-main = { description = "Deployerbot Main"; home = "/var/lib/deployerbot-main"; shell = "/bin/sh"; group = "deployerbot-main"; isSystemUser = true; createHome = true; uid = cfg.uidgid; }; users.groups.deployerbot-main.gid = cfg.uidgid; systemd.services.deployerbot = { description = "Update all known systems"; environment = { TZ = "UTC"; }; path = [ pkgs.git pkgs.openssh pkgs.nix ]; restartIfChanged = false; serviceConfig = { Type = "oneshot"; User = "deployerbot-main"; WorkingDirectory = config.users.users.deployerbot-main.home; LoadCredential = [ "ssh-key:/etc/ssh/ssh_host_ed25519_key" ]; }; script = let deployDerivationsStr = builtins.concatStringsSep " " cfg.deployDerivations; in '' set -xeuo pipefail export GIT_SSH_COMMAND="ssh -i ''${CREDENTIALS_DIRECTORY}/ssh-key" if [[ ! -d config ]]; then git clone ${cfg.repo} config cd config else cd config git fetch origin git reset --hard origin/main fi nix flake update --accept-flake-config --commit-lock-file # TODO --all-systems nix flake check --all-systems --accept-flake-config EXITCODE=0 ${pkgs.deploy-rs.deploy-rs}/bin/deploy \ --ssh-opts="-i ''${CREDENTIALS_DIRECTORY}/ssh-key" \ --ssh-user=deployerbot-follower \ --confirm-timeout 60 \ --skip-checks \ --targets ${deployDerivationsStr} -- \ --accept-flake-config || EXITCODE=1 if [[ $EXITCODE != 0 ]]; then exit $EXITCODE else git push origin main fi # Optional deployments ${lib.concatMapStringsSep "\n" (t: '' if ${pkgs.inetutils}/bin/ping -c 1 ${t.pingTarget}; then ${pkgs.deploy-rs.deploy-rs}/bin/deploy \ --ssh-opts="-i ''${CREDENTIALS_DIRECTORY}/ssh-key" \ --ssh-user=deployerbot-follower \ --confirm-timeout 60 \ --skip-checks \ --targets ${t.derivationTarget} -- \ --accept-flake-config || EXITCODE=1 fi '') cfg.deployIfPresent} exit $EXITCODE ''; }; systemd.timers.deployerbot = { description = "deployerbot-main timer"; wantedBy = [ "timers.target" ]; timerConfig.OnCalendar = "*-*-* 09:00:00 Europe/Vilnius"; }; mj.base.unitstatus.units = [ "deployerbot" ]; nix.settings.trusted-users = [ "deployerbot-main" ]; } ) ( let cfg = config.mj.services.deployerbot.follower; in lib.mkIf cfg.enable { users.users.deployerbot-follower = { description = "Deployerbot Follower"; home = "/var/lib/deployerbot-follower"; shell = "/bin/sh"; group = "deployerbot-follower"; extraGroups = [ "wheel" ]; isSystemUser = true; createHome = true; uid = cfg.uidgid; openssh.authorizedKeys.keys = map ( k: ''from="${builtins.concatStringsSep "," cfg.sshAllowSubnets}" '' + k ) cfg.publicKeys; }; users.groups.deployerbot-follower.gid = cfg.uidgid; nix.settings.trusted-users = [ "deployerbot-follower" ]; } ) ]; }