refactor mic/chroot.py
authorGui Chen <gui.chen@intel.com>
Wed, 7 Aug 2013 02:58:56 +0000 (22:58 -0400)
committerGui Chen <gui.chen@intel.com>
Tue, 13 Aug 2013 09:23:11 +0000 (05:23 -0400)
put inner function outside to be api of
the chroot module
correct logic in setup_chrootenv and
cleanup_chrootenv
remove unused dev_null code

Signed-off-by: Gui Chen <gui.chen@intel.com>
mic/bootstrap.py
mic/chroot.py

index 66c291b..c20af78 100644 (file)
@@ -253,7 +253,7 @@ class Bootstrap(object):
         gloablmounts = None
         try:
             proxy.set_proxy_environ()
-            gloablmounts = setup_chrootenv(rootdir, bindmounts, False)
+            gloablmounts = setup_chrootenv(rootdir, bindmounts)
             sync_timesetting(rootdir)
             sync_passwdfile(rootdir)
             retcode = subprocess.call(cmd, preexec_fn=mychroot, env=env, shell=shell)
index 99fb9a2..ef6b244 100644 (file)
@@ -24,6 +24,11 @@ from mic import msger
 from mic.conf import configmgr
 from mic.utils import misc, errors, runner, fs_related
 
+#####################################################################
+### GLOBAL CONSTANTS
+#####################################################################
+
+chroot_bindmounts = None
 chroot_lockfd = -1
 chroot_lock = ""
 BIND_MOUNTS = (
@@ -32,232 +37,190 @@ BIND_MOUNTS = (
                 "/sys",
                 "/dev",
                 "/dev/pts",
-                "/dev/shm",
                 "/var/lib/dbus",
                 "/var/run/dbus",
                 "/var/lock",
               )
 
-def cleanup_after_chroot(targettype,imgmount,tmpdir,tmpmnt):
-    if imgmount and targettype == "img":
-        imgmount.cleanup()
+#####################################################################
+### GLOBAL ROUTINE
+#####################################################################
 
-    if tmpdir:
-        shutil.rmtree(tmpdir, ignore_errors = True)
+def get_bindmounts(chrootdir, bindmounts):
+    global chroot_bindmounts
 
-    if tmpmnt:
-        shutil.rmtree(tmpmnt, ignore_errors = True)
+    if chroot_bindmounts:
+        return chroot_bindmounts
 
-def check_bind_mounts(chrootdir, bindmounts):
     chrootmounts = []
+    bindmounts = bindmounts or ""
+
     for mount in bindmounts.split(";"):
         if not mount:
             continue
 
         srcdst = mount.split(":")
+        srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
         if len(srcdst) == 1:
             srcdst.append("none")
 
-        if not os.path.isdir(srcdst[0]):
-            return False
+        # if some bindmount is not existed, but it's created inside
+        # chroot, this is not expected
+        if not os.path.exists(srcdst[0]):
+            os.makedirs(srcdst[0])
 
-        if srcdst[1] == "" or srcdst[1] == "none":
-            srcdst[1] = None
-
-        if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
+        if not os.path.isdir(srcdst[0]):
             continue
 
-        if chrootdir:
-            if not srcdst[1]:
-                srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[0]))
-            else:
-                srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
-
-            tmpdir = chrootdir + "/" + srcdst[1]
-            if os.path.isdir(tmpdir):
-                msger.warning("Warning: dir %s has existed."  % tmpdir)
-
-    return True
-
-def cleanup_mounts(chrootdir):
-    umountcmd = misc.find_binary_path("umount")
-    abs_chrootdir = os.path.abspath(chrootdir)
-    mounts = open('/proc/mounts').readlines()
-    for line in reversed(mounts):
-        if abs_chrootdir not in line:
+        if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
+            msger.verbose("%s will be mounted by default." % srcdst[0])
             continue
 
