X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/45d4c81c01e75d3ca0f0ecdab23e07f3c79eb9c1..bc5d0215:/lib/opcodes.py diff --git a/lib/opcodes.py b/lib/opcodes.py index 113ce99..73c9564 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -31,12 +31,12 @@ opcodes. # this are practically structures, so disable the message about too # few public methods: -# pylint: disable-msg=R0903 +# pylint: disable=R0903 import logging import re -import operator +from ganeti import compat from ganeti import constants from ganeti import errors from ganeti import ht @@ -109,18 +109,83 @@ _PNodeGroupAllocPolicy = \ _PGroupNodeParams = ("ndparams", None, ht.TMaybeDict, "Default node parameters for group") +_PQueryWhat = ("what", ht.NoDefault, ht.TElemOf(constants.QR_VIA_OP), + "Resource(s) to query for") + +_PEarlyRelease = ("early_release", False, ht.TBool, + "Whether to release locks as soon as possible") + _PIpCheckDoc = "Whether to ensure instance's IP address is inactive" +#: Do not remember instance state changes +_PNoRemember = ("no_remember", False, ht.TBool, + "Do not remember the state change") + +#: Target node for instance migration/failover +_PMigrationTargetNode = ("target_node", None, ht.TMaybeString, + "Target node for shared-storage instances") + +_PStartupPaused = ("startup_paused", False, ht.TBool, + "Pause instance at startup") + +_PVerbose = ("verbose", False, ht.TBool, "Verbose mode") + +# Parameters for cluster verification +_PDebugSimulateErrors = ("debug_simulate_errors", False, ht.TBool, + "Whether to simulate errors (useful for debugging)") +_PErrorCodes = ("error_codes", False, ht.TBool, "Error codes") +_PSkipChecks = ("skip_checks", ht.EmptyList, + ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS)), + "Which checks to skip") +_PIgnoreErrors = ("ignore_errors", ht.EmptyList, + ht.TListOf(ht.TElemOf(constants.CV_ALL_ECODES_STRINGS)), + "List of error codes that should be treated as warnings") + +# Disk parameters +_PDiskParams = ("diskparams", None, + ht.TOr( + ht.TDictOf(ht.TElemOf(constants.DISK_TEMPLATES), ht.TDict), + ht.TNone), + "Disk templates' parameter defaults") + #: OP_ID conversion regular expression _OPID_RE = re.compile("([a-z])([A-Z])") #: Utility function for L{OpClusterSetParams} _TestClusterOsList = ht.TOr(ht.TNone, ht.TListOf(ht.TAnd(ht.TList, ht.TIsLength(2), - ht.TMap(ht.WithDesc("GetFirstItem")(operator.itemgetter(0)), + ht.TMap(ht.WithDesc("GetFirstItem")(compat.fst), ht.TElemOf(constants.DDMS_VALUES))))) +# TODO: Generate check from constants.INIC_PARAMS_TYPES +#: Utility function for testing NIC definitions +_TestNicDef = ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS), + ht.TOr(ht.TNone, ht.TNonEmptyString)) + +_TSetParamsResultItemItems = [ + ht.Comment("name of changed parameter")(ht.TNonEmptyString), + ht.Comment("new value")(ht.TAny), + ] + +_TSetParamsResult = \ + ht.TListOf(ht.TAnd(ht.TIsLength(len(_TSetParamsResultItemItems)), + ht.TItems(_TSetParamsResultItemItems))) + +_SUMMARY_PREFIX = { + "CLUSTER_": "C_", + "GROUP_": "G_", + "NODE_": "N_", + "INSTANCE_": "I_", + } + +#: Attribute name for dependencies +DEPEND_ATTR = "depends" + +#: Attribute name for comment +COMMENT_ATTR = "comment" + + def _NameToId(name): """Convert an opcode class name to an OP_ID. @@ -156,6 +221,20 @@ def RequireFileStorage(): errors.ECODE_INVAL) +def RequireSharedFileStorage(): + """Checks that shared file storage is enabled. + + While it doesn't really fit into this module, L{utils} was deemed too large + of a dependency to be imported for just one or two functions. + + @raise errors.OpPrereqError: when shared file storage is disabled + + """ + if not constants.ENABLE_SHARED_FILE_STORAGE: + raise errors.OpPrereqError("Shared file storage disabled at" + " configure time", errors.ECODE_INVAL) + + @ht.WithDesc("CheckFileStorage") def _CheckFileStorage(value): """Ensures file storage is enabled if used. @@ -163,11 +242,25 @@ def _CheckFileStorage(value): """ if value == constants.DT_FILE: RequireFileStorage() + elif value == constants.DT_SHARED_FILE: + RequireSharedFileStorage() return True -_CheckDiskTemplate = ht.TAnd(ht.TElemOf(constants.DISK_TEMPLATES), - _CheckFileStorage) +def _BuildDiskTemplateCheck(accept_none): + """Builds check for disk template. + + @type accept_none: bool + @param accept_none: whether to accept None as a correct value + @rtype: callable + + """ + template_check = ht.TElemOf(constants.DISK_TEMPLATES) + + if accept_none: + template_check = ht.TOr(template_check, ht.TNone) + + return ht.TAnd(template_check, _CheckFileStorage) def _CheckStorageType(storage_type): @@ -228,7 +321,7 @@ class BaseOpCode(object): field handling. """ - # pylint: disable-msg=E1101 + # pylint: disable=E1101 # as OP_ID is dynamically defined __metaclass__ = _AutoOpParamSlots @@ -343,6 +436,44 @@ class BaseOpCode(object): errors.ECODE_INVAL) +def _BuildJobDepCheck(relative): + """Builds check for job dependencies (L{DEPEND_ATTR}). + + @type relative: bool + @param relative: Whether to accept relative job IDs (negative) + @rtype: callable + + """ + if relative: + job_id = ht.TOr(ht.TJobId, ht.TRelativeJobId) + else: + job_id = ht.TJobId + + job_dep = \ + ht.TAnd(ht.TIsLength(2), + ht.TItems([job_id, + ht.TListOf(ht.TElemOf(constants.JOBS_FINALIZED))])) + + return ht.TOr(ht.TNone, ht.TListOf(job_dep)) + + +TNoRelativeJobDependencies = _BuildJobDepCheck(False) + +#: List of submission status and job ID as returned by C{SubmitManyJobs} +_TJobIdListItem = \ + ht.TAnd(ht.TIsLength(2), + ht.TItems([ht.Comment("success")(ht.TBool), + ht.Comment("Job ID if successful, error message" + " otherwise")(ht.TOr(ht.TString, + ht.TJobId))])) +TJobIdList = ht.TListOf(_TJobIdListItem) + +#: Result containing only list of submitted jobs +TJobIdListOnly = ht.TStrictDict(True, True, { + constants.JOB_IDS_KEY: ht.Comment("List of submitted jobs")(TJobIdList), + }) + + class OpCode(BaseOpCode): """Abstract OpCode. @@ -356,6 +487,7 @@ class OpCode(BaseOpCode): method for details). @cvar OP_PARAMS: List of opcode attributes, the default values they should get if not already defined, and types they must match. + @cvar OP_RESULT: Callable to verify opcode result @cvar WITH_LU: Boolean that specifies whether this should be included in mcpu's dispatch table @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just @@ -363,7 +495,7 @@ class OpCode(BaseOpCode): @ivar priority: Opcode priority for queue """ - # pylint: disable-msg=E1101 + # pylint: disable=E1101 # as OP_ID is dynamically defined WITH_LU = True OP_PARAMS = [ @@ -371,7 +503,13 @@ class OpCode(BaseOpCode): ("debug_level", None, ht.TOr(ht.TNone, ht.TPositiveInt), "Debug level"), ("priority", constants.OP_PRIO_DEFAULT, ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"), + (DEPEND_ATTR, None, _BuildJobDepCheck(True), + "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)" + " job IDs can be used"), + (COMMENT_ATTR, None, ht.TMaybeString, + "Comment describing the purpose of the opcode"), ] + OP_RESULT = None def __getstate__(self): """Specialized getstate for opcodes. @@ -438,6 +576,20 @@ class OpCode(BaseOpCode): txt = "%s(%s)" % (txt, field_value) return txt + def TinySummary(self): + """Generates a compact summary description of the opcode. + + """ + assert self.OP_ID.startswith("OP_") + + text = self.OP_ID[3:] + + for (prefix, supplement) in _SUMMARY_PREFIX.items(): + if text.startswith(prefix): + return supplement + text[len(prefix):] + + return text + # cluster opcodes @@ -464,7 +616,35 @@ class OpClusterQuery(OpCode): class OpClusterVerify(OpCode): - """Verify the cluster state. + """Submits all jobs necessary to verify the cluster. + + """ + OP_PARAMS = [ + _PDebugSimulateErrors, + _PErrorCodes, + _PSkipChecks, + _PIgnoreErrors, + _PVerbose, + ("group_name", None, ht.TMaybeString, "Group to verify") + ] + OP_RESULT = TJobIdListOnly + + +class OpClusterVerifyConfig(OpCode): + """Verify the cluster config. + + """ + OP_PARAMS = [ + _PDebugSimulateErrors, + _PErrorCodes, + _PIgnoreErrors, + _PVerbose, + ] + OP_RESULT = ht.TBool + + +class OpClusterVerifyGroup(OpCode): + """Run verify on a node group from the cluster. @type skip_checks: C{list} @ivar skip_checks: steps to be skipped from the verify process; this @@ -473,23 +653,30 @@ class OpClusterVerify(OpCode): only L{constants.VERIFY_NPLUSONE_MEM} can be passed """ + OP_DSC_FIELD = "group_name" OP_PARAMS = [ - ("skip_checks", ht.EmptyList, - ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS)), None), - ("verbose", False, ht.TBool, None), - ("error_codes", False, ht.TBool, None), - ("debug_simulate_errors", False, ht.TBool, None), + _PGroupName, + _PDebugSimulateErrors, + _PErrorCodes, + _PSkipChecks, + _PIgnoreErrors, + _PVerbose, ] + OP_RESULT = ht.TBool class OpClusterVerifyDisks(OpCode): """Verify the cluster disks. - Parameters: none + """ + OP_RESULT = TJobIdListOnly + + +class OpGroupVerifyDisks(OpCode): + """Verifies the status of all disks in a node group. - Result: a tuple of four elements: - - list of node names with bad data returned (unreachable, etc.) - - dict of node names with broken volume groups (values: error msg) + Result: a tuple of three elements: + - dict of node names with issues (values: error msg) - list of instances with degraded disks (that should be activated) - dict of instances with missing logical volumes (values: (node, vol) pairs with details about the missing volumes) @@ -503,6 +690,16 @@ class OpClusterVerifyDisks(OpCode): consideration. This might need to be revisited in the future. """ + OP_DSC_FIELD = "group_name" + OP_PARAMS = [ + _PGroupName, + ] + OP_RESULT = \ + ht.TAnd(ht.TIsLength(3), + ht.TItems([ht.TDictOf(ht.TString, ht.TString), + ht.TListOf(ht.TString), + ht.TDictOf(ht.TString, + ht.TListOf(ht.TListOf(ht.TString)))])) class OpClusterRepairDiskSizes(OpCode): @@ -572,6 +769,7 @@ class OpClusterSetParams(OpCode): ("osparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict), ht.TNone), "Cluster-wide OS parameter defaults"), + _PDiskParams, ("candidate_pool_size", None, ht.TOr(ht.TStrictPositiveInt, ht.TNone), "Master candidate pool size"), ("uid_pool", None, ht.NoType, @@ -594,6 +792,8 @@ class OpClusterSetParams(OpCode): "Default iallocator for cluster"), ("master_netdev", None, ht.TOr(ht.TString, ht.TNone), "Master network device"), + ("master_netmask", None, ht.TOr(ht.TInt, ht.TNone), + "Netmask of the master IP"), ("reserved_lvs", None, ht.TOr(ht.TListOf(ht.TNonEmptyString), ht.TNone), "List of reserved LVs"), ("hidden_os", None, _TestClusterOsList, @@ -604,6 +804,8 @@ class OpClusterSetParams(OpCode): "Modify list of blacklisted operating systems. Each modification must have" " two items, the operation and the OS name. The operation can be" " ``%s`` or ``%s``." % (constants.DDM_ADD, constants.DDM_REMOVE)), + ("use_external_mip_script", None, ht.TMaybeBool, + "Whether to use an external master IP address setup script"), ] @@ -613,21 +815,33 @@ class OpClusterRedistConf(OpCode): """ +class OpClusterActivateMasterIp(OpCode): + """Activate the master IP on the master node. + + """ + + +class OpClusterDeactivateMasterIp(OpCode): + """Deactivate the master IP on the master node. + + """ + + class OpQuery(OpCode): """Query for resources/items. - @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY} + @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP} @ivar fields: List of fields to retrieve - @ivar filter: Query filter + @ivar qfilter: Query filter """ + OP_DSC_FIELD = "what" OP_PARAMS = [ - ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY), - "Resource(s) to query for"), + _PQueryWhat, + _PUseLocking, ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), "Requested fields"), - ("filter", None, ht.TOr(ht.TNone, - ht.TListOf(ht.TOr(ht.TNonEmptyString, ht.TList))), + ("qfilter", None, ht.TOr(ht.TNone, ht.TListOf), "Query filter"), ] @@ -635,24 +849,31 @@ class OpQuery(OpCode): class OpQueryFields(OpCode): """Query for available resource/item fields. - @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY} + @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP} @ivar fields: List of fields to retrieve """ + OP_DSC_FIELD = "what" OP_PARAMS = [ - ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY), None), - ("fields", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), None), + _PQueryWhat, + ("fields", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), + "Requested fields; if not given, all are returned"), ] class OpOobCommand(OpCode): """Interact with OOB.""" OP_PARAMS = [ - ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), - ("command", None, ht.TElemOf(constants.OOB_COMMANDS), None), - ("timeout", constants.OOB_TIMEOUT, ht.TInt, None), - ("ignore_status", False, ht.TBool, None), - ("force_master", False, ht.TBool, None), + ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), + "List of nodes to run the OOB command against"), + ("command", None, ht.TElemOf(constants.OOB_COMMANDS), + "OOB command to be run"), + ("timeout", constants.OOB_TIMEOUT, ht.TInt, + "Timeout before the OOB helper will be terminated"), + ("ignore_status", False, ht.TBool, + "Ignores the node offline status for power off"), + ("power_delay", constants.OOB_POWER_DELAY, ht.TPositiveFloat, + "Time in seconds to wait between powering on nodes"), ] @@ -789,6 +1010,7 @@ class OpNodeSetParams(OpCode): ("powered", None, ht.TMaybeBool, "Whether the node should be marked as powered"), ] + OP_RESULT = _TSetParamsResult class OpNodePowercycle(OpCode): @@ -807,17 +1029,25 @@ class OpNodeMigrate(OpCode): _PNodeName, _PMigrationMode, _PMigrationLive, + _PMigrationTargetNode, + ("iallocator", None, ht.TMaybeString, + "Iallocator for deciding the target node for shared-storage instances"), ] + OP_RESULT = TJobIdListOnly -class OpNodeEvacStrategy(OpCode): - """Compute the evacuation strategy for a list of nodes.""" - OP_DSC_FIELD = "nodes" +class OpNodeEvacuate(OpCode): + """Evacuate instances off a number of nodes.""" + OP_DSC_FIELD = "node_name" OP_PARAMS = [ - ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), None), - ("remote_node", None, ht.TMaybeString, None), - ("iallocator", None, ht.TMaybeString, None), + _PEarlyRelease, + _PNodeName, + ("remote_node", None, ht.TMaybeString, "New secondary node"), + ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"), + ("mode", ht.NoDefault, ht.TElemOf(constants.NODE_EVAC_MODES), + "Node evacuation mode"), ] + OP_RESULT = TJobIdListOnly # instance opcodes @@ -841,8 +1071,19 @@ class OpInstanceCreate(OpCode): _PWaitForSync, _PNameCheck, ("beparams", ht.EmptyDict, ht.TDict, "Backend parameters for instance"), - ("disks", ht.NoDefault, ht.TListOf(ht.TDict), "Disk descriptions"), - ("disk_template", ht.NoDefault, _CheckDiskTemplate, "Disk template"), + ("disks", ht.NoDefault, + # TODO: Generate check from constants.IDISK_PARAMS_TYPES + ht.TListOf(ht.TDictOf(ht.TElemOf(constants.IDISK_PARAMS), + ht.TOr(ht.TNonEmptyString, ht.TInt))), + "Disk descriptions, for example ``[{\"%s\": 100}, {\"%s\": 5}]``;" + " each disk definition must contain a ``%s`` value and" + " can contain an optional ``%s`` value denoting the disk access mode" + " (%s)" % + (constants.IDISK_SIZE, constants.IDISK_SIZE, constants.IDISK_SIZE, + constants.IDISK_MODE, + " or ".join("``%s``" % i for i in sorted(constants.DISK_ACCESS_SET)))), + ("disk_template", ht.NoDefault, _BuildDiskTemplateCheck(True), + "Disk template"), ("file_driver", None, ht.TOr(ht.TNone, ht.TElemOf(constants.FILE_DRIVER)), "Driver for file-backed disks"), ("file_storage_dir", None, ht.TMaybeString, @@ -857,8 +1098,12 @@ class OpInstanceCreate(OpCode): ("ip_check", True, ht.TBool, _PIpCheckDoc), ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES), "Instance creation mode"), - ("nics", ht.NoDefault, ht.TListOf(ht.TDict), - "List of NIC (network interface) definitions"), + ("nics", ht.NoDefault, ht.TListOf(_TestNicDef), + "List of NIC (network interface) definitions, for example" + " ``[{}, {}, {\"%s\": \"198.51.100.4\"}]``; each NIC definition can" + " contain the optional values %s" % + (constants.INIC_IP, + ", ".join("``%s``" % i for i in sorted(constants.INIC_PARAMS)))), ("no_install", None, ht.TMaybeBool, "Do not install the OS (will disable automatic start)"), ("osparams", ht.EmptyDict, ht.TDict, "OS parameters for instance"), @@ -870,13 +1115,16 @@ class OpInstanceCreate(OpCode): ("source_instance_name", None, ht.TMaybeString, "Source instance name (remote import only)"), ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, - ht.TPositiveInt, "How long source instance was given to shut down"), + ht.TPositiveInt, + "How long source instance was given to shut down (remote import only)"), ("source_x509_ca", None, ht.TMaybeString, "Source X509 CA in PEM format (remote import only)"), ("src_node", None, ht.TMaybeString, "Source node for import"), ("src_path", None, ht.TMaybeString, "Source directory for import"), ("start", True, ht.TBool, "Whether to start instance after creation"), + ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Instance tags"), ] + OP_RESULT = ht.Comment("instance nodes")(ht.TListOf(ht.TNonEmptyString)) class OpInstanceReinstall(OpCode): @@ -909,6 +1157,7 @@ class OpInstanceRename(OpCode): ("new_name", ht.NoDefault, ht.TNonEmptyString, "New instance name"), ("ip_check", False, ht.TBool, _PIpCheckDoc), ] + OP_RESULT = ht.Comment("New instance name")(ht.TNonEmptyString) class OpInstanceStartup(OpCode): @@ -921,6 +1170,8 @@ class OpInstanceStartup(OpCode): ("hvparams", ht.EmptyDict, ht.TDict, "Temporary hypervisor parameters, hypervisor-dependent"), ("beparams", ht.EmptyDict, ht.TDict, "Temporary backend parameters"), + _PNoRemember, + _PStartupPaused, ] @@ -932,6 +1183,7 @@ class OpInstanceShutdown(OpCode): _PIgnoreOfflineNodes, ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TPositiveInt, "How long to wait for instance to shut down"), + _PNoRemember, ] @@ -953,6 +1205,7 @@ class OpInstanceReplaceDisks(OpCode): OP_DSC_FIELD = "instance_name" OP_PARAMS = [ _PInstanceName, + _PEarlyRelease, ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES), "Replacement mode"), ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt), @@ -960,8 +1213,6 @@ class OpInstanceReplaceDisks(OpCode): ("remote_node", None, ht.TMaybeString, "New secondary node"), ("iallocator", None, ht.TMaybeString, "Iallocator for deciding new secondary node"), - ("early_release", False, ht.TBool, - "Whether to release locks as soon as possible"), ] @@ -972,6 +1223,9 @@ class OpInstanceFailover(OpCode): _PInstanceName, _PShutdownTimeout, _PIgnoreConsistency, + _PMigrationTargetNode, + ("iallocator", None, ht.TMaybeString, + "Iallocator for deciding the target node for shared-storage instances"), ] @@ -990,8 +1244,13 @@ class OpInstanceMigrate(OpCode): _PInstanceName, _PMigrationMode, _PMigrationLive, + _PMigrationTargetNode, ("cleanup", False, ht.TBool, "Whether a previously failed migration should be cleaned up"), + ("iallocator", None, ht.TMaybeString, + "Iallocator for deciding the target node for shared-storage instances"), + ("allow_failover", False, ht.TBool, + "Whether we can fallback to failover if migration is not possible"), ] @@ -1010,6 +1269,7 @@ class OpInstanceMove(OpCode): _PInstanceName, _PShutdownTimeout, ("target_node", ht.NoDefault, ht.TNonEmptyString, "Target node"), + _PIgnoreConsistency, ] @@ -1040,12 +1300,14 @@ class OpInstanceDeactivateDisks(OpCode): class OpInstanceRecreateDisks(OpCode): - """Deactivate an instance's disks.""" + """Recreate an instance's disks.""" OP_DSC_FIELD = "instance_name" OP_PARAMS = [ _PInstanceName, ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt), "List of disk indexes"), + ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), + "New instance nodes, if relocation is desired"), ] @@ -1062,8 +1324,12 @@ class OpInstanceQuery(OpCode): class OpInstanceQueryData(OpCode): """Compute the run-time status of instances.""" OP_PARAMS = [ - ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), - ("static", False, ht.TBool, None), + _PUseLocking, + ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), + "Instance names"), + ("static", False, ht.TBool, + "Whether to only return configuration data without querying" + " nodes"), ] @@ -1074,6 +1340,7 @@ class OpInstanceSetParams(OpCode): _PInstanceName, _PForce, _PForceVariant, + # TODO: Use _TestNicDef ("nics", ht.EmptyList, ht.TList, "List of NIC changes. Each item is of the form ``(op, settings)``." " ``op`` can be ``%s`` to add a new NIC with the specified settings," @@ -1084,14 +1351,21 @@ class OpInstanceSetParams(OpCode): ("beparams", ht.EmptyDict, ht.TDict, "Per-instance backend parameters"), ("hvparams", ht.EmptyDict, ht.TDict, "Per-instance hypervisor parameters, hypervisor-dependent"), - ("disk_template", None, ht.TOr(ht.TNone, _CheckDiskTemplate), + ("disk_template", None, ht.TOr(ht.TNone, _BuildDiskTemplateCheck(False)), "Disk template for instance"), ("remote_node", None, ht.TMaybeString, "Secondary node (used when changing disk template)"), ("os_name", None, ht.TMaybeString, "Change instance's OS name. Does not reinstall the instance."), ("osparams", None, ht.TMaybeDict, "Per-instance OS parameters"), + ("wait_for_sync", True, ht.TBool, + "Whether to wait for the disk to synchronize, when changing template"), + ("offline_inst", False, ht.TBool, + "Whether to turn off the down instance completely"), + ("online_inst", False, ht.TBool, + "Whether to enable the offline instance"), ] + OP_RESULT = _TSetParamsResult class OpInstanceGrowDisk(OpCode): @@ -1106,6 +1380,19 @@ class OpInstanceGrowDisk(OpCode): ] +class OpInstanceChangeGroup(OpCode): + """Moves an instance to another node group.""" + OP_DSC_FIELD = "instance_name" + OP_PARAMS = [ + _PInstanceName, + _PEarlyRelease, + ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"), + ("target_groups", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), + "Destination group names or UUIDs (defaults to \"all but current group\""), + ] + OP_RESULT = TJobIdListOnly + + # Node group opcodes class OpGroupAdd(OpCode): @@ -1115,6 +1402,7 @@ class OpGroupAdd(OpCode): _PGroupName, _PNodeGroupAllocPolicy, _PGroupNodeParams, + _PDiskParams, ] @@ -1145,7 +1433,9 @@ class OpGroupSetParams(OpCode): _PGroupName, _PNodeGroupAllocPolicy, _PGroupNodeParams, + _PDiskParams, ] + OP_RESULT = _TSetParamsResult class OpGroupRemove(OpCode): @@ -1158,11 +1448,24 @@ class OpGroupRemove(OpCode): class OpGroupRename(OpCode): """Rename a node group in the cluster.""" - OP_DSC_FIELD = "old_name" OP_PARAMS = [ - ("old_name", ht.NoDefault, ht.TNonEmptyString, None), - ("new_name", ht.NoDefault, ht.TNonEmptyString, None), + _PGroupName, + ("new_name", ht.NoDefault, ht.TNonEmptyString, "New group name"), + ] + OP_RESULT = ht.Comment("New group name")(ht.TNonEmptyString) + + +class OpGroupEvacuate(OpCode): + """Evacuate a node group in the cluster.""" + OP_DSC_FIELD = "group_name" + OP_PARAMS = [ + _PGroupName, + _PEarlyRelease, + ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"), + ("target_groups", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), + "Destination group names or UUIDs"), ] + OP_RESULT = TJobIdListOnly # OS opcodes @@ -1284,6 +1587,7 @@ class OpTagsDel(OpCode): ("name", ht.NoDefault, ht.TMaybeString, None), ] + # Test opcodes class OpTestDelay(OpCode): """Sleeps for a configured amount of time. @@ -1308,7 +1612,7 @@ class OpTestDelay(OpCode): """ OP_DSC_FIELD = "duration" OP_PARAMS = [ - ("duration", ht.NoDefault, ht.TFloat, None), + ("duration", ht.NoDefault, ht.TNumber, None), ("on_master", True, ht.TBool, None), ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), ("repeat", 0, ht.TPositiveInt, None), @@ -1333,17 +1637,21 @@ class OpTestAllocator(OpCode): ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES), None), ("name", ht.NoDefault, ht.TNonEmptyString, None), ("nics", ht.NoDefault, ht.TOr(ht.TNone, ht.TListOf( - ht.TDictOf(ht.TElemOf(["mac", "ip", "bridge"]), + ht.TDictOf(ht.TElemOf([constants.INIC_MAC, constants.INIC_IP, "bridge"]), ht.TOr(ht.TNone, ht.TNonEmptyString)))), None), ("disks", ht.NoDefault, ht.TOr(ht.TNone, ht.TList), None), ("hypervisor", None, ht.TMaybeString, None), ("allocator", None, ht.TMaybeString, None), ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), - ("mem_size", None, ht.TOr(ht.TNone, ht.TPositiveInt), None), + ("memory", None, ht.TOr(ht.TNone, ht.TPositiveInt), None), ("vcpus", None, ht.TOr(ht.TNone, ht.TPositiveInt), None), ("os", None, ht.TMaybeString, None), ("disk_template", None, ht.TMaybeString, None), - ("evac_nodes", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), + ("instances", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), + None), + ("evac_mode", None, + ht.TOr(ht.TNone, ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)), None), + ("target_groups", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), None), ] @@ -1368,6 +1676,7 @@ class OpTestDummy(OpCode): ("result", ht.NoDefault, ht.NoType, None), ("messages", ht.NoDefault, ht.NoType, None), ("fail", ht.NoDefault, ht.NoType, None), + ("submit_jobs", None, ht.NoType, None), ] WITH_LU = False