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