-        point = line.split()[1]
-
-        # '/' to avoid common name prefix
-        if abs_chrootdir == point or point.startswith(abs_chrootdir + '/'):
-            args = [ umountcmd, "-l", point ]
-            ret = runner.quiet(args)
-            if ret != 0:
-                msger.warning("failed to unmount %s" % point)
-
-    return 0
-
-def setup_chrootenv(chrootdir, bindmounts = None, mountparent = True):
-    global chroot_lockfd, chroot_lock
-
-    def get_bind_mounts(chrootdir, bindmounts, mountparent = True):
-        chrootmounts = []
-        if bindmounts in ("", None):
-            bindmounts = ""
-
-        for mount in bindmounts.split(";"):
-            if not mount:
-                continue
-
-            srcdst = mount.split(":")
-            srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
-            if len(srcdst) == 1:
-                srcdst.append("none")
-
-            # if some bindmount is not existed, but it's created inside
-            # chroot, this is not expected
-            if not os.path.exists(srcdst[0]):
-                os.makedirs(srcdst[0])
-
-            if not os.path.isdir(srcdst[0]):
-                continue
-
-            if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
-                msger.verbose("%s will be mounted by default." % srcdst[0])
-                continue
-
-            if srcdst[1] == "" or srcdst[1] == "none":
-                srcdst[1] = None
-            else:
-                srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
-                if os.path.isdir(chrootdir + "/" + srcdst[1]):
-                    msger.warning("%s has existed in %s , skip it."\
-                                  % (srcdst[1], chrootdir))
-                    continue
-
-            chrootmounts.append(fs_related.BindChrootMount(srcdst[0],
-                                                           chrootdir,
-                                                           srcdst[1]))
-
-        """Default bind mounts"""
-        for pt in BIND_MOUNTS:
-            if not os.path.exists(pt):
+        if srcdst[1] == "" or srcdst[1] == "none":
+            srcdst[1] = None
+        else:
+            srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
+            if os.path.isdir(chrootdir + "/" + srcdst[1]):
+                msger.warning("%s has existed in %s , skip it."\
+                              % (srcdst[1], chrootdir))
                 continue
-            chrootmounts.append(fs_related.BindChrootMount(pt,
-                                                           chrootdir,
-                                                           None))
-
-        if mountparent:
-            chrootmounts.append(fs_related.BindChrootMount("/",
-                                                           chrootdir,
-                                                           "/parentroot",
-                                                           "ro"))
-
-        for kernel in os.listdir("/lib/modules"):
-            chrootmounts.append(fs_related.BindChrootMount(
-                                                "/lib/modules/"+kernel,
-                                                chrootdir,
-                                                None,
-                                                "ro"))
-
-        return chrootmounts
-
-    def bind_mount(chrootmounts):
-        for b in chrootmounts:
-            msger.verbose("bind_mount: %s -> %s" % (b.src, b.dest))
-            b.mount()
-
-    def setup_resolv(chrootdir):
-        try:
-            shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
-        except:
-            pass
 
-    globalmounts = get_bind_mounts(chrootdir, bindmounts, mountparent)
-    bind_mount(globalmounts)
+        chrootmounts.append(fs_related.BindChrootMount(srcdst[0],
+                                                       chrootdir,
+                                                       srcdst[1]))
 
-    setup_resolv(chrootdir)
+    """Default bind mounts"""
+    for pt in BIND_MOUNTS:
+        if not os.path.exists(pt):
+            continue
+        chrootmounts.append(fs_related.BindChrootMount(pt,
+                                                       chrootdir,
+                                                       None))
+
+    for kernel in os.listdir("/lib/modules"):
+        chrootmounts.append(fs_related.BindChrootMount(
+                                            "/lib/modules/"+kernel,
+                                            chrootdir,
+                                            None,
+                                            "ro"))
+    chroot_bindmounts = chrootmounts
+    return chroot_bindmounts
+
+#####################################################################
+### SETUP CHROOT ENVIRONMENT
+#####################################################################
+
+def bind_mount(chrootmounts):
+    for b in chrootmounts:
+        msger.verbose("bind_mount: %s -> %s" % (b.src, b.dest))
+        b.mount()
+
+def setup_resolv(chrootdir):
+    try:
+        shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
+    except:
+        pass
 
+def setup_mtab(chrootdir):
     mtab = "/etc/mtab"
     dstmtab = chrootdir + mtab
     if not os.path.islink(dstmtab):
         shutil.copyfile(mtab, dstmtab)
 
+def setup_chrootenv(chrootdir, bindmounts = None):
+    # bind mounting
+    bind_mount(get_bindmounts(chrootdir, bindmounts))
+    # setup resolv.conf
+    setup_resolv(chrootdir)
+    # update /etc/mtab
+    setup_mtab(chrootdir)
+
+    # lock
     chroot_lock = os.path.join(chrootdir, ".chroot.lock")
     chroot_lockfd = open(chroot_lock, "w")
 
-    return globalmounts
+    return None
 
-def cleanup_chrootenv(chrootdir, bindmounts=None, globalmounts=()):
-    global chroot_lockfd, chroot_lock
+######################################################################
+### CLEANUP CHROOT ENVIRONMENT
+######################################################################
 
-    def bind_unmount(chrootmounts):
-        for b in reversed(chrootmounts):
-            msger.verbose("bind_unmount: %s -> %s" % (b.src, b.dest))
-            b.unmount()
+def bind_unmount(chrootmounts):
+    for b in reversed(chrootmounts):
+        msger.verbose("bind_unmount: %s -> %s" % (b.src, b.dest))
+        b.unmount()
 
