X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/bb3776b4b5f9a8caf80ddb2a8eaf21242c336603..31155d60eed6d14d25979c41c031f746e51d3c7d:/lib/objects.py diff --git a/lib/objects.py b/lib/objects.py index c92ea3f..be6f2d7 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -340,6 +340,21 @@ class ConfigData(ConfigObject): obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance) return obj + def HasAnyDiskOfType(self, dev_type): + """Check if in there is at disk of the given type in the configuration. + + @type dev_type: L{constants.LDS_BLOCK} + @param dev_type: the type to look for + @rtype: boolean + @return: boolean indicating if a disk of the given type was found or not + + """ + for instance in self.instances.values(): + for disk in instance.disks: + if disk.IsBasedOnDiskType(dev_type): + return True + return False + def UpgradeConfig(self): """Fill defaults for missing configuration values. @@ -349,6 +364,12 @@ class ConfigData(ConfigObject): node.UpgradeConfig() for instance in self.instances.values(): instance.UpgradeConfig() + if self.cluster.drbd_usermode_helper is None: + # To decide if we set an helper let's check if at least one instance has + # a DRBD disk. This does not cover all the possible scenarios but it + # gives a good approximation. + if self.HasAnyDiskOfType(constants.LD_DRBD8): + self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER class NIC(ConfigObject): @@ -383,7 +404,8 @@ class NIC(ConfigObject): self.nicparams[constants.NIC_MODE] = constants.NIC_MODE_BRIDGED self.nicparams[constants.NIC_LINK] = self.bridge # bridge is no longer used it 2.1. The slot is left there to support - # upgrading, but will be removed in 2.2 + # upgrading, but can be removed once upgrades to the current version + # straight from 2.0 are deprecated. if self.bridge is not None: self.bridge = None @@ -436,6 +458,21 @@ class Disk(ConfigObject): return 0 return -1 + def IsBasedOnDiskType(self, dev_type): + """Check if the disk or its children are based on the given type. + + @type dev_type: L{constants.LDS_BLOCK} + @param dev_type: the type to look for + @rtype: boolean + @return: boolean indicating if a device of the given type was found or not + + """ + if self.children: + for child in self.children: + if child.IsBasedOnDiskType(dev_type): + return True + return self.dev_type == dev_type + def GetNodes(self, node): """This function returns the nodes this device lives on. @@ -498,7 +535,7 @@ class Disk(ConfigObject): actual algorithms from bdev. """ - if self.dev_type == constants.LD_LV: + if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE: self.size += amount elif self.dev_type == constants.LD_DRBD8: if self.children: @@ -657,6 +694,7 @@ class Instance(TaggableObject): "hypervisor", "hvparams", "beparams", + "osparams", "admin_up", "nics", "disks", @@ -812,10 +850,18 @@ class Instance(TaggableObject): del self.hvparams[key] except KeyError: pass + if self.osparams is None: + self.osparams = {} class OS(ConfigObject): - """Config object representing an operating system.""" + """Config object representing an operating system. + + @type supported_parameters: list + @ivar supported_parameters: a list of tuples, name and description, + containing the supported parameters by this OS + + """ __slots__ = [ "name", "path", @@ -824,7 +870,9 @@ class OS(ConfigObject): "export_script", "import_script", "rename_script", + "verify_script", "supported_variants", + "supported_parameters", ] @@ -850,6 +898,7 @@ class Cluster(TaggableObject): "tcpudp_port_pool", "mac_prefix", "volume_group_name", + "drbd_usermode_helper", "default_bridge", "default_hypervisor", "master_node", @@ -861,10 +910,14 @@ class Cluster(TaggableObject): "hvparams", "os_hvp", "beparams", + "osparams", "nicparams", "candidate_pool_size", "modify_etc_hosts", "modify_ssh_setup", + "maintain_node_health", + "uid_pool", + "default_iallocator", ] + _TIMESTAMPS + _UUID def UpgradeConfig(self): @@ -880,10 +933,13 @@ class Cluster(TaggableObject): self.hvparams[hypervisor] = FillDict( constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor]) - # TODO: Figure out if it's better to put this into OS than Cluster if self.os_hvp is None: self.os_hvp = {} + # osparams added before 2.2 + if self.osparams is None: + self.osparams = {} + self.beparams = UpgradeGroupedParams(self.beparams, constants.BEC_DEFAULTS) migrate_default_bridge = not self.nicparams @@ -900,17 +956,29 @@ class Cluster(TaggableObject): self.modify_ssh_setup = True # default_bridge is no longer used it 2.1. The slot is left there to - # support auto-upgrading, but will be removed in 2.2 + # support auto-upgrading. It can be removed once we decide to deprecate + # upgrading straight from 2.0. if self.default_bridge is not None: self.default_bridge = None - # default_hypervisor is just the first enabled one in 2.1 + # default_hypervisor is just the first enabled one in 2.1. This slot and + # code can be removed once upgrading straight from 2.0 is deprecated. if self.default_hypervisor is not None: self.enabled_hypervisors = ([self.default_hypervisor] + [hvname for hvname in self.enabled_hypervisors if hvname != self.default_hypervisor]) self.default_hypervisor = None + # maintain_node_health added after 2.1.1 + if self.maintain_node_health is None: + self.maintain_node_health = False + + if self.uid_pool is None: + self.uid_pool = [] + + if self.default_iallocator is None: + self.default_iallocator = "" + def ToDict(self): """Custom function for cluster. @@ -929,16 +997,41 @@ class Cluster(TaggableObject): obj.tcpudp_port_pool = set(obj.tcpudp_port_pool) return obj - def FillHV(self, instance, skip_globals=False): - """Fill an instance's hvparams dict. + def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None): + """Get the default hypervisor parameters for the cluster. - @type instance: L{objects.Instance} - @param instance: the instance parameter to fill + @param hypervisor: the hypervisor name + @param os_name: if specified, we'll also update the defaults for this OS + @param skip_keys: if passed, list of keys not to use + @return: the defaults dict + + """ + if skip_keys is None: + skip_keys = [] + + fill_stack = [self.hvparams.get(hypervisor, {})] + if os_name is not None: + os_hvp = self.os_hvp.get(os_name, {}).get(hypervisor, {}) + fill_stack.append(os_hvp) + + ret_dict = {} + for o_dict in fill_stack: + ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys) + + return ret_dict + + def SimpleFillHV(self, hv_name, os_name, hvparams, skip_globals=False): + """Fill a given hvparams dict with cluster defaults. + + @type hv_name: string + @param hv_name: the hypervisor to use + @type os_name: string + @param os_name: the OS to use for overriding the hypervisor defaults @type skip_globals: boolean @param skip_globals: if True, the global hypervisor parameters will not be filled @rtype: dict - @return: a copy of the instance's hvparams with missing keys filled from + @return: a copy of the given hvparams with missing keys filled from the cluster defaults """ @@ -947,21 +1040,39 @@ class Cluster(TaggableObject): else: skip_keys = [] - # We fill the list from least to most important override - fill_stack = [ - self.hvparams.get(instance.hypervisor, {}), - self.os_hvp.get(instance.os, {}).get(instance.hypervisor, {}), - instance.hvparams, - ] + def_dict = self.GetHVDefaults(hv_name, os_name, skip_keys=skip_keys) + return FillDict(def_dict, hvparams, skip_keys=skip_keys) - ret_dict = {} - for o_dict in fill_stack: - ret_dict = FillDict(ret_dict, o_dict, skip_keys=skip_keys) + def FillHV(self, instance, skip_globals=False): + """Fill an instance's hvparams dict with cluster defaults. - return ret_dict + @type instance: L{objects.Instance} + @param instance: the instance parameter to fill + @type skip_globals: boolean + @param skip_globals: if True, the global hypervisor parameters will + not be filled + @rtype: dict + @return: a copy of the instance's hvparams with missing keys filled from + the cluster defaults + + """ + return self.SimpleFillHV(instance.hypervisor, instance.os, + instance.hvparams, skip_globals) + + def SimpleFillBE(self, beparams): + """Fill a given beparams dict with cluster defaults. + + @type beparams: dict + @param beparams: the dict to fill + @rtype: dict + @return: a copy of the passed in beparams with missing keys filled + from the cluster defaults + + """ + return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), beparams) def FillBE(self, instance): - """Fill an instance's beparams dict. + """Fill an instance's beparams dict with cluster defaults. @type instance: L{objects.Instance} @param instance: the instance parameter to fill @@ -970,8 +1081,39 @@ class Cluster(TaggableObject): the cluster defaults """ - return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), - instance.beparams) + return self.SimpleFillBE(instance.beparams) + + def SimpleFillNIC(self, nicparams): + """Fill a given nicparams dict with cluster defaults. + + @type nicparams: dict + @param nicparams: the dict to fill + @rtype: dict + @return: a copy of the passed in nicparams with missing keys filled + from the cluster defaults + + """ + return FillDict(self.nicparams.get(constants.PP_DEFAULT, {}), nicparams) + + def SimpleFillOS(self, os_name, os_params): + """Fill an instance's osparams dict with cluster defaults. + + @type os_name: string + @param os_name: the OS name to use + @type os_params: dict + @param os_params: the dict to fill with default values + @rtype: dict + @return: a copy of the instance's osparams with missing keys filled from + the cluster defaults + + """ + name_only = os_name.split("+", 1)[0] + # base OS + result = self.osparams.get(name_only, {}) + # OS with variant + result = FillDict(result, self.osparams.get(os_name, {})) + # specified params + return FillDict(result, os_params) class BlockDevStatus(ConfigObject): @@ -987,6 +1129,38 @@ class BlockDevStatus(ConfigObject): ] +class ImportExportStatus(ConfigObject): + """Config object representing the status of an import or export.""" + __slots__ = [ + "recent_output", + "listen_port", + "connected", + "progress_mbytes", + "progress_throughput", + "progress_eta", + "progress_percent", + "exit_status", + "error_message", + ] + _TIMESTAMPS + + +class ImportExportOptions(ConfigObject): + """Options for import/export daemon + + @ivar key_name: X509 key name (None for cluster certificate) + @ivar ca_pem: Remote peer CA in PEM format (None for cluster certificate) + @ivar compress: Compression method (one of L{constants.IEC_ALL}) + @ivar magic: Used to ensure the connection goes to the right disk + + """ + __slots__ = [ + "key_name", + "ca_pem", + "compress", + "magic", + ] + + class ConfdRequest(ConfigObject): """Object holding a confd request. @@ -1035,10 +1209,10 @@ class SerializableConfigParser(ConfigParser.SafeConfigParser): self.write(buf) return buf.getvalue() - @staticmethod - def Loads(data): + @classmethod + def Loads(cls, data): """Load data from a string.""" buf = StringIO(data) - cfp = SerializableConfigParser() + cfp = cls() cfp.readfp(buf) return cfp