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

Reply via email to