-    def cleanup_resolv(chrootdir):
+def cleanup_resolv(chrootdir):
+    try:
+        fd = open(chrootdir + "/etc/resolv.conf", "w")
+        fd.truncate(0)
+        fd.close()
+    except:
+        pass
+
+def kill_processes(chrootdir):
+    import glob
+    for fp in glob.glob("/proc/*/root"):
         try:
-            fd = open(chrootdir + "/etc/resolv.conf", "w")
-            fd.truncate(0)
-            fd.close()
+            if os.readlink(fp) == chrootdir:
+                pid = int(fp.split("/")[2])
+                os.kill(pid, 9)
         except:
             pass
 
-    def kill_processes(chrootdir):
-        import glob
-        for fp in glob.glob("/proc/*/root"):
-            try:
-                if os.readlink(fp) == chrootdir:
-                    pid = int(fp.split("/")[2])
-                    os.kill(pid, 9)
-            except:
-                pass
-
-    def cleanup_mountdir(chrootdir, bindmounts):
-        if bindmounts == "" or bindmounts == None:
-            return
-        chrootmounts = []
-        for mount in bindmounts.split(";"):
-            if not mount:
-                continue
-
-            srcdst = mount.split(":")
-
-            if len(srcdst) == 1:
-                srcdst.append("none")
+def cleanup_mtab(chrootdir):
+    if os.path.exists(chrootdir + "/etc/mtab"):
+        os.unlink(chrootdir + "/etc/mtab")
 
-            if srcdst[0] == "/":
-                continue
+def cleanup_mounts(chrootdir):
+    umountcmd = misc.find_binary_path("umount")
+    mounts = open('/proc/mounts').readlines()
+    for line in reversed(mounts):
+        if chrootdir not in line:
+            continue
 
-            if srcdst[1] == "" or srcdst[1] == "none":
-                srcdst[1] = srcdst[0]
+        point = line.split()[1]
 
-            srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
-            tmpdir = chrootdir + "/" + srcdst[1]
-            if os.path.isdir(tmpdir):
-                if len(os.listdir(tmpdir)) == 0:
-                    shutil.rmtree(tmpdir, ignore_errors = True)
-                else:
-                    msger.warning("Warning: dir %s isn't empty." % tmpdir)
+        # '/' to avoid common name prefix
+        if chrootdir == point or point.startswith(chrootdir + '/'):
+            args = [ umountcmd, "-l", point ]
+            ret = runner.quiet(args)
+            if ret != 0:
+                msger.warning("failed to unmount %s" % point)
+            if os.path.isdir(point) and len(os.listdir(point)) == 0:
+                shutil.rmtree(point)
+            else:
+                msger.warning("%s is not directory or is not empty" % point)
 
+def cleanup_chrootenv(chrootdir, bindmounts=None, globalmounts=()):
+    # unlock
     chroot_lockfd.close()
-    bind_unmount(globalmounts)
-
-    if not fs_related.my_fuser(chroot_lock):
-        tmpdir = chrootdir + "/parentroot"
-        if os.path.exists(tmpdir) and len(os.listdir(tmpdir)) == 0:
-            shutil.rmtree(tmpdir, ignore_errors = True)
-
-        cleanup_resolv(chrootdir)
-
-        if os.path.exists(chrootdir + "/etc/mtab"):
-            os.unlink(chrootdir + "/etc/mtab")
+    # kill processes
+    kill_processes(chrootdir)
+    # clean mtab
+    cleanup_mtab(chrootdir)
+    # clean resolv.conf
+    cleanup_resolv(chrootdir)
+    # bind umounting
+    bind_unmount(get_bindmounts(chrootdir, bindmounts))
+    # clean up mounts
+    cleanup_mounts(chrootdir)
+
+    return None
+
+#####################################################################
+### CHROOT STUFF
+#####################################################################
+
+def cleanup_after_chroot(targettype, imgmount, tmpdir, tmpmnt):
+    if imgmount and targettype == "img":
+        imgmount.cleanup()
 
-        kill_processes(chrootdir)
+    if tmpdir:
+        shutil.rmtree(tmpdir, ignore_errors = True)
 
-    cleanup_mountdir(chrootdir, bindmounts)
+    if tmpmnt:
+        shutil.rmtree(tmpmnt, ignore_errors = True)
 
 def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
     def mychroot():
@@ -293,7 +256,6 @@ def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
         else:
             msger.warning(wrnmsg)
 
-    dev_null = os.open("/dev/null", os.O_WRONLY)
     files_to_check = ["/bin/bash", "/sbin/init"]
 
     architecture_found = False
@@ -322,7 +284,6 @@ def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
         if architecture_found:
             break
 
-    os.close(dev_null)
     if not architecture_found:
         raise errors.CreatorError("Failed to get architecture from any of the "
                                   "following files %s from chroot." \