Hi Jelmer,
On Thu, Sep 01, 2022 at 03:51:19PM +0000, Jelmer Vernooij wrote:
> It would be great if piuparts supported root-less operation, ideally in a less
> complicated way than via podman+docker.
>
> Conversation in #debian-qa suggests the are various options for building on
> top of infrastructure that's provided by other packages, e.g. sbuild,
> autopkgtest or mmdebootstrap.
>
> <josch> Jelmer, h01ger: I'd second what helmut said. With mmdebstrap you get
> the equivalent of "lxc-usernsexec -- lxc-unshare -s 'MOUNT|PID|UTSNAME|IPC'
> -- /usr/sbin/chroot ./debian-rootfs /bin/bash" but without having to depend
> on lxc -- You can see a variant of this in the mmdebstrap man page where
> mmdebstrap is used as a wrapper of debootstrap to fix #829134. That way you
> can run debootstrap without
> needing root: mmdebstrap --variant=custom --mode=unshare --setup-hook='env
> container=lxc debootstrap unstable "$1"' - debian-debootstrap.tar
Yeah, I think we're 99% there.
piuparts has a --existing-chroot option. Unfortunately, it doesn't
exactly do what we need here. It uses the given directory as a template
and tries to copy it. That is bound to fail as mmdebstrap has kindly
mounted /sys and /proc and such. It would be nice if piuparts got some
--use-existing option that would make it just use that chroot directly.
--use-existing is relatively easy to implement. I'm attaching a patch
for your convenience. I'm not sure whether this is acceptable in
piuparts. I do find the flag, its semantics and its implementation quite
suboptimal. I'd prefer if you use it as inspiration rather than
solution.
So we're doing something like piuparts --existing-chroot=...
--use-existing and this is going to be our --customize-hook for
mmdebstrap. The whole thing is not entirely trivial to assemble, but
this is how it looks:
mmdebstrap \
--verbose \
--mode=unshare \
--variant=apt \
--customize-hook='mv $1/sbin/start-stop-daemon.REAL
$1/sbin/start-stop-daemon && ./piuparts --use-existing --existing-chroot=$1
.../somepackage.changes' \
sid \
/dev/null \
http://deb.debian.org/debian
I suppose the most tricky part is the one about start-stop-daemon. It's
mangled by mmdebstrap for historical reasons. It's a problem, because
piuparts runs debsums and debsums doesn't like that.
So I tried this with a simple package (e.g. buffer) and it passed
completely in an entirely unprivileged way without podman.
Helmut
--- /usr/sbin/piuparts 2021-10-14 15:23:26.000000000 +0200
+++ ./piuparts 2022-09-01 20:09:26.195314473 +0200
@@ -199,6 +199,7 @@
self.debfoster_options = None
self.docker_image = None
self.merged_usr = False
+ self.use_existing = False
# tests and checks
self.no_install_purge_test = False
self.no_upgrade_test = False
@@ -782,7 +783,8 @@
def create(self, temp_tgz=None):
"""Create a chroot according to user's wishes."""
self.panic_handler_id = do_on_panic(self.remove)
- if not settings.schroot and not settings.docker_image:
+ if (not settings.schroot and not settings.docker_image and
+ not (settings.existing_chroot and settings.use_existing)):
self.create_temp_dir()
if temp_tgz:
@@ -792,7 +794,10 @@
elif settings.lvm_volume:
self.setup_from_lvm(settings.lvm_volume)
elif settings.existing_chroot:
- self.setup_from_dir(settings.existing_chroot)
+ if settings.use_existing:
+ self.name = settings.existing_chroot
+ else:
+ self.setup_from_dir(settings.existing_chroot)
elif settings.schroot:
self.setup_from_schroot(settings.schroot)
elif settings.docker_image:
@@ -800,7 +805,8 @@
else:
self.setup_minimal_chroot()
- if not settings.schroot and not settings.docker_image:
+ if (not settings.schroot and not settings.docker_image and
+ not (settings.existing_chroot and settings.use_existing)):
self.mount_proc()
self.configure_chroot()
@@ -851,7 +857,8 @@
if settings.docker_image:
logging.debug("Destroy docker container '%s'" % self.docker_container)
run(['docker', 'rm', '-f', self.docker_container])
- if not settings.schroot and not settings.docker_image:
+ if (not settings.schroot and not settings.docker_image and
+ not (settings.existing_chroot and settings.use_existing)):
run(['rm', '-rf', '--one-file-system', self.name])
if os.path.exists(self.name):
create_file(os.path.join(self.name, ".piuparts.tmpdir"), "removal failed")
@@ -2761,6 +2768,8 @@
help="Use DIR as the contents of the initial " +
"chroot, instead of building a new one with " +
"debootstrap")
+ parser.add_option("--use-existing", default=False, action='store_true',
+ help="when combined with -e, use the chroot directly rather than copying it")
parser.add_option("--hard-link", default=False,
action='store_true',
@@ -3071,6 +3080,7 @@
settings.lvm_volume = opts.lvm_volume
settings.lvm_snapshot_size = opts.lvm_snapshot_size
settings.existing_chroot = opts.existing_chroot
+ settings.use_existing = opts.use_existing
settings.hard_link = opts.hard_link
settings.schroot = opts.schroot
settings.end_meta = opts.end_meta