X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/d73ef63f22f47eebb11d56bb0ddbe4bb4bf0fcbb..5ef5cfeaf308498f7ee3195fcc55e3a853359ab5:/lib/hypervisor/hv_chroot.py diff --git a/lib/hypervisor/hv_chroot.py b/lib/hypervisor/hv_chroot.py index 2ff41cd..e9f2317 100644 --- a/lib/hypervisor/hv_chroot.py +++ b/lib/hypervisor/hv_chroot.py @@ -27,10 +27,9 @@ import os import os.path import time import logging -from cStringIO import StringIO from ganeti import constants -from ganeti import errors +from ganeti import errors # pylint: disable-msg=W0611 from ganeti import utils from ganeti.hypervisor import hv_base from ganeti.errors import HypervisorError @@ -68,11 +67,7 @@ class ChrootManager(hv_base.BaseHypervisor): def __init__(self): hv_base.BaseHypervisor.__init__(self) - if not os.path.exists(self._ROOT_DIR): - os.mkdir(self._ROOT_DIR) - if not os.path.isdir(self._ROOT_DIR): - raise HypervisorError("Needed path %s is not a directory" % - self._ROOT_DIR) + utils.EnsureDirs([(self._ROOT_DIR, constants.RUN_DIRS_MODE)]) @staticmethod def _IsDirLive(path): @@ -97,7 +92,7 @@ class ChrootManager(hv_base.BaseHypervisor): fh = open("/proc/mounts", "r") try: for line in fh: - fstype, mountpoint, rest = line.split(" ", 2) + _, mountpoint, _ = line.split(" ", 2) if (mountpoint.startswith(path) and mountpoint != path): data.append(mountpoint) @@ -106,12 +101,19 @@ class ChrootManager(hv_base.BaseHypervisor): data.sort(key=lambda x: x.count("/"), reverse=True) return data + @classmethod + def _InstanceDir(cls, instance_name): + """Return the root directory for an instance. + + """ + return utils.PathJoin(cls._ROOT_DIR, instance_name) + def ListInstances(self): """Get the list of running instances. """ return [name for name in os.listdir(self._ROOT_DIR) - if self._IsDirLive(os.path.join(self._ROOT_DIR, name))] + if self._IsDirLive(utils.PathJoin(self._ROOT_DIR, name))] def GetInstanceInfo(self, instance_name): """Get instance properties. @@ -122,7 +124,7 @@ class ChrootManager(hv_base.BaseHypervisor): @return: (name, id, memory, vcpus, stat, times) """ - dir_name = "%s/%s" % (self._ROOT_DIR, instance_name) + dir_name = self._InstanceDir(instance_name) if not self._IsDirLive(dir_name): raise HypervisorError("Instance %s is not running" % instance_name) return (instance_name, 0, 0, 0, 0, 0) @@ -135,7 +137,7 @@ class ChrootManager(hv_base.BaseHypervisor): """ data = [] for file_name in os.listdir(self._ROOT_DIR): - path = os.path.join(self._ROOT_DIR, file_name) + path = utils.PathJoin(self._ROOT_DIR, file_name) if self._IsDirLive(path): data.append((file_name, 0, 0, 0, 0, 0)) return data @@ -147,7 +149,7 @@ class ChrootManager(hv_base.BaseHypervisor): execute '/ganeti-chroot start'. """ - root_dir = "%s/%s" % (self._ROOT_DIR, instance.name) + root_dir = self._InstanceDir(instance.name) if not os.path.exists(root_dir): try: os.mkdir(root_dir) @@ -171,7 +173,7 @@ class ChrootManager(hv_base.BaseHypervisor): raise HypervisorError("Can't run the chroot start script: %s" % result.output) - def StopInstance(self, instance, force=False): + def StopInstance(self, instance, force=False, retry=False, name=None): """Stop an instance. This method has complicated cleanup tests, as we must: @@ -180,41 +182,54 @@ class ChrootManager(hv_base.BaseHypervisor): - finally unmount the instance dir """ - root_dir = "%s/%s" % (self._ROOT_DIR, instance.name) - if not os.path.exists(root_dir): + if name is None: + name = instance.name + + root_dir = self._InstanceDir(name) + if not os.path.exists(root_dir) or not self._IsDirLive(root_dir): return - if self._IsDirLive(root_dir): + # Run the chroot stop script only once + if not retry and not force: result = utils.RunCmd(["chroot", root_dir, "/ganeti-chroot", "stop"]) if result.failed: raise HypervisorError("Can't run the chroot stop script: %s" % result.output) - retry = 20 - while not force and self._IsDirLive(root_dir) and retry > 0: - time.sleep(1) - retry -= 1 - if retry < 10: - result = utils.RunCmd(["fuser", "-k", "-TERM", "-m", root_dir]) - retry = 5 - while force and self._IsDirLive(root_dir) and retry > 0: - time.sleep(1) - retry -= 1 - utils.RunCmd(["fuser", "-k", "-KILL", "-m", root_dir]) - if self._IsDirLive(root_dir): + + if not force: + utils.RunCmd(["fuser", "-k", "-TERM", "-m", root_dir]) + else: + utils.RunCmd(["fuser", "-k", "-KILL", "-m", root_dir]) + # 2 seconds at most should be enough for KILL to take action + time.sleep(2) + + if self._IsDirLive(root_dir): + if force: raise HypervisorError("Can't stop the processes using the chroot") + return + + def CleanupInstance(self, instance_name): + """Cleanup after a stopped instance + + """ + root_dir = self._InstanceDir(instance_name) + + if not os.path.exists(root_dir): + return + + if self._IsDirLive(root_dir): + raise HypervisorError("Processes are still using the chroot") + for mpath in self._GetMountSubdirs(root_dir): utils.RunCmd(["umount", mpath]) - retry = 10 - while retry > 0: - result = utils.RunCmd(["umount", root_dir]) - if not result.failed: - break - retry -= 1 - time.sleep(1) + + result = utils.RunCmd(["umount", root_dir]) if result.failed: - logging.error("Processes still alive in the chroot: %s", - utils.RunCmd("fuser -vm %s" % root_dir).output) - raise HypervisorError("Can't umount the chroot dir: %s" % result.output) + msg = ("Processes still alive in the chroot: %s" % + utils.RunCmd("fuser -vm %s" % root_dir).output) + logging.error(msg) + raise HypervisorError("Can't umount the chroot dir: %s (%s)" % + (result.output, msg)) def RebootInstance(self, instance): """Reboot an instance. @@ -243,7 +258,7 @@ class ChrootManager(hv_base.BaseHypervisor): """Return a command for connecting to the console of an instance. """ - root_dir = "%s/%s" % (cls._ROOT_DIR, instance.name) + root_dir = cls._InstanceDir(instance.name) if not os.path.ismount(root_dir): raise HypervisorError("Instance %s is not running" % instance.name) @@ -257,3 +272,23 @@ class ChrootManager(hv_base.BaseHypervisor): """ if not os.path.exists(self._ROOT_DIR): return "The required directory '%s' does not exist." % self._ROOT_DIR + + @classmethod + def PowercycleNode(cls): + """Chroot powercycle, just a wrapper over Linux powercycle. + + """ + cls.LinuxPowercycle() + + def MigrateInstance(self, instance, target, live): + """Migrate an instance. + + @type instance: L{objects.Instance} + @param instance: the instance to be migrated + @type target: string + @param target: hostname (usually ip) of the target node + @type live: boolean + @param live: whether to do a live or non-live migration + + """ + raise HypervisorError("Migration not supported by the chroot hypervisor")