From: Iustin Pop Date: Wed, 4 Nov 2009 16:41:04 +0000 (+0100) Subject: Introduce 'global hypervisor parameters' support X-Git-Tag: v2.1.0rc0~21 X-Git-Url: https://code.grnet.gr/git/ganeti-local/commitdiff_plain/7736a5f2ae02b10e92f8bb4cf55f0f0c60740c83 Introduce 'global hypervisor parameters' support This patch adds support for global hypervisor parameters in instance creation, instance modification, instance query and at instance load time. We basically prevent any query on these parameters, discard them at load time, and do not allow their modification. Together, this should make any such parameters go away if existing and not allowed to be added. Signed-off-by: Iustin Pop Reviewed-by: Guido Trotter --- diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 7f046ec..c1a52ff 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -500,6 +500,21 @@ def _CheckBooleanOpField(op, name): setattr(op, name, val) +def _CheckGlobalHvParams(params): + """Validates that given hypervisor params are not global ones. + + This will ensure that instances don't get customised versions of + global params. + + """ + used_globals = constants.HVC_GLOBALS.intersection(params) + if used_globals: + msg = ("The following hypervisor parameters are global and cannot" + " be customized at instance level, please modify them at" + " cluster level: %s" % ", ".join(used_globals)) + raise errors.OpPrereqError(msg, errors.ECODE_INVAL) + + def _CheckNodeOnline(lu, node): """Ensure that a given node is online. @@ -4200,7 +4215,8 @@ class LUQueryInstances(NoHooksLU): "hvparams", ] + _SIMPLE_FIELDS + ["hv/%s" % name - for name in constants.HVS_PARAMETERS] + + for name in constants.HVS_PARAMETERS + if name not in constants.HVC_GLOBALS] + ["be/%s" % name for name in constants.BES_PARAMETERS]) _FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status") @@ -4295,7 +4311,7 @@ class LUQueryInstances(NoHooksLU): cluster = self.cfg.GetClusterInfo() for instance in instance_list: iout = [] - i_hv = cluster.FillHV(instance) + i_hv = cluster.FillHV(instance, skip_globals=True) i_be = cluster.FillBE(instance) i_nicp = [objects.FillDict(cluster.nicparams[constants.PP_DEFAULT], nic.nicparams) for nic in instance.nics] @@ -4382,7 +4398,8 @@ class LUQueryInstances(NoHooksLU): elif field == "hvparams": val = i_hv elif (field.startswith(HVPREFIX) and - field[len(HVPREFIX):] in constants.HVS_PARAMETERS): + field[len(HVPREFIX):] in constants.HVS_PARAMETERS and + field[len(HVPREFIX):] not in constants.HVC_GLOBALS): val = i_hv.get(field[len(HVPREFIX):], None) elif field == "beparams": val = i_be @@ -5599,6 +5616,8 @@ class LUCreateInstance(LogicalUnit): hv_type = hypervisor.GetHypervisor(self.op.hypervisor) hv_type.CheckParameterSyntax(filled_hvp) self.hv_full = filled_hvp + # check that we don't specify global parameters on an instance + _CheckGlobalHvParams(self.op.hvparams) # fill and remember the beparams dict utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES) @@ -7292,7 +7311,7 @@ class LUQueryInstanceData(NoHooksLU): "hypervisor": instance.hypervisor, "network_port": instance.network_port, "hv_instance": instance.hvparams, - "hv_actual": cluster.FillHV(instance), + "hv_actual": cluster.FillHV(instance, skip_globals=True), "be_instance": instance.beparams, "be_actual": cluster.FillBE(instance), "serial_no": instance.serial_no, @@ -7329,6 +7348,9 @@ class LUSetInstanceParams(LogicalUnit): self.op.hvparams or self.op.beparams): raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL) + if self.op.hvparams: + _CheckGlobalHvParams(self.op.hvparams) + # Disk validation disk_addremove = 0 for disk_op, disk_dict in self.op.disks: diff --git a/lib/constants.py b/lib/constants.py index bab6d8d..8a47a9d 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -650,6 +650,10 @@ HVC_DEFAULTS = { }, } +HVC_GLOBALS = frozenset([ + HV_MIGRATION_PORT, + ]) + BEC_DEFAULTS = { BE_MEMORY: 128, BE_VCPUS: 1, diff --git a/lib/objects.py b/lib/objects.py index e87fadd..06bc7e0 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -42,19 +42,26 @@ __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance", _TIMESTAMPS = ["ctime", "mtime"] _UUID = ["uuid"] -def FillDict(defaults_dict, custom_dict): +def FillDict(defaults_dict, custom_dict, skip_keys=[]): """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 + @type skip_keys: list + @param skip_keys: which keys not to fill @rtype: dict @return: dict with the 'full' values """ ret_dict = copy.deepcopy(defaults_dict) ret_dict.update(custom_dict) + for k in skip_keys: + try: + del ret_dict[k] + except KeyError: + pass return ret_dict @@ -777,6 +784,12 @@ class Instance(TaggableObject): nic.UpgradeConfig() for disk in self.disks: disk.UpgradeConfig() + if self.hvparams: + for key in constants.HVC_GLOBALS: + try: + del self.hvparams[key] + except KeyError: + pass class OS(ConfigObject): @@ -887,18 +900,25 @@ class Cluster(TaggableObject): obj.tcpudp_port_pool = set(obj.tcpudp_port_pool) return obj - def FillHV(self, instance): + def FillHV(self, instance, skip_globals=False): """Fill an instance's hvparams 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 """ + if skip_globals: + skip_keys = constants.HVC_GLOBALS + else: + skip_keys = [] return FillDict(self.hvparams.get(instance.hypervisor, {}), - instance.hvparams) + instance.hvparams, skip_keys=skip_keys) def FillBE(self, instance): """Fill an instance's beparams dict. @@ -911,7 +931,7 @@ class Cluster(TaggableObject): """ return FillDict(self.beparams.get(constants.PP_DEFAULT, {}), - instance.beparams) + instance.beparams) class BlockDevStatus(ConfigObject):