[Piuparts-commits] [piuparts] 01/07: Add docker support, new param is introduced `--docker-image`

Holger Levsen holger at layer-acht.org
Tue Mar 27 14:44:25 UTC 2018


This is an automated email from the git hooks/post-receive script.

holger pushed a commit to branch develop
in repository piuparts.

commit 49729386a5c943831a058dd1785ae508beec914f
Author: Agustin Henze <tin at aayy.com.ar>
Date:   Wed Mar 21 16:54:50 2018 -0300

    Add docker support, new param is introduced `--docker-image`
    
    e.g. piuparts --docker-image debian:unstable package.deb
    
    It only supports overlay2 for now and it uses the `MergedDir` layer
    where piuparts can access, add, edit and remove files easily.
    
    Signed-off-by: Agustin Henze <tin at aayy.com.ar>
---
 piuparts.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 59 insertions(+), 6 deletions(-)

diff --git a/piuparts.py b/piuparts.py
index 3daba79..e12910d 100644
--- a/piuparts.py
+++ b/piuparts.py
@@ -47,6 +47,7 @@ import os
 import tarfile
 import stat
 import re
+import json
 import pickle
 import subprocess
 import traceback
@@ -191,6 +192,7 @@ class Settings:
         self.skip_minimize = True
         self.minimize = False
         self.debfoster_options = None
+        self.docker_image = None
         # tests and checks
         self.no_install_purge_test = False
         self.no_upgrade_test = False
@@ -769,7 +771,7 @@ class Chroot:
     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:
+        if not settings.schroot and not settings.docker_image:
             self.create_temp_dir()
 
         if temp_tgz:
@@ -782,10 +784,12 @@ class Chroot:
             self.setup_from_dir(settings.existing_chroot)
         elif settings.schroot:
             self.setup_from_schroot(settings.schroot)
+        elif settings.docker_image:
+            self.setup_from_docker(settings.docker_image)
         else:
             self.setup_minimal_chroot()
 
-        if not settings.schroot:
+        if not settings.schroot and not settings.docker_image:
             self.mount_proc()
         self.configure_chroot()
 
@@ -807,7 +811,7 @@ class Chroot:
         self.run_scripts("post_chroot_unpack")
 
         self.run(["apt-get", "update"])
-        if settings.basetgz or settings.schroot or settings.existing_chroot:
+        if settings.basetgz or settings.docker_image or settings.schroot or settings.existing_chroot:
             self.run(["apt-get", "-yf", "dist-upgrade"])
         self.minimize()
         self.remember_available_md5()
@@ -832,7 +836,10 @@ class Chroot:
             if settings.schroot:
                 logging.debug("Terminate schroot session '%s'" % self.name)
                 run(['schroot', '--end-session', '--chroot', "session:" + self.schroot_session])
-            if not settings.schroot:
+            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:
                 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")
@@ -840,6 +847,8 @@ class Chroot:
         elif settings.keep_tmpdir:
             if settings.schroot:
                 logging.debug("Keeping schroot session %s at %s" % (self.schroot_session, self.name))
+            elif settings.docker_image:
+                logging.debug("Keeping container %s" % self.docker_container)
             else:
                 logging.debug("Keeping directory tree at %s" % self.name)
         dont_do_on_panic(self.panic_handler_id)
@@ -892,6 +901,25 @@ class Chroot:
         self.name = output.strip()
         logging.info("New schroot session in '%s'" % self.name)
 
+    @staticmethod
+    def check_if_docker_storage_driver_is_supported():
+        ret_code, output = run(['docker', 'info'])
+        if 'overlay2' not in output:
+            logging.error('Only overlay2 storage driver is supported')
+            panic()
+
+    def setup_from_docker(self, docker_image):
+        self.check_if_docker_storage_driver_is_supported()
+        ret_code, output = run(['docker', 'run', '-d', '-it', docker_image, 'bash'])
+        if ret_code != 0:
+            logging.error("Couldn't start the container from '%s'" % docker_image)
+            panic()
+        self.docker_container = output.strip()
+        ret_code, output = run(['docker', 'inspect', self.docker_container])
+        container_data = json.loads(output)[0]
+        self.name = container_data['GraphDriver']['Data']['MergedDir']
+        logging.info("New container created '%s'" % self.docker_container)
+
     def setup_from_lvm(self, lvm_volume):
         """Create a chroot by creating an LVM snapshot."""
         self.lvm_base = os.path.dirname(lvm_volume)
