From a23b5cc9f21df1bc3da8adc72b0054a35b5bae19 Mon Sep 17 00:00:00 2001 From: Gui Chen Date: Tue, 6 Aug 2013 22:58:56 -0400 Subject: [PATCH] refactor mic/chroot.py 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 --- mic/bootstrap.py | 2 +- mic/chroot.py | 321 ++++++++++++++++++++++++------------------------------- 2 files changed, 142 insertions(+), 181 deletions(-) diff --git a/mic/bootstrap.py b/mic/bootstrap.py index 66c291b..c20af78 100644 --- a/mic/bootstrap.py +++ b/mic/bootstrap.py @@ -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) diff --git a/mic/chroot.py b/mic/chroot.py index 99fb9a2..ef6b244 100644 --- a/mic/chroot.py +++ b/mic/chroot.py @@ -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." \ -- 2.7.4