X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/ffa1c0dc146c9929b7baf7f2d3b18f9e0144fcbf..96acbc09b70c82051e2156744bf1ae6752004cb7:/lib/objects.py?ds=sidebyside diff --git a/lib/objects.py b/lib/objects.py index a26907d..1cdc98f 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -29,6 +29,7 @@ pass to and from external parties. import ConfigParser import re +import copy from cStringIO import StringIO from ganeti import errors @@ -36,7 +37,40 @@ from ganeti import constants __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance", - "OS", "Node", "Cluster"] + "OS", "Node", "Cluster", "FillDict"] + + +def FillDict(defaults_dict, custom_dict): + """Basic function to apply settings on top a default dict. + + @type defaults_dict: dict + @param defaults_dict: dictionary holding the default values + @type custom_dict: dict + @param custom_dict: dictionary holding customized value + @rtype: dict + @return: dict with the 'full' values + + """ + ret_dict = copy.deepcopy(defaults_dict) + ret_dict.update(custom_dict) + return ret_dict + + +def UpgradeGroupedParams(target, defaults): + """Update all groups for the target parameter. + + @type target: dict of dicts + @param target: {group: {parameter: value}} + @type defaults: dict + @param defaults: default parameter values + + """ + if target is None: + target = {constants.PP_DEFAULT: defaults} + else: + for group in target: + target[group] = FillDict(defaults, target[group]) + return target class ConfigObject(object): @@ -49,7 +83,7 @@ class ConfigObject(object): as None instead of raising an error Classes derived from this must always declare __slots__ (we use many - config objects and the memory reduction is useful. + config objects and the memory reduction is useful) """ __slots__ = [] @@ -57,6 +91,7 @@ class ConfigObject(object): def __init__(self, **kwargs): for k, v in kwargs.iteritems(): setattr(self, k, v) + self.UpgradeConfig() def __getattr__(self, name): if name not in self.__slots__: @@ -156,6 +191,15 @@ class ConfigObject(object): """Implement __repr__ for ConfigObjects.""" return repr(self.ToDict()) + def UpgradeConfig(self): + """Fill defaults for missing configuration values. + + This method will be called at object init time, and its implementation will + be object dependent. + + """ + pass + class TaggableObject(ConfigObject): """An generic class supporting tags. @@ -178,7 +222,7 @@ class TaggableObject(ConfigObject): constants.MAX_TAG_LEN) if not tag: raise errors.TagError("Tags cannot be empty") - if not re.match("^[ \w.+*/:-]+$", tag): + if not re.match("^[\w.+*/:-]+$", tag): raise errors.TagError("Tag contains invalid characters") def GetTags(self): @@ -237,7 +281,7 @@ class TaggableObject(ConfigObject): class ConfigData(ConfigObject): """Top-level config object.""" - __slots__ = ["cluster", "nodes", "instances"] + __slots__ = ["version", "cluster", "nodes", "instances", "serial_no"] def ToDict(self): """Custom function for top-level config data. @@ -267,13 +311,45 @@ class ConfigData(ConfigObject): class NIC(ConfigObject): """Config object representing a network card.""" - __slots__ = ["mac", "ip", "bridge"] + __slots__ = ["mac", "ip", "bridge", "nicparams"] + + @classmethod + def CheckParameterSyntax(cls, nicparams): + """Check the given parameters for validity. + + @type nicparams: dict + @param nicparams: dictionary with parameter names/value + @raise errors.ConfigurationError: when a parameter is not valid + + """ + if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES: + err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE] + raise errors.ConfigurationError(err) + + if (nicparams[constants.NIC_MODE] is constants.NIC_MODE_BRIDGED and + not nicparams[constants.NIC_LINK]): + err = "Missing bridged nic link" + raise errors.ConfigurationError(err) + + def UpgradeConfig(self): + """Fill defaults for missing configuration values. + + """ + if self.nicparams is None: + self.nicparams = {} + if self.bridge is not None: + 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 + if self.bridge is not None: + self.bridge = None class Disk(ConfigObject): """Config object representing a block device.""" __slots__ = ["dev_type", "logical_id", "physical_id", - "children", "iv_name", "size"] + "children", "iv_name", "size", "mode"] def CreateOnSecondary(self): """Test if this device needs to be created on a secondary node.""" @@ -412,7 +488,7 @@ class Disk(ConfigObject): if self.logical_id is None and self.physical_id is not None: return if self.dev_type in constants.LDS_DRBD: - pnode, snode, port, pminor, sminor = self.logical_id + pnode, snode, port, pminor, sminor, secret = self.logical_id if target_node not in (pnode, snode): raise errors.ConfigurationError("DRBD device not knowing node %s" % target_node) @@ -424,9 +500,9 @@ class Disk(ConfigObject): p_data = (pnode_ip, port) s_data = (snode_ip, port) if pnode == target_node: - self.physical_id = p_data + s_data + (pminor,) + self.physical_id = p_data + s_data + (pminor, secret) else: # it must be secondary, we tested above - self.physical_id = s_data + p_data + (sminor,) + self.physical_id = s_data + p_data + (sminor, secret) else: self.physical_id = self.logical_id return @@ -458,9 +534,10 @@ class Disk(ConfigObject): obj.logical_id = tuple(obj.logical_id) if obj.physical_id and isinstance(obj.physical_id, list): obj.physical_id = tuple(obj.physical_id) - if obj.dev_type in constants.LDS_DRBD and len(obj.logical_id) == 3: - # old non-minor based disk type - obj.logical_id += (None, None) + if obj.dev_type in constants.LDS_DRBD: + # we need a tuple of length six here + if len(obj.logical_id) < 6: + obj.logical_id += (None,) * (6 - len(obj.logical_id)) return obj def __str__(self): @@ -470,6 +547,7 @@ class Disk(ConfigObject): if self.dev_type == constants.LD_LV: val = "