create path needed for restic local backups
This commit is contained in:
parent
10dea06ec1
commit
5e076ebcf4
2 changed files with 177 additions and 3 deletions
|
@ -206,6 +206,16 @@ in
|
|||
{
|
||||
environment.systemPackages = lib.optionals (enabledInstances != {}) [ pkgs.restic ];
|
||||
|
||||
systemd.tmpfiles.rules =
|
||||
let
|
||||
mkRepositorySettings = name: instance: repository: lib.optionals (lib.hasPrefix "/" repository.path) [
|
||||
"d '${repository.path}' 0750 ${instance.user} ${instance.group} - -"
|
||||
];
|
||||
|
||||
mkSettings = name: instance: builtins.map (mkRepositorySettings name instance) instance.repositories;
|
||||
in
|
||||
lib.flatten (lib.attrsets.mapAttrsToList mkSettings enabledInstances);
|
||||
|
||||
services.restic.backups =
|
||||
let
|
||||
mkRepositorySettings = name: instance: repository: {
|
||||
|
|
|
@ -10,7 +10,7 @@ let
|
|||
];
|
||||
in
|
||||
{
|
||||
backupAndRestore = pkgs.testers.runNixOSTest {
|
||||
backupAndRestoreRoot = pkgs.testers.runNixOSTest {
|
||||
name = "restic_backupAndRestore";
|
||||
|
||||
nodes.machine = {
|
||||
|
@ -106,8 +106,172 @@ in
|
|||
machine.succeed("""
|
||||
mkdir -p /opt/files/A
|
||||
mkdir -p /opt/files/B
|
||||
mkdir -p /opt/repos/A
|
||||
mkdir -p /opt/repos/B
|
||||
|
||||
echo repoA_fileA_1 > /opt/files/A/fileA
|
||||
echo repoA_fileB_1 > /opt/files/A/fileB
|
||||
echo repoB_fileA_1 > /opt/files/B/fileA
|
||||
echo repoB_fileB_1 > /opt/files/B/fileB
|
||||
|
||||
# chown :backup -R /opt/files
|
||||
""")
|
||||
|
||||
assert_files("/opt/files", {
|
||||
'/opt/files/B/fileA': 'repoB_fileA_1',
|
||||
'/opt/files/B/fileB': 'repoB_fileB_1',
|
||||
'/opt/files/A/fileA': 'repoA_fileA_1',
|
||||
'/opt/files/A/fileB': 'repoA_fileB_1',
|
||||
})
|
||||
|
||||
with subtest("First backup in repo A"):
|
||||
machine.succeed("systemctl start restic-backups-testinstance_opt_repos_A")
|
||||
|
||||
with subtest("New content"):
|
||||
machine.succeed("""
|
||||
echo repoA_fileA_2 > /opt/files/A/fileA
|
||||
echo repoA_fileB_2 > /opt/files/A/fileB
|
||||
echo repoB_fileA_2 > /opt/files/B/fileA
|
||||
echo repoB_fileB_2 > /opt/files/B/fileB
|
||||
""")
|
||||
|
||||
assert_files("/opt/files", {
|
||||
'/opt/files/B/fileA': 'repoB_fileA_2',
|
||||
'/opt/files/B/fileB': 'repoB_fileB_2',
|
||||
'/opt/files/A/fileA': 'repoA_fileA_2',
|
||||
'/opt/files/A/fileB': 'repoA_fileB_2',
|
||||
})
|
||||
|
||||
with subtest("Second backup in repo B"):
|
||||
machine.succeed("systemctl start restic-backups-testinstance_opt_repos_B")
|
||||
|
||||
with subtest("Delete content"):
|
||||
machine.succeed("""
|
||||
rm -r /opt/files/A /opt/files/B
|
||||
""")
|
||||
|
||||
assert_files("/opt/files", {})
|
||||
|
||||
with subtest("Restore initial content from repo A"):
|
||||
machine.succeed("""
|
||||
restic-testinstance_opt_repos_A restore latest -t /
|
||||
""")
|
||||
|
||||
assert_files("/opt/files", {
|
||||
'/opt/files/B/fileA': 'repoB_fileA_1',
|
||||
'/opt/files/B/fileB': 'repoB_fileB_1',
|
||||
'/opt/files/A/fileA': 'repoA_fileA_1',
|
||||
'/opt/files/A/fileB': 'repoA_fileB_1',
|
||||
})
|
||||
|
||||
with subtest("Restore initial content from repo B"):
|
||||
machine.succeed("""
|
||||
restic-testinstance_opt_repos_B restore latest -t /
|
||||
""")
|
||||
|
||||
assert_files("/opt/files", {
|
||||
'/opt/files/B/fileA': 'repoB_fileA_2',
|
||||
'/opt/files/B/fileB': 'repoB_fileB_2',
|
||||
'/opt/files/A/fileA': 'repoA_fileA_2',
|
||||
'/opt/files/A/fileB': 'repoA_fileB_2',
|
||||
})
|
||||
'';
|
||||
};
|
||||
|
||||
backupAndRestoreUser = pkgs.testers.runNixOSTest {
|
||||
name = "restic_backupAndRestore";
|
||||
|
||||
nodes.machine = {
|
||||
imports = ( testLib.baseImports pkgs' ) ++ [
|
||||
../../modules/blocks/restic.nix
|
||||
];
|
||||
|
||||
shb.restic = {
|
||||
user = "backup";
|
||||
group = "backup";
|
||||
};
|
||||
shb.restic.instances."testinstance" = {
|
||||
enable = true;
|
||||
|
||||
passphraseFile = pkgs.writeText "passphrase" "PassPhrase";
|
||||
|
||||
sourceDirectories = [
|
||||
"/opt/files/A"
|
||||
"/opt/files/B"
|
||||
];
|
||||
|
||||
repositories = [
|
||||
{
|
||||
path = "/opt/repos/A";
|
||||
timerConfig = {
|
||||
OnCalendar = "00:00:00";
|
||||
RandomizedDelaySec = "5h";
|
||||
};
|
||||
# Those are not needed by the repository but are still included
|
||||
# so we can test them in the hooks section.
|
||||
secrets = {
|
||||
A.source = pkgs.writeText "A" "secretA";
|
||||
B.source = pkgs.writeText "B" "secretB";
|
||||
};
|
||||
}
|
||||
{
|
||||
path = "/opt/repos/B";
|
||||
timerConfig = {
|
||||
OnCalendar = "00:00:00";
|
||||
RandomizedDelaySec = "5h";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
hooks.before_backup = [''
|
||||
echo $RUNTIME_DIRECTORY
|
||||
if [ "$RUNTIME_DIRECTORY" = /run/restic-backups-testinstance_opt_repos_A ]; then
|
||||
if ! [ -f /run/secrets/restic/restic-backups-testinstance_opt_repos_A ]; then
|
||||
exit 10
|
||||
fi
|
||||
if [ -z "$A" ] || ! [ "$A" = "secretA" ]; then
|
||||
echo "A:$A"
|
||||
exit 11
|
||||
fi
|
||||
if [ -z "$B" ] || ! [ "$B" = "secretB" ]; then
|
||||
echo "A:$A"
|
||||
exit 12
|
||||
fi
|
||||
fi
|
||||
''];
|
||||
};
|
||||
};
|
||||
|
||||
extraPythonPackages = p: [ p.dictdiffer ];
|
||||
skipTypeCheck = true;
|
||||
|
||||
testScript = { nodes, ... }: let
|
||||
instanceCfg = nodes.machine.shb.restic.instances."testinstance";
|
||||
in ''
|
||||
from dictdiffer import diff
|
||||
|
||||
def list_files(dir):
|
||||
files_and_content = {}
|
||||
|
||||
files = machine.succeed(f"""
|
||||
find {dir} -type f
|
||||
""").split("\n")[:-1]
|
||||
|
||||
for f in files:
|
||||
content = machine.succeed(f"""
|
||||
cat {f}
|
||||
""").strip()
|
||||
files_and_content[f] = content
|
||||
|
||||
return files_and_content
|
||||
|
||||
def assert_files(dir, files):
|
||||
result = list(diff(list_files(dir), files))
|
||||
if len(result) > 0:
|
||||
raise Exception("Unexpected files:", result)
|
||||
|
||||
with subtest("Create initial content"):
|
||||
machine.succeed("""
|
||||
mkdir -p /opt/files/A
|
||||
mkdir -p /opt/files/B
|
||||
|
||||
echo repoA_fileA_1 > /opt/files/A/fileA
|
||||
echo repoA_fileB_1 > /opt/files/A/fileB
|
||||
|
|
Loading…
Add table
Reference in a new issue