X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/d04c9d45b385a604cc6ca80de0633676cde97b22..4a78c361a6de3bcbf98f02abfe41ae3b11de2b00:/lib/objects.py diff --git a/lib/objects.py b/lib/objects.py index 6e9374c..5ba4a1b 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -55,18 +55,6 @@ __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance", _TIMESTAMPS = ["ctime", "mtime"] _UUID = ["uuid"] -# constants used to create InstancePolicy dictionary -TISPECS_GROUP_TYPES = { - constants.ISPECS_MIN: constants.VTYPE_INT, - constants.ISPECS_MAX: constants.VTYPE_INT, - } - -TISPECS_CLUSTER_TYPES = { - constants.ISPECS_MIN: constants.VTYPE_INT, - constants.ISPECS_MAX: constants.VTYPE_INT, - constants.ISPECS_STD: constants.VTYPE_INT, - } - def FillDict(defaults_dict, custom_dict, skip_keys=None): """Basic function to apply settings on top a default dict. @@ -98,17 +86,33 @@ def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None): """ assert frozenset(default_ipolicy.keys()) == constants.IPOLICY_ALL_KEYS ret_dict = {} - for key in constants.IPOLICY_PARAMETERS: + for key in constants.IPOLICY_ISPECS: ret_dict[key] = FillDict(default_ipolicy[key], custom_ipolicy.get(key, {}), skip_keys=skip_keys) # list items for key in [constants.IPOLICY_DTS]: ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key])) + # other items which we know we can directly copy (immutables) + for key in constants.IPOLICY_PARAMETERS: + ret_dict[key] = custom_ipolicy.get(key, default_ipolicy[key]) return ret_dict +def FillDiskParams(default_dparams, custom_dparams, skip_keys=None): + """Fills the disk parameter defaults. + + @see: L{FillDict} for parameters and return value + + """ + assert frozenset(default_dparams.keys()) == constants.DISK_TEMPLATES + + return dict((dt, FillDict(default_dparams[dt], custom_dparams.get(dt, {}), + skip_keys=skip_keys)) + for dt in constants.DISK_TEMPLATES) + + def UpgradeGroupedParams(target, defaults): """Update all groups for the target parameter. @@ -146,26 +150,32 @@ def UpgradeDiskParams(diskparams): @type diskparams: dict @param diskparams: disk parameters to upgrade @rtype: dict - @return: the upgraded disk parameters dit + @return: the upgraded disk parameters dict """ - result = dict() - if diskparams is None: - result = constants.DISK_DT_DEFAULTS.copy() + if not diskparams: + result = {} else: - # Update the disk parameter values for each disk template. - # The code iterates over constants.DISK_TEMPLATES because new templates - # might have been added. - for template in constants.DISK_TEMPLATES: - if template not in diskparams: - result[template] = constants.DISK_DT_DEFAULTS[template].copy() - else: - result[template] = FillDict(constants.DISK_DT_DEFAULTS[template], - diskparams[template]) + result = FillDiskParams(constants.DISK_DT_DEFAULTS, diskparams) return result +def UpgradeNDParams(ndparams): + """Upgrade ndparams structure. + + @type ndparams: dict + @param ndparams: disk parameters to upgrade + @rtype: dict + @return: the upgraded node parameters dict + + """ + if ndparams is None: + ndparams = {} + + return FillDict(constants.NDC_DEFAULTS, ndparams) + + def MakeEmptyIPolicy(): """Create empty IPolicy dictionary. @@ -177,58 +187,6 @@ def MakeEmptyIPolicy(): ]) -def CreateIPolicyFromOpts(ispecs_mem_size=None, - ispecs_cpu_count=None, - ispecs_disk_count=None, - ispecs_disk_size=None, - ispecs_nic_count=None, - ipolicy_disk_templates=None, - group_ipolicy=False, - allowed_values=None, - fill_all=False): - """Creation of instance policy based on command line options. - - @param fill_all: whether for cluster policies we should ensure that - all values are filled - - - """ - # prepare ipolicy dict - ipolicy_transposed = { - constants.ISPEC_MEM_SIZE: ispecs_mem_size, - constants.ISPEC_CPU_COUNT: ispecs_cpu_count, - constants.ISPEC_DISK_COUNT: ispecs_disk_count, - constants.ISPEC_DISK_SIZE: ispecs_disk_size, - constants.ISPEC_NIC_COUNT: ispecs_nic_count, - } - - # first, check that the values given are correct - if group_ipolicy: - forced_type = TISPECS_GROUP_TYPES - else: - forced_type = TISPECS_CLUSTER_TYPES - - for specs in ipolicy_transposed.values(): - utils.ForceDictType(specs, forced_type, allowed_values=allowed_values) - - # then transpose - ipolicy_out = MakeEmptyIPolicy() - for name, specs in ipolicy_transposed.iteritems(): - assert name in constants.ISPECS_PARAMETERS - for key, val in specs.items(): # {min: .. ,max: .., std: ..} - ipolicy_out[key][name] = val - - # no filldict for lists - if not group_ipolicy and fill_all and ipolicy_disk_templates is None: - ipolicy_disk_templates = constants.DISK_TEMPLATES - if ipolicy_disk_templates is not None: - ipolicy_out[constants.IPOLICY_DTS] = list(ipolicy_disk_templates) - - assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS) - - return ipolicy_out - - class ConfigObject(object): """A generic config object. @@ -270,6 +228,9 @@ class ConfigObject(object): slots.extend(getattr(parent, "__slots__", [])) return slots + #: Public getter for the defined slots + GetAllSlots = _all_slots + def ToDict(self): """Convert to a dict holding only standard python types. @@ -730,6 +691,21 @@ class Disk(ConfigObject): raise errors.ProgrammerError("Disk.RecordGrow called for unsupported" " disk type %s" % self.dev_type) + def Update(self, size=None, mode=None): + """Apply changes to size and mode. + + """ + if self.dev_type == constants.LD_DRBD8: + if self.children: + self.children[0].Update(size=size, mode=mode) + else: + assert not self.children + + if size is not None: + self.size = size + if mode is not None: + self.mode = mode + def UnsetSize(self): """Sets recursively the size to zero for the disk and its children. @@ -875,11 +851,103 @@ class Disk(ConfigObject): self.params) # add here config upgrade for this disk + @staticmethod + def ComputeLDParams(disk_template, disk_params): + """Computes Logical Disk parameters from Disk Template parameters. + + @type disk_template: string + @param disk_template: disk template, one of L{constants.DISK_TEMPLATES} + @type disk_params: dict + @param disk_params: disk template parameters; + dict(template_name -> parameters + @rtype: list(dict) + @return: a list of dicts, one for each node of the disk hierarchy. Each dict + contains the LD parameters of the node. The tree is flattened in-order. + + """ + if disk_template not in constants.DISK_TEMPLATES: + raise errors.ProgrammerError("Unknown disk template %s" % disk_template) + + assert disk_template in disk_params + + result = list() + dt_params = disk_params[disk_template] + if disk_template == constants.DT_DRBD8: + drbd_params = { + constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE], + constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS], + constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS], + constants.LDP_DEFAULT_METAVG: dt_params[constants.DRBD_DEFAULT_METAVG], + constants.LDP_DISK_CUSTOM: dt_params[constants.DRBD_DISK_CUSTOM], + constants.LDP_NET_CUSTOM: dt_params[constants.DRBD_NET_CUSTOM], + constants.LDP_DYNAMIC_RESYNC: dt_params[constants.DRBD_DYNAMIC_RESYNC], + constants.LDP_PLAN_AHEAD: dt_params[constants.DRBD_PLAN_AHEAD], + constants.LDP_FILL_TARGET: dt_params[constants.DRBD_FILL_TARGET], + constants.LDP_DELAY_TARGET: dt_params[constants.DRBD_DELAY_TARGET], + constants.LDP_MAX_RATE: dt_params[constants.DRBD_MAX_RATE], + constants.LDP_MIN_RATE: dt_params[constants.DRBD_MIN_RATE], + } + + drbd_params = \ + FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8], + drbd_params) + + result.append(drbd_params) + + # data LV + data_params = { + constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES], + } + data_params = \ + FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], + data_params) + result.append(data_params) + + # metadata LV + meta_params = { + constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES], + } + meta_params = \ + FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], + meta_params) + result.append(meta_params) + + elif (disk_template == constants.DT_FILE or + disk_template == constants.DT_SHARED_FILE): + result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE]) + + elif disk_template == constants.DT_PLAIN: + params = { + constants.LDP_STRIPES: dt_params[constants.LV_STRIPES], + } + params = \ + FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], + params) + result.append(params) + + elif disk_template == constants.DT_BLOCK: + result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV]) + + elif disk_template == constants.DT_RBD: + params = { + constants.LDP_POOL: dt_params[constants.RBD_POOL] + } + params = \ + FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD], + params) + result.append(params) + + return result + class InstancePolicy(ConfigObject): - """Config object representing instance policy limits dictionary.""" - __slots__ = ["min", "max", "std", "disk_templates"] + """Config object representing instance policy limits dictionary. + + Note that this object is not actually used in the config, it's just + used as a placeholder for a few functions. + + """ @classmethod def CheckParameterSyntax(cls, ipolicy): """ Check the instance policy for validity. @@ -889,6 +957,9 @@ class InstancePolicy(ConfigObject): InstancePolicy.CheckISpecSyntax(ipolicy, param) if constants.IPOLICY_DTS in ipolicy: InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS]) + for key in constants.IPOLICY_PARAMETERS: + if key in ipolicy: + InstancePolicy.CheckParameter(key, ipolicy[key]) wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS if wrong_keys: raise errors.ConfigurationError("Invalid keys in ipolicy: %s" % @@ -929,6 +1000,19 @@ class InstancePolicy(ConfigObject): raise errors.ConfigurationError("Invalid disk template(s) %s" % utils.CommaJoin(wrong)) + @classmethod + def CheckParameter(cls, key, value): + """Checks a parameter. + + Currently we expect all parameters to be float values. + + """ + try: + float(value) + except (TypeError, ValueError), err: + raise errors.ConfigurationError("Invalid value for key" " '%s':" + " '%s', error: %s" % (key, value, err)) + class Instance(TaggableObject): """Config object representing an instance.""" @@ -1341,7 +1425,8 @@ class NodeGroup(TaggableObject): if self.mtime is None: self.mtime = time.time() - self.diskparams = UpgradeDiskParams(self.diskparams) + if self.diskparams is None: + self.diskparams = {} if self.ipolicy is None: self.ipolicy = MakeEmptyIPolicy() @@ -1432,8 +1517,7 @@ class Cluster(TaggableObject): if self.osparams is None: self.osparams = {} - if self.ndparams is None: - self.ndparams = constants.NDC_DEFAULTS + self.ndparams = UpgradeNDParams(self.ndparams) self.beparams = UpgradeGroupedParams(self.beparams, constants.BEC_DEFAULTS) @@ -1506,7 +1590,10 @@ class Cluster(TaggableObject): if self.use_external_mip_script is None: self.use_external_mip_script = False - self.diskparams = UpgradeDiskParams(self.diskparams) + if self.diskparams: + self.diskparams = UpgradeDiskParams(self.diskparams) + else: + self.diskparams = constants.DISK_DT_DEFAULTS.copy() # instance policy added before 2.6 if self.ipolicy is None: @@ -1544,6 +1631,15 @@ class Cluster(TaggableObject): obj.tcpudp_port_pool = set(obj.tcpudp_port_pool) return obj + def SimpleFillDP(self, diskparams): + """Fill a given diskparams dict with cluster defaults. + + @param diskparams: The diskparams + @return: The defaults dict + + """ + return FillDiskParams(self.diskparams, diskparams) + def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None): """Get the default hypervisor parameters for the cluster. @@ -1836,17 +1932,6 @@ class _QueryResponseBase(ConfigObject): return obj -class QueryRequest(ConfigObject): - """Object holding a query request. - - """ - __slots__ = [ - "what", - "fields", - "qfilter", - ] - - class QueryResponse(_QueryResponseBase): """Object holding the response to a query.