X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/94fed7dabe521ca18aa9aaa47f22d744b05ee8cc..ddc1de7c566450adda92e30a814e792d5beb22a7:/lib/hypervisor/hv_fake.py diff --git a/lib/hypervisor/hv_fake.py b/lib/hypervisor/hv_fake.py index bf4a654..d2cd9a5 100644 --- a/lib/hypervisor/hv_fake.py +++ b/lib/hypervisor/hv_fake.py @@ -30,6 +30,7 @@ import logging from ganeti import utils from ganeti import constants from ganeti import errors +from ganeti import objects from ganeti.hypervisor import hv_base @@ -40,12 +41,13 @@ class FakeHypervisor(hv_base.BaseHypervisor): a real virtualisation software installed. """ - _ROOT_DIR = constants.RUN_DIR + "/ganeti-fake-hypervisor" + CAN_MIGRATE = True + + _ROOT_DIR = constants.RUN_GANETI_DIR + "/fake-hypervisor" def __init__(self): hv_base.BaseHypervisor.__init__(self) - if not os.path.exists(self._ROOT_DIR): - os.mkdir(self._ROOT_DIR) + utils.EnsureDirs([(self._ROOT_DIR, constants.RUN_DIRS_MODE)]) def ListInstances(self): """Get the list of running instances. @@ -61,7 +63,7 @@ class FakeHypervisor(hv_base.BaseHypervisor): @return: tuple of (name, id, memory, vcpus, stat, times) """ - file_name = "%s/%s" % (self._ROOT_DIR, instance_name) + file_name = self._InstanceFile(instance_name) if not os.path.exists(file_name): return None try: @@ -88,7 +90,7 @@ class FakeHypervisor(hv_base.BaseHypervisor): data = [] for file_name in os.listdir(self._ROOT_DIR): try: - fh = open(self._ROOT_DIR + "/" + file_name, "r") + fh = open(utils.PathJoin(self._ROOT_DIR, file_name), "r") inst_id = "-1" memory = 0 vcpus = 1 @@ -107,12 +109,12 @@ class FakeHypervisor(hv_base.BaseHypervisor): raise errors.HypervisorError("Failed to list instances: %s" % err) return data - - def _InstanceFile(self, instance_name): + @classmethod + def _InstanceFile(cls, instance_name): """Compute the instance file for an instance name. """ - return self._ROOT_DIR + "/%s" % instance_name + return utils.PathJoin(cls._ROOT_DIR, instance_name) def _IsAlive(self, instance_name): """Checks if an instance is alive. @@ -121,7 +123,7 @@ class FakeHypervisor(hv_base.BaseHypervisor): file_name = self._InstanceFile(instance_name) return os.path.exists(file_name) - def _MarkUp(self, instance): + def _MarkUp(self, instance, memory): """Mark the instance as running. This does no checks, which should be done by its callers. @@ -131,21 +133,21 @@ class FakeHypervisor(hv_base.BaseHypervisor): fh = file(file_name, "w") try: fh.write("0\n%d\n%d\n" % - (instance.beparams[constants.BE_MEMORY], + (memory, instance.beparams[constants.BE_VCPUS])) finally: fh.close() - def _MarkDown(self, instance): + def _MarkDown(self, instance_name): """Mark the instance as running. This does no checks, which should be done by its callers. """ - file_name = self._InstanceFile(instance.name) + file_name = self._InstanceFile(instance_name) utils.RemoveFile(file_name) - def StartInstance(self, instance, block_devices): + def StartInstance(self, instance, block_devices, startup_paused): """Start an instance. For the fake hypervisor, it just creates a file in the base dir, @@ -157,22 +159,24 @@ class FakeHypervisor(hv_base.BaseHypervisor): raise errors.HypervisorError("Failed to start instance %s: %s" % (instance.name, "already running")) try: - self._MarkUp(instance) + self._MarkUp(instance, self._InstanceStartupMemory(instance)) except IOError, err: raise errors.HypervisorError("Failed to start instance %s: %s" % (instance.name, err)) - def StopInstance(self, instance, force=False, retry=False): + def StopInstance(self, instance, force=False, retry=False, name=None): """Stop an instance. For the fake hypervisor, this just removes the file in the base dir, if it exist, otherwise we raise an exception. """ - if not self._IsAlive(instance.name): + if name is None: + name = instance.name + if not self._IsAlive(name): raise errors.HypervisorError("Failed to stop instance %s: %s" % - (instance.name, "not running")) - self._MarkDown(instance) + (name, "not running")) + self._MarkDown(name) def RebootInstance(self, instance): """Reboot an instance. @@ -182,6 +186,24 @@ class FakeHypervisor(hv_base.BaseHypervisor): """ return + def BalloonInstanceMemory(self, instance, mem): + """Balloon an instance memory to a certain value. + + @type instance: L{objects.Instance} + @param instance: instance to be accepted + @type mem: int + @param mem: actual memory size to use for instance runtime + + """ + if not self._IsAlive(instance.name): + raise errors.HypervisorError("Failed to balloon memory for %s: %s" % + (instance.name, "not running")) + try: + self._MarkUp(instance, mem) + except EnvironmentError, err: + raise errors.HypervisorError("Failed to balloon memory for %s: %s" % + (instance.name, utils.ErrnoOrStr(err))) + def GetNodeInfo(self): """Return information about the node. @@ -196,16 +218,19 @@ class FakeHypervisor(hv_base.BaseHypervisor): result = self.GetLinuxNodeInfo() # substract running instances all_instances = self.GetAllInstancesInfo() - result['memory_free'] -= min(result['memory_free'], + result["memory_free"] -= min(result["memory_free"], sum([row[2] for row in all_instances])) return result @classmethod - def GetShellCommandForConsole(cls, instance, hvparams, beparams): - """Return a command for connecting to the console of an instance. + def GetInstanceConsole(cls, instance, hvparams, beparams): + """Return information for connecting to the console of an instance. """ - return "echo Console not available for fake hypervisor" + return objects.InstanceConsole(instance=instance.name, + kind=constants.CONS_MESSAGE, + message=("Console not available for fake" + " hypervisor")) def Verify(self): """Verify the hypervisor. @@ -241,7 +266,7 @@ class FakeHypervisor(hv_base.BaseHypervisor): def MigrateInstance(self, instance, target, live): """Migrate an instance. - @type instance: L{object.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 @@ -252,19 +277,62 @@ class FakeHypervisor(hv_base.BaseHypervisor): logging.debug("Fake hypervisor migrating %s to %s (live=%s)", instance, target, live) - self._MarkDown(instance) - - def FinalizeMigration(self, instance, info, success): - """Finalize an instance migration. + def FinalizeMigrationDst(self, instance, info, success): + """Finalize the instance migration on the target node. For the fake hv, this just marks the instance up. @type instance: L{objects.Instance} @param instance: instance whose migration is being finalized + @type info: string/data (opaque) + @param info: migration information, from the source node + @type success: boolean + @param success: whether the migration was a success or a failure """ if success: - self._MarkUp(instance) + self._MarkUp(instance, self._InstanceStartupMemory(instance)) else: # ensure it's down - self._MarkDown(instance) + self._MarkDown(instance.name) + + def PostMigrationCleanup(self, instance): + """Clean-up after a migration. + + To be executed on the source node. + + @type instance: L{objects.Instance} + @param instance: the instance that was migrated + + """ + pass + + def FinalizeMigrationSource(self, instance, success, live): + """Finalize the instance migration on the source node. + + @type instance: L{objects.Instance} + @param instance: the instance that was migrated + @type success: bool + @param success: whether the migration succeeded or not + @type live: bool + @param live: whether the user requested a live migration or not + + """ + # pylint: disable=W0613 + if success: + self._MarkDown(instance.name) + + def GetMigrationStatus(self, instance): + """Get the migration status + + The fake hypervisor migration always succeeds. + + @type instance: L{objects.Instance} + @param instance: the instance that is being migrated + @rtype: L{objects.MigrationStatus} + @return: the status of the current migration (one of + L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional + progress info that can be retrieved from the hypervisor + + """ + return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)