From b881269108c872ada159167d09f3e7c3d93d012d Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Thu, 1 Jul 2010 19:01:48 +0200 Subject: [PATCH] Rework the "type" system This patch merges the _OP_REQP and _OP_DEFS class attributes into a _OP_PARAMS list, which holds both. The associated unittest checks that all opcode attributes are declared and checked, and that no LU uses the old fields (could be removed later). Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Guido Trotter <ultrotter@google.com> --- lib/cmdlib.py | 523 +++++++++++++++++---------------- test/ganeti.cmdlib_unittest.py | 37 +++ 2 files changed, 299 insertions(+), 261 deletions(-) diff --git a/lib/cmdlib.py b/lib/cmdlib.py index b8a1649ea..a8295fa0d 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -246,14 +246,13 @@ class LogicalUnit(object): @ivar dry_run_result: the value (if any) that will be returned to the caller in dry-run mode (signalled by opcode dry_run parameter) - @cvar _OP_DEFS: a list of opcode attributes and the defaults values - they should get if not already existing + @cvar _OP_PARAMS: a list of opcode attributes, their defaults values + they should get if not already defined, and types they must match """ HPATH = None HTYPE = None - _OP_REQP = [] - _OP_DEFS = [] + _OP_PARAMS = [] REQ_BGL = True def __init__(self, processor, op, context, rpc): @@ -291,28 +290,32 @@ class LogicalUnit(object): # Tasklets self.tasklets = None - for aname, aval in self._OP_DEFS: - if not hasattr(self.op, aname): - if callable(aval): - dval = aval() - else: - dval = aval - setattr(self.op, aname, dval) - - for attr_name, test in self._OP_REQP: + # The new kind-of-type-system + op_id = self.op.OP_ID + for attr_name, aval, test in self._OP_PARAMS: if not hasattr(op, attr_name): - raise errors.OpPrereqError("Required parameter '%s' missing" % - attr_name, errors.ECODE_INVAL) - attr_val = getattr(op, attr_name, None) + if aval == _NoDefault: + raise errors.OpPrereqError("Required parameter '%s.%s' missing" % + (op_id, attr_name), errors.ECODE_INVAL) + else: + if callable(aval): + dval = aval() + else: + dval = aval + setattr(self.op, attr_name, dval) + attr_val = getattr(op, attr_name) + if test == _NoType: + # no tests here + continue if not callable(test): - raise errors.ProgrammerError("Validation for parameter '%s' failed," + raise errors.ProgrammerError("Validation for parameter '%s.%s' failed," " given type is not a proper type (%s)" % - (attr_name, test)) + (op_id, attr_name, test)) if not test(attr_val): logging.error("OpCode %s, parameter %s, has invalid type %s/value %s", self.op.OP_ID, attr_name, type(attr_val), attr_val) - raise errors.OpPrereqError("Parameter '%s' has invalid type" % - attr_name, errors.ECODE_INVAL) + raise errors.OpPrereqError("Parameter '%s.%s' fails validation" % + (op_id, attr_name), errors.ECODE_INVAL) self.CheckArguments() @@ -1160,7 +1163,6 @@ class LUPostInitCluster(LogicalUnit): """ HPATH = "cluster-init" HTYPE = constants.HTYPE_CLUSTER - _OP_REQP = [] def BuildHooksEnv(self): """Build hooks env. @@ -1183,7 +1185,6 @@ class LUDestroyCluster(LogicalUnit): """ HPATH = "cluster-destroy" HTYPE = constants.HTYPE_CLUSTER - _OP_REQP = [] def BuildHooksEnv(self): """Build hooks env. @@ -1278,11 +1279,12 @@ class LUVerifyCluster(LogicalUnit): """ HPATH = "cluster-verify" HTYPE = constants.HTYPE_CLUSTER - _OP_REQP = [ - ("skip_checks", _TListOf(_TElemOf(constants.VERIFY_OPTIONAL_CHECKS))), - ("verbose", _TBool), - ("error_codes", _TBool), - ("debug_simulate_errors", _TBool), + _OP_PARAMS = [ + ("skip_checks", _EmptyList, + _TListOf(_TElemOf(constants.VERIFY_OPTIONAL_CHECKS))), + ("verbose", False, _TBool), + ("error_codes", False, _TBool), + ("debug_simulate_errors", False, _TBool), ] REQ_BGL = False @@ -2261,7 +2263,6 @@ class LUVerifyDisks(NoHooksLU): """Verifies the cluster disks status. """ - _OP_REQP = [] REQ_BGL = False def ExpandNames(self): @@ -2336,7 +2337,7 @@ class LURepairDiskSizes(NoHooksLU): """Verifies the cluster disks sizes. """ - _OP_REQP = [("instances", _TListOf(_TNonEmptyString))] + _OP_PARAMS = [("instances", _EmptyList, _TListOf(_TNonEmptyString))] REQ_BGL = False def ExpandNames(self): @@ -2454,7 +2455,7 @@ class LURenameCluster(LogicalUnit): """ HPATH = "cluster-rename" HTYPE = constants.HTYPE_CLUSTER - _OP_REQP = [("name", _TNonEmptyString)] + _OP_PARAMS = [("name", _NoDefault, _TNonEmptyString)] def BuildHooksEnv(self): """Build hooks env. @@ -2554,21 +2555,20 @@ class LUSetClusterParams(LogicalUnit): """ HPATH = "cluster-modify" HTYPE = constants.HTYPE_CLUSTER - _OP_REQP = [ - ("hvparams", _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), - ("os_hvp", _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), - ("osparams", _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), - ("enabled_hypervisors", + _OP_PARAMS = [ + ("vg_name", None, _TMaybeString), + ("enabled_hypervisors", None, _TOr(_TAnd(_TListOf(_TElemOf(constants.HYPER_TYPES)), _TTrue), _TNone)), - ] - _OP_DEFS = [ - ("candidate_pool_size", None), - ("uid_pool", None), - ("add_uids", None), - ("remove_uids", None), - ("hvparams", None), - ("os_hvp", None), - ("osparams", None), + ("hvparams", None, _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), + ("beparams", None, _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), + ("os_hvp", None, _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), + ("osparams", None, _TOr(_TDictOf(_TNonEmptyString, _TDict), _TNone)), + ("candidate_pool_size", None, _TOr(_TStrictPositiveInt, _TNone)), + ("uid_pool", None, _NoType), + ("add_uids", None, _NoType), + ("remove_uids", None, _NoType), + ("maintain_node_health", None, _TMaybeBool), + ("nicparams", None, _TOr(_TDict, _TNone)), ] REQ_BGL = False @@ -2576,18 +2576,6 @@ class LUSetClusterParams(LogicalUnit): """Check parameters """ - if self.op.candidate_pool_size is not None: - try: - self.op.candidate_pool_size = int(self.op.candidate_pool_size) - except (ValueError, TypeError), err: - raise errors.OpPrereqError("Invalid candidate_pool_size value: %s" % - str(err), errors.ECODE_INVAL) - if self.op.candidate_pool_size < 1: - raise errors.OpPrereqError("At least one master candidate needed", - errors.ECODE_INVAL) - - _CheckBooleanOpField(self.op, "maintain_node_health") - if self.op.uid_pool: uidpool.CheckUidPool(self.op.uid_pool) @@ -2865,7 +2853,6 @@ class LURedistributeConfig(NoHooksLU): This is a very simple LU. """ - _OP_REQP = [] REQ_BGL = False def ExpandNames(self): @@ -2995,9 +2982,9 @@ class LUDiagnoseOS(NoHooksLU): """Logical unit for OS diagnose/query. """ - _OP_REQP = [ - ("output_fields", _TListOf(_TNonEmptyString)), - ("names", _TListOf(_TNonEmptyString)), + _OP_PARAMS = [ + _POutputFields, + ("names", _EmptyList, _TListOf(_TNonEmptyString)), ] REQ_BGL = False _FIELDS_STATIC = utils.FieldSet() @@ -3119,7 +3106,9 @@ class LURemoveNode(LogicalUnit): """ HPATH = "node-remove" HTYPE = constants.HTYPE_NODE - _OP_REQP = [("node_name", _TNonEmptyString)] + _OP_PARAMS = [ + _PNodeName, + ] def BuildHooksEnv(self): """Build hooks env. @@ -3212,10 +3201,10 @@ class LUQueryNodes(NoHooksLU): """ # pylint: disable-msg=W0142 - _OP_REQP = [ - ("output_fields", _TListOf(_TNonEmptyString)), - ("names", _TListOf(_TNonEmptyString)), - ("use_locking", _TBool), + _OP_PARAMS = [ + _POutputFields, + ("names", _EmptyList, _TListOf(_TNonEmptyString)), + ("use_locking", False, _TBool), ] REQ_BGL = False @@ -3369,9 +3358,9 @@ class LUQueryNodeVolumes(NoHooksLU): """Logical unit for getting volumes on node(s). """ - _OP_REQP = [ - ("nodes", _TListOf(_TNonEmptyString)), - ("output_fields", _TListOf(_TNonEmptyString)), + _OP_PARAMS = [ + ("nodes", _EmptyList, _TListOf(_TNonEmptyString)), + ("output_fields", _NoDefault, _TListOf(_TNonEmptyString)), ] REQ_BGL = False _FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance") @@ -3452,12 +3441,12 @@ class LUQueryNodeStorage(NoHooksLU): """ _FIELDS_STATIC = utils.FieldSet(constants.SF_NODE) - _OP_REQP = [ - ("nodes", _TListOf(_TNonEmptyString)), - ("storage_type", _CheckStorageType), - ("output_fields", _TListOf(_TNonEmptyString)), + _OP_PARAMS = [ + ("nodes", _EmptyList, _TListOf(_TNonEmptyString)), + ("storage_type", _NoDefault, _CheckStorageType), + ("output_fields", _NoDefault, _TListOf(_TNonEmptyString)), + ("name", None, _TMaybeString), ] - _OP_DEFS = [("name", None)] REQ_BGL = False def CheckArguments(self): @@ -3540,11 +3529,11 @@ class LUModifyNodeStorage(NoHooksLU): """Logical unit for modifying a storage volume on a node. """ - _OP_REQP = [ - ("node_name", _TNonEmptyString), - ("storage_type", _CheckStorageType), - ("name", _TNonEmptyString), - ("changes", _TDict), + _OP_PARAMS = [ + _PNodeName, + ("storage_type", _NoDefault, _CheckStorageType), + ("name", _NoDefault, _TNonEmptyString), + ("changes", _NoDefault, _TDict), ] REQ_BGL = False @@ -3590,10 +3579,12 @@ class LUAddNode(LogicalUnit): """ HPATH = "node-add" HTYPE = constants.HTYPE_NODE - _OP_REQP = [ - ("node_name", _TNonEmptyString), + _OP_PARAMS = [ + _PNodeName, + ("primary_ip", None, _NoType), + ("secondary_ip", None, _TMaybeString), + ("readd", False, _TBool), ] - _OP_DEFS = [("secondary_ip", None)] def CheckArguments(self): # validate/normalize the node name @@ -3823,15 +3814,18 @@ class LUSetNodeParams(LogicalUnit): """ HPATH = "node-modify" HTYPE = constants.HTYPE_NODE - _OP_REQP = [("node_name", _TNonEmptyString)] + _OP_PARAMS = [ + _PNodeName, + ("master_candidate", None, _TMaybeBool), + ("offline", None, _TMaybeBool), + ("drained", None, _TMaybeBool), + ("auto_promote", False, _TBool), + _PForce, + ] REQ_BGL = False def CheckArguments(self): self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name) - _CheckBooleanOpField(self.op, 'master_candidate') - _CheckBooleanOpField(self.op, 'offline') - _CheckBooleanOpField(self.op, 'drained') - _CheckBooleanOpField(self.op, 'auto_promote') all_mods = [self.op.offline, self.op.master_candidate, self.op.drained] if all_mods.count(None) == 3: raise errors.OpPrereqError("Please pass at least one modification", @@ -3984,9 +3978,9 @@ class LUPowercycleNode(NoHooksLU): """Powercycles a node. """ - _OP_REQP = [ - ("node_name", _TNonEmptyString), - ("force", _TBool), + _OP_PARAMS = [ + _PNodeName, + _PForce, ] REQ_BGL = False @@ -4020,7 +4014,6 @@ class LUQueryClusterInfo(NoHooksLU): """Query cluster configuration. """ - _OP_REQP = [] REQ_BGL = False def ExpandNames(self): @@ -4076,7 +4069,7 @@ class LUQueryConfigValues(NoHooksLU): """Return configuration values. """ - _OP_REQP = [] + _OP_PARAMS = [_POutputFields] REQ_BGL = False _FIELDS_DYNAMIC = utils.FieldSet() _FIELDS_STATIC = utils.FieldSet("cluster_name", "master_node", "drain_flag", @@ -4114,8 +4107,10 @@ class LUActivateInstanceDisks(NoHooksLU): """Bring up an instance's disks. """ - _OP_REQP = [("instance_name", _TNonEmptyString)] - _OP_DEFS = [("ignore_size", False)] + _OP_PARAMS = [ + _PInstanceName, + ("ignore_size", False, _TBool), + ] REQ_BGL = False def ExpandNames(self): @@ -4258,7 +4253,9 @@ class LUDeactivateInstanceDisks(NoHooksLU): """Shutdown an instance's disks. """ - _OP_REQP = [("instance_name", _TNonEmptyString)] + _OP_PARAMS = [ + _PInstanceName, + ] REQ_BGL = False def ExpandNames(self): @@ -4421,15 +4418,11 @@ class LUStartupInstance(LogicalUnit): """ HPATH = "instance-start" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("force", _TBool), - ("beparams", _TDict), - ("hvparams", _TDict), - ] - _OP_DEFS = [ - ("beparams", _EmptyDict), - ("hvparams", _EmptyDict), + _OP_PARAMS = [ + _PInstanceName, + _PForce, + ("hvparams", _EmptyDict, _TDict), + ("beparams", _EmptyDict, _TDict), ] REQ_BGL = False @@ -4519,12 +4512,12 @@ class LURebootInstance(LogicalUnit): """ HPATH = "instance-reboot" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("ignore_secondaries", _TBool), - ("reboot_type", _TElemOf(constants.REBOOT_TYPES)), + _OP_PARAMS = [ + _PInstanceName, + ("ignore_secondaries", False, _TBool), + ("reboot_type", _NoDefault, _TElemOf(constants.REBOOT_TYPES)), + _PShutdownTimeout, ] - _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)] REQ_BGL = False def ExpandNames(self): @@ -4600,8 +4593,10 @@ class LUShutdownInstance(LogicalUnit): """ HPATH = "instance-stop" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [("instance_name", _TNonEmptyString)] - _OP_DEFS = [("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)] + _OP_PARAMS = [ + _PInstanceName, + ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, _TPositiveInt), + ] REQ_BGL = False def ExpandNames(self): @@ -4651,10 +4646,10 @@ class LUReinstallInstance(LogicalUnit): """ HPATH = "instance-reinstall" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [("instance_name", _TNonEmptyString)] - _OP_DEFS = [ - ("os_type", None), - ("force_variant", False), + _OP_PARAMS = [ + _PInstanceName, + ("os_type", None, _TMaybeString), + ("force_variant", False, _TBool), ] REQ_BGL = False @@ -4724,9 +4719,9 @@ class LURecreateInstanceDisks(LogicalUnit): """ HPATH = "instance-recreate-disks" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("disks", _TListOf(_TPositiveInt)), + _OP_PARAMS = [ + _PInstanceName, + ("disks", _EmptyList, _TListOf(_TPositiveInt)), ] REQ_BGL = False @@ -4788,13 +4783,12 @@ class LURenameInstance(LogicalUnit): """ HPATH = "instance-rename" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("new_name", _TNonEmptyString), - ("ignore_ip", _TBool), - ("check_name", _TBool), + _OP_PARAMS = [ + _PInstanceName, + ("new_name", _NoDefault, _TNonEmptyString), + ("ignore_ip", False, _TBool), + ("check_name", True, _TBool), ] - _OP_DEFS = [("ignore_ip", False), ("check_name", True)] def BuildHooksEnv(self): """Build hooks env. @@ -4887,11 +4881,11 @@ class LURemoveInstance(LogicalUnit): """ HPATH = "instance-remove" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("ignore_failures", _TBool), + _OP_PARAMS = [ + _PInstanceName, + ("ignore_failures", False, _TBool), + _PShutdownTimeout, ] - _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)] REQ_BGL = False def ExpandNames(self): @@ -4974,10 +4968,10 @@ class LUQueryInstances(NoHooksLU): """ # pylint: disable-msg=W0142 - _OP_REQP = [ - ("output_fields", _TListOf(_TNonEmptyString)), - ("names", _TListOf(_TNonEmptyString)), - ("use_locking", _TBool), + _OP_PARAMS = [ + ("output_fields", _NoDefault, _TListOf(_TNonEmptyString)), + ("names", _EmptyList, _TListOf(_TNonEmptyString)), + ("use_locking", False, _TBool), ] REQ_BGL = False _SIMPLE_FIELDS = ["name", "os", "network_port", "hypervisor", @@ -5256,11 +5250,11 @@ class LUFailoverInstance(LogicalUnit): """ HPATH = "instance-failover" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("ignore_consistency", _TBool), + _OP_PARAMS = [ + _PInstanceName, + ("ignore_consistency", False, _TBool), + _PShutdownTimeout, ] - _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)] REQ_BGL = False def ExpandNames(self): @@ -5410,10 +5404,10 @@ class LUMigrateInstance(LogicalUnit): """ HPATH = "instance-migrate" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("live", _TBool), - ("cleanup", _TBool), + _OP_PARAMS = [ + _PInstanceName, + ("live", True, _TBool), + ("cleanup", False, _TBool), ] REQ_BGL = False @@ -5462,11 +5456,11 @@ class LUMoveInstance(LogicalUnit): """ HPATH = "instance-move" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("target_node", _TNonEmptyString), + _OP_PARAMS = [ + _PInstanceName, + ("target_node", _NoDefault, _TNonEmptyString), + _PShutdownTimeout, ] - _OP_DEFS = [("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT)] REQ_BGL = False def ExpandNames(self): @@ -5641,9 +5635,9 @@ class LUMigrateNode(LogicalUnit): """ HPATH = "node-migrate" HTYPE = constants.HTYPE_NODE - _OP_REQP = [ - ("node_name", _TNonEmptyString), - ("live", _TBool), + _OP_PARAMS = [ + _PNodeName, + ("live", False, _TBool), ] REQ_BGL = False @@ -6378,34 +6372,35 @@ class LUCreateInstance(LogicalUnit): """ HPATH = "instance-add" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("mode", _TElemOf(constants.INSTANCE_CREATE_MODES)), - ("start", _TBool), - ("wait_for_sync", _TBool), - ("ip_check", _TBool), - ("disks", _TListOf(_TDict)), - ("nics", _TListOf(_TDict)), - ("hvparams", _TDict), - ("beparams", _TDict), - ("osparams", _TDict), - ] - _OP_DEFS = [ - ("name_check", True), - ("no_install", False), - ("os_type", None), - ("force_variant", False), - ("source_handshake", None), - ("source_x509_ca", None), - ("source_instance_name", None), - ("src_node", None), - ("src_path", None), - ("pnode", None), - ("snode", None), - ("iallocator", None), - ("hypervisor", None), - ("disk_template", None), - ("identify_defaults", None), + _OP_PARAMS = [ + _PInstanceName, + ("mode", _NoDefault, _TElemOf(constants.INSTANCE_CREATE_MODES)), + ("start", True, _TBool), + ("wait_for_sync", True, _TBool), + ("ip_check", True, _TBool), + ("name_check", True, _TBool), + ("disks", _NoDefault, _TListOf(_TDict)), + ("nics", _NoDefault, _TListOf(_TDict)), + ("hvparams", _NoDefault, _TDict), + ("beparams", _NoDefault, _TDict), + ("osparams", _NoDefault, _TDict), + ("no_install", None, _TMaybeBool), + ("os_type", None, _TMaybeString), + ("force_variant", False, _TBool), + ("source_handshake", None, _TOr(_TList, _TNone)), + ("source_x509_ca", None, _TOr(_TList, _TNone)), + ("source_instance_name", None, _TMaybeString), + ("src_node", None, _TMaybeString), + ("src_path", None, _TMaybeString), + ("pnode", None, _TMaybeString), + ("snode", None, _TMaybeString), + ("iallocator", None, _TMaybeString), + ("hypervisor", None, _TMaybeString), + ("disk_template", _NoDefault, _CheckDiskTemplate), + ("identify_defaults", False, _TBool), + ("file_driver", None, _TOr(_TNone, _TElemOf(constants.FILE_DRIVER))), + ("file_storage_dir", None, _TMaybeString), + ("dry_run", False, _TBool), ] REQ_BGL = False @@ -7287,7 +7282,9 @@ class LUConnectConsole(NoHooksLU): console. """ - _OP_REQP = [("instance_name", _TNonEmptyString)] + _OP_PARAMS = [ + _PInstanceName + ] REQ_BGL = False def ExpandNames(self): @@ -7338,15 +7335,13 @@ class LUReplaceDisks(LogicalUnit): """ HPATH = "mirrors-replace" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("mode", _TElemOf(constants.REPLACE_MODES)), - ("disks", _TListOf(_TPositiveInt)), - ] - _OP_DEFS = [ - ("remote_node", None), - ("iallocator", None), - ("early_release", None), + _OP_PARAMS = [ + _PInstanceName, + ("mode", _NoDefault, _TElemOf(constants.REPLACE_MODES)), + ("disks", _EmptyList, _TListOf(_TPositiveInt)), + ("remote_node", None, _TMaybeString), + ("iallocator", None, _TMaybeString), + ("early_release", False, _TBool), ] REQ_BGL = False @@ -8083,14 +8078,17 @@ class LURepairNodeStorage(NoHooksLU): """Repairs the volume group on a node. """ - _OP_REQP = [("node_name", _TNonEmptyString)] + _OP_PARAMS = [ + _PNodeName, + ("storage_type", _NoDefault, _CheckStorageType), + ("name", _NoDefault, _TNonEmptyString), + ("ignore_consistency", False, _TBool), + ] REQ_BGL = False def CheckArguments(self): self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name) - _CheckStorageType(self.op.storage_type) - storage_type = self.op.storage_type if (constants.SO_FIX_CONSISTENCY not in @@ -8148,10 +8146,10 @@ class LUNodeEvacuationStrategy(NoHooksLU): """Computes the node evacuation strategy. """ - _OP_REQP = [("nodes", _TListOf(_TNonEmptyString))] - _OP_DEFS = [ - ("remote_node", None), - ("iallocator", None), + _OP_PARAMS = [ + ("nodes", _NoDefault, _TListOf(_TNonEmptyString)), + ("remote_node", None, _TMaybeString), + ("iallocator", None, _TMaybeString), ] REQ_BGL = False @@ -8201,11 +8199,11 @@ class LUGrowDisk(LogicalUnit): """ HPATH = "disk-grow" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("disk", _TInt), - ("amount", _TInt), - ("wait_for_sync", _TBool), + _OP_PARAMS = [ + _PInstanceName, + ("disk", _NoDefault, _TInt), + ("amount", _NoDefault, _TInt), + ("wait_for_sync", True, _TBool), ] REQ_BGL = False @@ -8300,9 +8298,9 @@ class LUQueryInstanceData(NoHooksLU): """Query runtime instance data. """ - _OP_REQP = [ - ("instances", _TListOf(_TNonEmptyString)), - ("static", _TBool), + _OP_PARAMS = [ + ("instances", _EmptyList, _TListOf(_TNonEmptyString)), + ("static", False, _TBool), ] REQ_BGL = False @@ -8460,18 +8458,18 @@ class LUSetInstanceParams(LogicalUnit): """ HPATH = "instance-modify" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [("instance_name", _TNonEmptyString)] - _OP_DEFS = [ - ("nics", _EmptyList), - ("disks", _EmptyList), - ("beparams", _EmptyDict), - ("hvparams", _EmptyDict), - ("disk_template", None), - ("remote_node", None), - ("os_name", None), - ("force_variant", False), - ("osparams", None), - ("force", False), + _OP_PARAMS = [ + _PInstanceName, + ("nics", _EmptyList, _TList), + ("disks", _EmptyList, _TList), + ("beparams", _EmptyDict, _TDict), + ("hvparams", _EmptyDict, _TDict), + ("disk_template", None, _TMaybeString), + ("remote_node", None, _TMaybeString), + ("os_name", None, _TMaybeString), + ("force_variant", False, _TBool), + ("osparams", None, _TOr(_TDict, _TNone)), + _PForce, ] REQ_BGL = False @@ -9122,7 +9120,10 @@ class LUQueryExports(NoHooksLU): """Query the exports list """ - _OP_REQP = [("nodes", _TListOf(_TNonEmptyString))] + _OP_PARAMS = [ + ("nodes", _EmptyList, _TListOf(_TNonEmptyString)), + ("use_locking", False, _TBool), + ] REQ_BGL = False def ExpandNames(self): @@ -9159,9 +9160,9 @@ class LUPrepareExport(NoHooksLU): """Prepares an instance for an export and returns useful information. """ - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("mode", _TElemOf(constants.EXPORT_MODES)), + _OP_PARAMS = [ + _PInstanceName, + ("mode", _NoDefault, _TElemOf(constants.EXPORT_MODES)), ] REQ_BGL = False @@ -9216,19 +9217,16 @@ class LUExportInstance(LogicalUnit): """ HPATH = "instance-export" HTYPE = constants.HTYPE_INSTANCE - _OP_REQP = [ - ("instance_name", _TNonEmptyString), - ("target_node", _TNonEmptyString), - ("shutdown", _TBool), - ("mode", _TElemOf(constants.EXPORT_MODES)), - ] - _OP_DEFS = [ - ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT), - ("remove_instance", False), - ("ignore_remove_failures", False), - ("mode", constants.EXPORT_MODE_LOCAL), - ("x509_key_name", None), - ("destination_x509_ca", None), + _OP_PARAMS = [ + _PInstanceName, + ("target_node", _NoDefault, _TOr(_TNonEmptyString, _TList)), + ("shutdown", True, _TBool), + _PShutdownTimeout, + ("remove_instance", False, _TBool), + ("ignore_remove_failures", False, _TBool), + ("mode", constants.EXPORT_MODE_LOCAL, _TElemOf(constants.EXPORT_MODES)), + ("x509_key_name", None, _TOr(_TList, _TNone)), + ("destination_x509_ca", None, _TMaybeString), ] REQ_BGL = False @@ -9505,7 +9503,9 @@ class LURemoveExport(NoHooksLU): """Remove exports related to the named instance. """ - _OP_REQP = [("instance_name", _TNonEmptyString)] + _OP_PARAMS = [ + _PInstanceName, + ] REQ_BGL = False def ExpandNames(self): @@ -9584,9 +9584,9 @@ class LUGetTags(TagsLU): """Returns the tags of a given object. """ - _OP_REQP = [ - ("kind", _TElemOf(constants.VALID_TAG_TYPES)), - ("name", _TNonEmptyString), + _OP_PARAMS = [ + ("kind", _NoDefault, _TElemOf(constants.VALID_TAG_TYPES)), + ("name", _NoDefault, _TNonEmptyString), ] REQ_BGL = False @@ -9601,7 +9601,9 @@ class LUSearchTags(NoHooksLU): """Searches the tags for a given pattern. """ - _OP_REQP = [("pattern", _TNonEmptyString)] + _OP_PARAMS = [ + ("pattern", _NoDefault, _TNonEmptyString), + ] REQ_BGL = False def ExpandNames(self): @@ -9641,10 +9643,10 @@ class LUAddTags(TagsLU): """Sets a tag on a given object. """ - _OP_REQP = [ - ("kind", _TElemOf(constants.VALID_TAG_TYPES)), - ("name", _TNonEmptyString), - ("tags", _TListOf(objects.TaggableObject.ValidateTag)), + _OP_PARAMS = [ + ("kind", _NoDefault, _TElemOf(constants.VALID_TAG_TYPES)), + ("name", _NoDefault, _TNonEmptyString), + ("tags", _NoDefault, _TListOf(_TNonEmptyString)), ] REQ_BGL = False @@ -9674,10 +9676,10 @@ class LUDelTags(TagsLU): """Delete a list of tags from a given object. """ - _OP_REQP = [ - ("kind", _TElemOf(constants.VALID_TAG_TYPES)), - ("name", _TNonEmptyString), - ("tags", _TListOf(objects.TaggableObject.ValidateTag)), + _OP_PARAMS = [ + ("kind", _NoDefault, _TElemOf(constants.VALID_TAG_TYPES)), + ("name", _NoDefault, _TNonEmptyString), + ("tags", _NoDefault, _TListOf(_TNonEmptyString)), ] REQ_BGL = False @@ -9715,14 +9717,11 @@ class LUTestDelay(NoHooksLU): time. """ - _OP_REQP = [ - ("duration", _TFloat), - ("on_master", _TBool), - ("on_nodes", _TListOf(_TNonEmptyString)), - ("repeat", _TPositiveInt) - ] - _OP_DEFS = [ - ("repeat", 0), + _OP_PARAMS = [ + ("duration", _NoDefault, _TFloat), + ("on_master", True, _TBool), + ("on_nodes", _EmptyList, _TListOf(_TNonEmptyString)), + ("repeat", 0, _TPositiveInt) ] REQ_BGL = False @@ -10097,20 +10096,22 @@ class LUTestAllocator(NoHooksLU): This LU runs the allocator tests """ - _OP_REQP = [ - ("direction", _TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)), - ("mode", _TElemOf(constants.VALID_IALLOCATOR_MODES)), - ("name", _TNonEmptyString), - ("nics", _TOr(_TNone, _TListOf( + _OP_PARAMS = [ + ("direction", _NoDefault, _TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)), + ("mode", _NoDefault, _TElemOf(constants.VALID_IALLOCATOR_MODES)), + ("name", _NoDefault, _TNonEmptyString), + ("nics", _NoDefault, _TOr(_TNone, _TListOf( _TDictOf(_TElemOf(["mac", "ip", "bridge"]), _TOr(_TNone, _TNonEmptyString))))), - ("disks", _TOr(_TNone, _TList)), - ] - _OP_DEFS = [ - ("hypervisor", None), - ("allocator", None), - ("nics", None), - ("disks", None), + ("disks", _NoDefault, _TOr(_TNone, _TList)), + ("hypervisor", None, _TMaybeString), + ("allocator", None, _TMaybeString), + ("tags", _EmptyList, _TListOf(_TNonEmptyString)), + ("mem_size", None, _TOr(_TNone, _TPositiveInt)), + ("vcpus", None, _TOr(_TNone, _TPositiveInt)), + ("os", None, _TMaybeString), + ("disk_template", None, _TMaybeString), + ("evac_nodes", None, _TOr(_TNone, _TListOf(_TNonEmptyString))), ] def CheckPrereq(self): diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py index 092225b20..0606f8d0c 100755 --- a/test/ganeti.cmdlib_unittest.py +++ b/test/ganeti.cmdlib_unittest.py @@ -28,8 +28,11 @@ import time import tempfile import shutil +from ganeti import mcpu from ganeti import cmdlib +from ganeti import opcodes from ganeti import errors +from ganeti import utils import testutils @@ -57,5 +60,39 @@ class TestCertVerification(testutils.GanetiTestCase): self.assertEqual(errcode, cmdlib.LUVerifyCluster.ETYPE_ERROR) +class TestOpcodeParams(testutils.GanetiTestCase): + def testParamsStructures(self): + for op in sorted(mcpu.Processor.DISPATCH_TABLE): + lu = mcpu.Processor.DISPATCH_TABLE[op] + lu_name = lu.__name__ + self.failIf(hasattr(lu, "_OP_REQP"), "LU '%s' has old-style _OP_REQP" % + lu_name) + self.failIf(hasattr(lu, "_OP_DEFS"), "LU '%s' has old-style _OP_DEFS" % + lu_name) + # this needs to remain a list! + defined_params = [v[0] for v in lu._OP_PARAMS] + for row in lu._OP_PARAMS: + # this relies on there being at least one element + param_name = row[0] + self.failIf(len(row) != 3, "LU '%s' parameter %s has invalid length" % + (lu_name, param_name)) + self.failIf(defined_params.count(param_name) > 1, "LU '%s' parameter" + " '%s' is defined multiple times" % (lu_name, param_name)) + + def testParamsDefined(self): + for op in sorted(mcpu.Processor.DISPATCH_TABLE): + lu = mcpu.Processor.DISPATCH_TABLE[op] + lu_name = lu.__name__ + # TODO: this doesn't deal with recursive slots definitions + all_params = set(op.__slots__) + defined_params = set(v[0] for v in lu._OP_PARAMS) + missing = all_params.difference(defined_params) + self.failIf(missing, "Undeclared parameter types for LU '%s': %s" % + (lu_name, utils.CommaJoin(missing))) + extra = defined_params.difference(all_params) + self.failIf(extra, "Extra parameter types for LU '%s': %s" % + (lu_name, utils.CommaJoin(extra))) + + if __name__ == "__main__": testutils.GanetiTestProgram() -- GitLab