@@ -938,6 +966,12 @@ class Chroot:
                 ["schroot", "--preserve-environment", "--run-session", "--chroot", "session:" +
                     self.schroot_session, "--directory", "/", "-u", "root", "--"] + prefix + command,
                    ignore_errors=ignore_errors, timeout=settings.max_command_runtime)
+        elif settings.docker_image:
+            return run(
+                ['docker', 'exec', self.docker_container,] + prefix + command,
+                ignore_errors=ignore_errors,
+                timeout=settings.max_command_runtime,
+            )
         else:
             return run(["chroot", self.name] + prefix + command,
                        ignore_errors=ignore_errors, timeout=settings.max_command_runtime)
@@ -1042,6 +1076,9 @@ class Chroot:
 
     def create_resolv_conf(self):
         """Update resolv.conf based on the current configuration in the host system. Strip comments and whitespace."""
+        if settings.docker_image:
+            # Docker takes care of this
+            return
         full_name = self.relative("etc/resolv.conf")
         resolvconf = ""
         with open("/etc/resolv.conf", "r") as f:
@@ -1379,6 +1416,9 @@ class Chroot:
                     'broken-symlink',
             ]
             ignored_tags = []
+            if not os.path.exists(self.name + '/dev/null'):
+                device = os.makedev(1, 3)
+                os.mknod(self.name + '/dev/null', 0o666, device)
             (status, output) = run(["adequate", "--root", self.name] + packages, ignore_errors=True)
             for tag in ignored_tags:
                 # ignore some tags
@@ -1624,8 +1664,12 @@ class Chroot:
 
     def check_for_no_processes(self, fail=None):
         """Check there are no processes running inside the chroot."""
-        (status, output) = run(["lsof", "-w", "+D", self.name], ignore_errors=True)
-        count = len(output.split("\n")) - 1
+        if settings.docker_image:
+            (status, output) = run(["docker", "top", self.docker_container])
+            count = len(output.strip().split("\n")) - 2 # header + bash launched on container creation
+        else:
+            (status, output) = run(["lsof", "-w", "+D", self.name], ignore_errors=True)
+            count = len(output.split("\n")) - 1
         if count > 0:
             if fail is None:
                 fail = not settings.allow_database
@@ -1637,6 +1681,9 @@ class Chroot:
 
     def terminate_running_processes(self):
         """Terminate all processes running in the chroot."""
+        if settings.docker_image:
+            # Docker takes care of this
+            return
         seen = []
         while True:
             p = subprocess.Popen(["lsof", "-t", "+D", self.name],
@@ -2726,6 +2773,11 @@ def parse_command_line():
                       help="Use schroot session named SCHROOT-NAME for the chroot, instead of building " +
                            "a new one with debootstrap.")
 
+    parser.add_option("--docker-image", metavar="DOCKER-IMAGE", action="store",
+                      help="Use a container created from the docker image "
+                      "DOCKER-IMAGE for the testing environment, instead of "
+                      "building a new one with debootstrap.")
+
     parser.add_option("-m", "--mirror", action="append", metavar="URL",
                       default=[],
                       help="Which Debian mirror to use.")
@@ -2948,6 +3000,7 @@ def parse_command_line():
     if settings.minimize:
         settings.skip_minimize = False
     settings.debfoster_options = opts.debfoster_options.split()
+    settings.docker_image = opts.docker_image
     # tests and checks
     settings.no_install_purge_test = opts.no_install_purge_test
     settings.no_upgrade_test = opts.no_upgrade_test

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/piuparts/piuparts.git



More information about the Piuparts-commits mailing list