From 918eb80bea02013b7a474e3ef0e9d5fb4a3ac8ea Mon Sep 17 00:00:00 2001 From: Agata Murawska <agatamurawska@google.com> Date: Tue, 6 Dec 2011 16:07:50 +0100 Subject: [PATCH] Introduce instance policy on cluster level Signed-off-by: Agata Murawska <agatamurawska@google.com> Reviewed-by: Iustin Pop <iustin@google.com> --- lib/config.py | 13 ++++++++ lib/constants.py | 51 +++++++++++++++++++++++++++++++ lib/objects.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/lib/config.py b/lib/config.py index c7c3cc6e7..13e00ad11 100644 --- a/lib/config.py +++ b/lib/config.py @@ -426,6 +426,17 @@ class ConfigWriter: except errors.ConfigurationError, err: result.append("%s has invalid nicparams: %s" % (owner, err)) + def _helper_ipolicy(owner, params): + try: + objects.InstancePolicy.CheckParameterSyntax(params) + except errors.ConfigurationError, err: + result.append("%s has invalid instance policy: %s" % (owner, err)) + + def _helper_ispecs(owner, params): + for key, value in params.iteritems(): + fullkey = "ipolicy/" + key + _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES) + # check cluster parameters _helper("cluster", "beparams", cluster.SimpleFillBE({}), constants.BES_PARAMETER_TYPES) @@ -434,6 +445,8 @@ class ConfigWriter: _helper_nic("cluster", cluster.SimpleFillNIC({})) _helper("cluster", "ndparams", cluster.SimpleFillND({}), constants.NDS_PARAMETER_TYPES) + _helper_ipolicy("cluster", cluster.SimpleFillIPolicy({})) + _helper_ispecs("cluster", cluster.SimpleFillIPolicy({})) # per-instance checks for instance_name in data.instances: diff --git a/lib/constants.py b/lib/constants.py index d27fefe97..27a993cfe 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -921,6 +921,33 @@ BES_PARAMETER_COMPAT.update(BES_PARAMETER_TYPES) BES_PARAMETERS = frozenset(BES_PARAMETER_TYPES.keys()) +# instance specs +MEM_SIZE_SPEC = "memory-size" +CPU_COUNT_SPEC = "cpu-count" +DISK_COUNT_SPEC = "disk-count" +DISK_SIZE_SPEC = "disk-size" +NIC_COUNT_SPEC = "nic-count" + +ISPECS_PARAMETER_TYPES = { + MEM_SIZE_SPEC: VTYPE_INT, + CPU_COUNT_SPEC: VTYPE_INT, + DISK_COUNT_SPEC: VTYPE_INT, + DISK_SIZE_SPEC: VTYPE_INT, + NIC_COUNT_SPEC: VTYPE_INT, + } + +ISPECS_PARAMETERS = frozenset(ISPECS_PARAMETER_TYPES.keys()) + +MIN_ISPECS = "min" +MAX_ISPECS = "max" +STD_ISPECS = "std" + +IPOLICY_PARAMETERS = frozenset([ + MIN_ISPECS, + MAX_ISPECS, + STD_ISPECS + ]) + # Node parameter names ND_OOB_PROGRAM = "oob_program" @@ -1783,6 +1810,30 @@ NICC_DEFAULTS = { NIC_LINK: DEFAULT_BRIDGE, } +IPOLICY_DEFAULTS = { + MIN_ISPECS: { + MEM_SIZE_SPEC: 128, + CPU_COUNT_SPEC: 1, + DISK_COUNT_SPEC: 1, + DISK_SIZE_SPEC: 1024, + NIC_COUNT_SPEC: 1, + }, + MAX_ISPECS: { + MEM_SIZE_SPEC: 128, + CPU_COUNT_SPEC: 1, + DISK_COUNT_SPEC: 1, + DISK_SIZE_SPEC: 1024, + NIC_COUNT_SPEC: 1, + }, + STD_ISPECS: { + MEM_SIZE_SPEC: 128, + CPU_COUNT_SPEC: 1, + DISK_COUNT_SPEC: 1, + DISK_SIZE_SPEC: 1024, + NIC_COUNT_SPEC: 1, + } + } + MASTER_POOL_SIZE_DEFAULT = 10 CONFD_PROTOCOL_VERSION = 1 diff --git a/lib/objects.py b/lib/objects.py index 7cedc12d2..f0bd2bb13 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -79,6 +79,18 @@ def FillDict(defaults_dict, custom_dict, skip_keys=None): return ret_dict +def FillDictOfDicts(defaults_dict, custom_dict, skip_keys=None): + """Run FillDict for each key in dictionary. + + """ + ret_dict = {} + for key in defaults_dict.keys(): + ret_dict[key] = FillDict(defaults_dict[key], + custom_dict.get(key, {}), + skip_keys=skip_keys) + return ret_dict + + def UpgradeGroupedParams(target, defaults): """Update all groups for the target parameter. @@ -136,6 +148,17 @@ def UpgradeDiskParams(diskparams): return result +def MakeEmptyIPolicy(): + """Create empty IPolicy dictionary. + + """ + return dict([ + (constants.MIN_ISPECS, dict()), + (constants.MAX_ISPECS, dict()), + (constants.STD_ISPECS, dict()), + ]) + + class ConfigObject(object): """A generic config object. @@ -780,6 +803,44 @@ class Disk(ConfigObject): # add here config upgrade for this disk +class InstancePolicy(ConfigObject): + """Config object representing instance policy limits dictionary.""" + __slots__ = ["min", "max", "std"] + + @classmethod + def CheckParameterSyntax(cls, ipolicy): + """ Check the instance policy for validity. + + """ + for param in constants.ISPECS_PARAMETERS: + InstancePolicy.CheckISpecSyntax(ipolicy, param) + + @classmethod + def CheckISpecSyntax(cls, ipolicy, name): + """Check the instance policy for validity on a given key. + + We check if the instance policy makes sense for a given key, that is + if ipolicy[min][name] <= ipolicy[std][name] <= ipolicy[max][name]. + + @type ipolicy: dict + @param ipolicy: dictionary with min, max, std specs + @type name: string + @param name: what are the limits for + @raise errors.ConfigureError: when specs for given name are not valid + + """ + min_v = ipolicy[constants.MIN_ISPECS].get(name, 0) + std_v = ipolicy[constants.STD_ISPECS].get(name, min_v) + max_v = ipolicy[constants.MAX_ISPECS].get(name, std_v) + err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" % + (name, + ipolicy[constants.MIN_ISPECS].get(name, "-"), + ipolicy[constants.MAX_ISPECS].get(name, "-"), + ipolicy[constants.STD_ISPECS].get(name, "-"))) + if min_v > std_v or std_v > max_v: + raise errors.ConfigurationError(err) + + class Instance(TaggableObject): """Config object representing an instance.""" __slots__ = [ @@ -1238,6 +1299,7 @@ class Cluster(TaggableObject): "shared_file_storage_dir", "enabled_hypervisors", "hvparams", + "ipolicy", "os_hvp", "beparams", "osparams", @@ -1354,6 +1416,10 @@ class Cluster(TaggableObject): self.diskparams = UpgradeDiskParams(self.diskparams) + # instance policy added before 2.6 + if self.ipolicy is None: + self.ipolicy = MakeEmptyIPolicy() + @property def primary_hypervisor(self): """The first hypervisor is the primary. @@ -1537,6 +1603,18 @@ class Cluster(TaggableObject): """ return FillDict(self.ndparams, ndparams) + def SimpleFillIPolicy(self, ipolicy): + """ Fill instance policy dict with defaults. + + @type ipolicy: dict + @param ipolicy: the dict to fill + @rtype: dict + @return: a copy of passed ipolicy with missing keys filled from + the cluster defaults + + """ + return FillDictOfDicts(self.ipolicy, ipolicy) + class BlockDevStatus(ConfigObject): """Config object representing the status of a block device.""" -- GitLab