tywin: enable git backups
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing

This commit is contained in:
Jake Hillion 2023-07-02 22:43:53 +01:00
parent e8c2001eb4
commit 25a49899af
6 changed files with 119 additions and 1 deletions

View File

@ -43,6 +43,17 @@
fileSystems."/mnt/d0".options = [ "x-systemd.mount-timeout=3m" ]; fileSystems."/mnt/d0".options = [ "x-systemd.mount-timeout=3m" ];
## Backups
### Git
age.secrets."git/git_backups_ecdsa".file = ../../secrets/git/git_backups_ecdsa.age;
age.secrets."git/git_backups_remotes".file = ../../secrets/git/git_backups_remotes.age;
custom.backups.git = {
enable = true;
sshKey = config.age.secrets."git/git_backups_ecdsa".path;
reposFile = config.age.secrets."git/git_backups_remotes".path;
repos = [ "https://gitea.hillion.co.uk/JakeHillion/nixos.git" ];
};
## Resilio ## Resilio
custom.resilio.enable = true; custom.resilio.enable = true;
@ -107,6 +118,7 @@
}; };
pruneOpts = [ pruneOpts = [
"--keep-last 48"
"--keep-within-hourly 7d" "--keep-within-hourly 7d"
"--keep-within-daily 1m" "--keep-within-daily 1m"
"--keep-within-weekly 6m" "--keep-within-weekly 6m"

View File

@ -2,6 +2,7 @@
{ {
imports = [ imports = [
./git.nix
./matrix.nix ./matrix.nix
]; ];
} }

102
modules/backups/git.nix Normal file
View File

@ -0,0 +1,102 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.backups.git;
in
{
options.custom.backups.git = {
enable = lib.mkEnableOption "git";
repos = lib.mkOption {
description = "A list of remotes to clone.";
type = with lib.types; listOf str;
default = [ ];
};
reposFile = lib.mkOption {
description = "A file containing the remotes to clone, one per line.";
type = with lib.types; nullOr str;
default = null;
};
sshKey = lib.mkOption {
description = "SSH private key to use when cloning repositories over SSH.";
type = with lib.types; nullOr str;
default = null;
};
};
config = lib.mkIf cfg.enable {
age.secrets."git-backups/restic/128G".file = ../../secrets/restic/128G.age;
systemd.services.backup-git = {
description = "Git repo backup service.";
serviceConfig = {
DynamicUser = true;
CacheDirectory = "backup-git";
WorkingDirectory = "%C/backup-git";
LoadCredential = [
"restic_password:${config.age.secrets."git-backups/restic/128G".path}"
] ++ (if cfg.sshKey == null then [ ] else [ "id_ecdsa:${cfg.sshKey}" ])
++ (if cfg.reposFile == null then [ ] else [ "repos_file:${cfg.reposFile}" ]);
};
environment = {
GIT_SSH_COMMAND = "${pkgs.openssh}/bin/ssh -i %d/id_ecdsa";
RESTIC_PASSWORD_FILE = "%d/restic_password";
};
script = ''
shopt -s nullglob
# Read and deduplicate repos
${if cfg.reposFile == null then "" else "readarray -t raw_repos < $CREDENTIALS_DIRECTORY/repos_file"}
declare -A repos=(${builtins.concatStringsSep " " (builtins.map (x : "[${x}]=1") cfg.repos)})
for repo in ''${raw_repos[@]}; do repos[$repo]=1; done
# Clean up existing repos
declare -A dirs
for d in *; do
origin=$(cd $d && ${pkgs.git}/bin/git remote get-url origin)
if ! [ -n "''${repos[$origin]}" ]; then
echo "$origin removed from config, cleaning up..."
rm -rf $d
else
dirs[$origin]=$d
fi
done
# Update repos
EXIT_CODE=0
for repo in "''${!repos[@]}"; do
if [ -n "''${dirs[$repo]}" ]; then
if ! (cd ''${dirs[$repo]} && ${pkgs.git}/bin/git remote update); then EXIT_CODE=1; fi
else
if ! (${pkgs.git}/bin/git clone --mirror $repo); then EXIT_CODE=1; fi
fi
done
# Backup to Restic
${pkgs.restic}/bin/restic \
-r rest:http://restic.tywin.storage.ts.hillion.co.uk/128G \
--cache-dir .restic --exclude .restic \
backup .
if test $EXIT_CODE -ne 0; then
echo "Some repositories failed to clone!"
exit $EXIT_CODE
fi
'';
};
systemd.timers.backup-git = {
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnUnitInactiveSec = "15m";
RandomizedDelaySec = "5m";
Unit = "backup-git.service";
};
};
};
}

Binary file not shown.

Binary file not shown.

View File

@ -62,11 +62,14 @@ in
# Backblaze Secrets # Backblaze Secrets
"backblaze/vm-strangervm-backups-matrix.age".publicKeys = jake_users ++ [ ts.strangervm.vm ]; "backblaze/vm-strangervm-backups-matrix.age".publicKeys = jake_users ++ [ ts.strangervm.vm ];
# Restic Secrets # Backups Secrets
"restic/b2-backups-matrix.age".publicKeys = jake_users ++ [ ts.strangervm.vm ]; "restic/b2-backups-matrix.age".publicKeys = jake_users ++ [ ts.strangervm.vm ];
"restic/128G.age".publicKeys = jake_users ++ [ ts.storage.tywin ]; "restic/128G.age".publicKeys = jake_users ++ [ ts.storage.tywin ];
"restic/1.6T.age".publicKeys = jake_users ++ [ ts.storage.tywin ]; "restic/1.6T.age".publicKeys = jake_users ++ [ ts.storage.tywin ];
"git/git_backups_ecdsa.age".publicKeys = jake_users ++ [ ts.storage.tywin ];
"git/git_backups_remotes.age".publicKeys = jake_users ++ [ ts.storage.tywin ];
# Spotify Secrets # Spotify Secrets
"spotify/11132032266.age".publicKeys = jake_users ++ [ ts.terminals.jakehillion.gendry ]; "spotify/11132032266.age".publicKeys = jake_users ++ [ ts.terminals.jakehillion.gendry ];