diff options
| author | Gregor Kleen <gkleen@yggdrasil.li> | 2022-02-18 11:31:28 +0100 |
|---|---|---|
| committer | Gregor Kleen <gkleen@yggdrasil.li> | 2022-02-18 11:31:28 +0100 |
| commit | 29a65ee80c474b57f4fce974ff5040996220f77e (patch) | |
| tree | 11dcdc66fd15d27add320b7079b9b4addb563a09 /hosts/vidhar | |
| parent | 906594e63bbc28d6c0c354ab8dafa4a7b6042faf (diff) | |
| download | nixos-29a65ee80c474b57f4fce974ff5040996220f77e.tar nixos-29a65ee80c474b57f4fce974ff5040996220f77e.tar.gz nixos-29a65ee80c474b57f4fce974ff5040996220f77e.tar.bz2 nixos-29a65ee80c474b57f4fce974ff5040996220f77e.tar.xz nixos-29a65ee80c474b57f4fce974ff5040996220f77e.zip | |
vidhar: copy-borg: setuid
Diffstat (limited to 'hosts/vidhar')
| -rwxr-xr-x | hosts/vidhar/borg/copy.py | 25 | ||||
| -rw-r--r-- | hosts/vidhar/borg/default.nix | 19 |
2 files changed, 28 insertions, 16 deletions
diff --git a/hosts/vidhar/borg/copy.py b/hosts/vidhar/borg/copy.py index 0f39b495..1efeaef4 100755 --- a/hosts/vidhar/borg/copy.py +++ b/hosts/vidhar/borg/copy.py | |||
| @@ -21,6 +21,8 @@ from xdg import xdg_runtime_dir | |||
| 21 | import pathlib | 21 | import pathlib |
| 22 | 22 | ||
| 23 | import unshare | 23 | import unshare |
| 24 | from pyprctl import cap_permitted, cap_inheritable, cap_effective, cap_ambient, Cap | ||
| 25 | from pwd import getpwnam | ||
| 24 | 26 | ||
| 25 | import signal | 27 | import signal |
| 26 | from time import sleep | 28 | from time import sleep |
| @@ -41,10 +43,20 @@ halo_args = { | |||
| 41 | 'spinner': 'arc' | 43 | 'spinner': 'arc' |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 46 | borg_pwd = getpwnam('borg') | ||
| 47 | |||
| 48 | def as_borg(caps=set()): | ||
| 49 | if caps: | ||
| 50 | for capset in [cap_permitted, cap_inheritable, cap_effective, cap_ambient]: | ||
| 51 | capset.add(*caps) | ||
| 52 | |||
| 53 | os.setuid(borg_pwd.pw_uid) | ||
| 54 | os.setgid(borg_pwd.pw_gid) | ||
| 55 | |||
| 44 | def read_repo(path): | 56 | def read_repo(path): |
| 45 | with Halo(text=f'Listing {path}', **halo_args) as sp: | 57 | with Halo(text=f'Listing {path}', **halo_args) as sp: |
| 46 | res = None | 58 | res = None |
| 47 | with subprocess.Popen(['borg', 'list', '--info', '--lock-wait=600', '--json', path], stdout=subprocess.PIPE) as proc: | 59 | with subprocess.Popen(['borg', 'list', '--info', '--lock-wait=600', '--json', path], stdout=subprocess.PIPE, preexec_fn=lambda: as_borg()) as proc: |
| 48 | res = json.load(proc.stdout)['archives'] | 60 | res = json.load(proc.stdout)['archives'] |
| 49 | if sp.enabled: | 61 | if sp.enabled: |
| 50 | sp.succeed(f'{len(res)} archives in {path}') | 62 | sp.succeed(f'{len(res)} archives in {path}') |
| @@ -83,7 +95,7 @@ def copy_archive(src_repo_path, dst_repo_path, entry): | |||
| 83 | match = re.compile('^(.*)-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.(checkpoint|recreate)(\.[0-9]+)?)?').fullmatch(entry['name']) | 95 | match = re.compile('^(.*)-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.(checkpoint|recreate)(\.[0-9]+)?)?').fullmatch(entry['name']) |
| 84 | if match: | 96 | if match: |
| 85 | repo_id = None | 97 | repo_id = None |
| 86 | with subprocess.Popen(['borg', 'info', '--info', '--lock-wait=600', '--json', src_repo_path], stdout=subprocess.PIPE) as proc: | 98 | with subprocess.Popen(['borg', 'info', '--info', '--lock-wait=600', '--json', src_repo_path], stdout=subprocess.PIPE, preexec_fn=lambda: as_borg()) as proc: |
| 87 | repo_id = json.load(proc.stdout)['repository']['id'] | 99 | repo_id = json.load(proc.stdout)['repository']['id'] |
| 88 | if repo_id: | 100 | if repo_id: |
| 89 | cache_suffix = f'{repo_id}_{match.group(1)}' | 101 | cache_suffix = f'{repo_id}_{match.group(1)}' |
| @@ -119,11 +131,12 @@ def copy_archive(src_repo_path, dst_repo_path, entry): | |||
| 119 | os.chroot(chroot) | 131 | os.chroot(chroot) |
| 120 | os.chdir('/') | 132 | os.chdir('/') |
| 121 | dir = pathlib.Path('/borg') | 133 | dir = pathlib.Path('/borg') |
| 122 | dir.mkdir(parents=True,exist_ok=True) | 134 | dir.mkdir(parents=True,exist_ok=True,mode=750) |
| 135 | os.chown(dir, borg_pwd.pw_uid, borg_pwd.pw_gid) | ||
| 123 | with Halo(text=f'Determine size', **halo_args) as sp: | 136 | with Halo(text=f'Determine size', **halo_args) as sp: |
| 124 | total_size = None | 137 | total_size = None |
| 125 | total_files = None | 138 | total_files = None |
| 126 | with subprocess.Popen(['borg', 'info', '--info', '--json', '--lock-wait=600', f'{src_repo_path}::{entry["name"]}'], stdout=subprocess.PIPE, text=True) as proc: | 139 | with subprocess.Popen(['borg', 'info', '--info', '--json', '--lock-wait=600', f'{src_repo_path}::{entry["name"]}'], stdout=subprocess.PIPE, text=True, preexec_fn=lambda: as_borg()) as proc: |
| 127 | stats = json.load(proc.stdout)['archives'][0]['stats'] | 140 | stats = json.load(proc.stdout)['archives'][0]['stats'] |
| 128 | total_size = stats['original_size'] | 141 | total_size = stats['original_size'] |
| 129 | total_files = stats['nfiles'] | 142 | total_files = stats['nfiles'] |
| @@ -132,7 +145,7 @@ def copy_archive(src_repo_path, dst_repo_path, entry): | |||
| 132 | else: | 145 | else: |
| 133 | print(f'{total_files} files, {naturalsize(total_size, binary=True)}', file=stderr) | 146 | print(f'{total_files} files, {naturalsize(total_size, binary=True)}', file=stderr) |
| 134 | # print(f'Mounting to {dir}', file=stderr) | 147 | # print(f'Mounting to {dir}', file=stderr) |
| 135 | with subprocess.Popen(['borg', 'mount', '--foreground', '--progress', '--lock-wait=600', f'{src_repo_path}::{entry["name"]}', dir]) as mount_proc: | 148 | with subprocess.Popen(['borg', 'mount', '--foreground', '--progress', '--lock-wait=600', f'{src_repo_path}::{entry["name"]}', dir], preexec_fn=lambda: as_borg()) as mount_proc: |
| 136 | with Halo(text='Waiting for mount', **halo_args) as sp: | 149 | with Halo(text='Waiting for mount', **halo_args) as sp: |
| 137 | wait_start = datetime.now() | 150 | wait_start = datetime.now() |
| 138 | while True: | 151 | while True: |
| @@ -173,7 +186,7 @@ def copy_archive(src_repo_path, dst_repo_path, entry): | |||
| 173 | else: | 186 | else: |
| 174 | create_args += ['--files-cache=disabled'] | 187 | create_args += ['--files-cache=disabled'] |
| 175 | create_args += [f'{dst_repo_path}::{entry["name"]}', '.'] | 188 | create_args += [f'{dst_repo_path}::{entry["name"]}', '.'] |
| 176 | with subprocess.Popen(create_args, cwd=dir, stdin=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True, env=env) as proc: | 189 | with subprocess.Popen(create_args, cwd=dir, stdin=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True, env=env, preexec_fn=lambda: as_borg(caps={Cap.DAC_READ_SEARCH})) as proc: |
| 177 | last_list = None | 190 | last_list = None |
| 178 | last_list_time = None | 191 | last_list_time = None |
| 179 | for line in proc.stderr: | 192 | for line in proc.stderr: |
diff --git a/hosts/vidhar/borg/default.nix b/hosts/vidhar/borg/default.nix index c404001b..37cdba8c 100644 --- a/hosts/vidhar/borg/default.nix +++ b/hosts/vidhar/borg/default.nix | |||
| @@ -45,9 +45,8 @@ let | |||
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | copyBorg = pkgs.stdenv.mkDerivation (let | 47 | copyBorg = pkgs.stdenv.mkDerivation (let |
| 48 | # packageOverrides = pkgs.callPackage ./pyprctl-packages.nix {}; | 48 | packageOverrides = pkgs.callPackage ./pyprctl-packages.nix {}; |
| 49 | # inpPython = pkgs.python39.override { inherit packageOverrides; }; | 49 | inpPython = pkgs.python39.override { inherit packageOverrides; }; |
| 50 | inpPython = pkgs.python39; | ||
| 51 | in rec { | 50 | in rec { |
| 52 | name = "copy"; | 51 | name = "copy"; |
| 53 | src = ./copy.py; | 52 | src = ./copy.py; |
| @@ -56,7 +55,7 @@ let | |||
| 56 | 55 | ||
| 57 | buildInputs = with pkgs; [makeWrapper]; | 56 | buildInputs = with pkgs; [makeWrapper]; |
| 58 | 57 | ||
| 59 | python = inpPython.withPackages (ps: with ps; [humanize tqdm dateutil xdg python-unshare halo]); | 58 | python = inpPython.withPackages (ps: with ps; [humanize tqdm dateutil xdg python-unshare pyprctl halo]); |
| 60 | 59 | ||
| 61 | buildPhase = '' | 60 | buildPhase = '' |
| 62 | substitute $src copy \ | 61 | substitute $src copy \ |
| @@ -111,12 +110,12 @@ in { | |||
| 111 | 110 | ||
| 112 | systemd.services = listToAttrs (map copyService [{ repo = "/srv/backup/borg/jotnar"; repoEscaped = "srv-backup-borg-jotnar"; }]); | 111 | systemd.services = listToAttrs (map copyService [{ repo = "/srv/backup/borg/jotnar"; repoEscaped = "srv-backup-borg-jotnar"; }]); |
| 113 | 112 | ||
| 114 | systemd.timers."copy-borg@srv-backup-borg-jotnar" = { | 113 | # systemd.timers."copy-borg@srv-backup-borg-jotnar" = { |
| 115 | wantedBy = ["multi-user.target"]; | 114 | # wantedBy = ["multi-user.target"]; |
| 116 | 115 | ||
| 117 | timerConfig = { | 116 | # timerConfig = { |
| 118 | OnCalendar = "*-*-* 00/4:00:00 Europe/Berlin"; | 117 | # OnCalendar = "*-*-* 00/4:00:00 Europe/Berlin"; |
| 119 | }; | 118 | # }; |
| 120 | }; | 119 | # }; |
| 121 | }; | 120 | }; |
| 122 | } | 121 | } |
