diff options
author | Anton Khirnov <anton@khirnov.net> | 2020-10-20 11:18:45 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2020-10-20 11:18:45 +0200 |
commit | 1a6e05e609b1ef45bdde97fcaf3944fc2824fd40 (patch) | |
tree | 506c1f7e61a1c165a9f023e3b67f292fd643a723 /lbup | |
parent | 5ea14e4a132788472205f66be68ad1540ad56243 (diff) |
TargetSSHLXCLVM: factor creating+mounting the snapshot
Make it into its own context manager, similar to TargetSSHLVM. This is
easier to follow and will allow to share more code in the future.
Diffstat (limited to 'lbup')
-rw-r--r-- | lbup/targets.py | 55 |
1 files changed, 31 insertions, 24 deletions
diff --git a/lbup/targets.py b/lbup/targets.py index 8b90188..7f85526 100644 --- a/lbup/targets.py +++ b/lbup/targets.py @@ -396,6 +396,32 @@ class TargetSSHLXCLVM(TargetSSHLVM): return "%s{LXC:%s/%s@[%s]}{LVM:%s}" % (super().__str__(), self._lxc_containername, self._lxc_username, str(self._parent_remote), self._snapshot_size) + @contextlib.contextmanager + def _nsmount_snapshot(self, ssh, devnum, mount_path, container_pid, fstype): + """ + Return a context manager that creates a read-only LVM snapshot + for the specified LV device number and mounts it at mount_path + inside the container, then unmounts and destroys it at exit. + """ + with self._snapshot_lv(ssh, devnum) as lv_path: + # we cannot trust any binaries located inside the container, since a + # compromised container could use them to execute arbitrary code + # with real root privileges, thus nullifying the point of + # unprivileged containers) + # so we ship a special tool, 'nsmount', which has to be + # installed on the parent, to mount the snapshot into the + # container mount namespace + self._paramiko_exec_cmd(ssh, + 'nsmount m {pid} {mount_path} {lv_path} {fstype}'.format( + pid = container_pid, mount_path = mount_path, + lv_path = lv_path, fstype = fstype)) + try: + yield None + finally: + self._paramiko_exec_cmd(ssh, + 'nsmount u {pid} {mount_path}'.format( + pid = container_pid, mount_path = mount_path)) + def save(self, dry_run = False): with contextlib.ExitStack() as stack: parent = stack.enter_context(_ssh_client.SSHConnection(self._parent_remote)) @@ -433,33 +459,14 @@ class TargetSSHLXCLVM(TargetSSHLVM): self._logger.debug('Backup targets are at device %s(%s), mounted at %s', "%d:%d" % (lv_devnum >> 8, lv_devnum & 255), lv_fstype, lv_mountpoint) - snapshot_path = stack.enter_context(self._snapshot_lv(parent, lv_devnum)) + stack.enter_context(self._nsmount_snapshot(parent, lv_devnum, container_mountpoint, + container_pid, lv_fstype)) # execute the backup - - # we cannot trust any binaries located inside the container, since a - # compromised container could use them to execute arbitrary code - # with real root privileges, thus nullifying the point of - # unprivileged containers) - # so we ship a special tool, 'nsmount', which has to be - # installed on the parent, to mount the snapshot into the - # container mount namespace - self._paramiko_exec_cmd(parent, - 'nsmount m {pid} {mountpoint} {devpath} {fstype}'.format( - pid = container_pid, mountpoint = container_mountpoint, - devpath = snapshot_path, fstype = lv_fstype)) - bup_exec = ['bup', 'on', '%s@%s' % (self._remote.username, self._remote.host), '-d', container_bupdir] save_opts = ['--graft=%s=%s' % (container_mountpoint, lv_mountpoint)] reparent = (lv_mountpoint, AbsPath(container_mountpoint)) - try: - ret = self._do_save(bup_exec, dry_run, - reparent = reparent, - save_opts = save_opts, index_opts = ['--no-check-device']) - finally: - self._paramiko_exec_cmd(parent, - 'nsmount u {pid} {mountpoint}'.format( - pid = container_pid, mountpoint = container_mountpoint)) - - return ret + return self._do_save(bup_exec, dry_run, + reparent = reparent, + save_opts = save_opts, index_opts = ['--no-check-device']) |