X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/b247c6fca8c673282a0210cf90e5a0921c24fabc..fb2865ae4e5162e7dc9bffd9975073d94fda8de8:/lib/opcodes.py diff --git a/lib/opcodes.py b/lib/opcodes.py index bb9ebe5..bd8964d 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 @@ -128,6 +128,15 @@ _PMigrationTargetNode = ("target_node", None, ht.TMaybeString, _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") #: OP_ID conversion regular expression _OPID_RE = re.compile("([a-z])([A-Z])") @@ -135,7 +144,7 @@ _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))))) @@ -144,6 +153,15 @@ _TestClusterOsList = ht.TOr(ht.TNone, _TestNicDef = ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS), ht.TOr(ht.TNone, ht.TNonEmptyString)) +_TSetParamsResultItemItems = [ + ht.Comment("name of changed parameter")(ht.TNonEmptyString), + ht.TAny, + ] + +_TSetParamsResult = \ + ht.TListOf(ht.TAnd(ht.TIsLength(len(_TSetParamsResultItemItems)), + ht.TItems(_TSetParamsResultItemItems))) + _SUMMARY_PREFIX = { "CLUSTER_": "C_", "GROUP_": "G_", @@ -154,6 +172,9 @@ _SUMMARY_PREFIX = { #: 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. @@ -278,7 +299,7 @@ class BaseOpCode(object): field handling. """ - # pylint: disable-msg=E1101 + # pylint: disable=E1101 # as OP_ID is dynamically defined __metaclass__ = _AutoOpParamSlots @@ -416,6 +437,20 @@ def _BuildJobDepCheck(relative): 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. @@ -430,6 +465,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 @@ -437,7 +473,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 = [ @@ -448,7 +484,10 @@ class OpCode(BaseOpCode): (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. @@ -554,15 +593,30 @@ class OpClusterQuery(OpCode): """Query cluster information.""" +class OpClusterVerify(OpCode): + """Submits all jobs necessary to verify the cluster. + + """ + OP_PARAMS = [ + _PDebugSimulateErrors, + _PErrorCodes, + _PSkipChecks, + _PVerbose, + ("group_name", None, ht.TMaybeString, "Group to verify") + ] + OP_RESULT = TJobIdListOnly + + class OpClusterVerifyConfig(OpCode): """Verify the cluster config. """ OP_PARAMS = [ - ("verbose", False, ht.TBool, None), - ("error_codes", False, ht.TBool, None), - ("debug_simulate_errors", False, ht.TBool, None), + _PDebugSimulateErrors, + _PErrorCodes, + _PVerbose, ] + OP_RESULT = ht.TBool class OpClusterVerifyGroup(OpCode): @@ -577,23 +631,27 @@ class OpClusterVerifyGroup(OpCode): """ OP_DSC_FIELD = "group_name" OP_PARAMS = [ - ("group_name", ht.NoDefault, ht.TNonEmptyString, None), - ("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, + _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) @@ -607,6 +665,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): @@ -725,8 +793,10 @@ class OpQuery(OpCode): @ivar filter: Query filter """ + OP_DSC_FIELD = "what" OP_PARAMS = [ _PQueryWhat, + _PUseLocking, ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), "Requested fields"), ("filter", None, ht.TOr(ht.TNone, ht.TListOf), @@ -741,6 +811,7 @@ class OpQueryFields(OpCode): @ivar fields: List of fields to retrieve """ + OP_DSC_FIELD = "what" OP_PARAMS = [ _PQueryWhat, ("fields", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), @@ -897,6 +968,7 @@ class OpNodeSetParams(OpCode): ("powered", None, ht.TMaybeBool, "Whether the node should be marked as powered"), ] + OP_RESULT = _TSetParamsResult class OpNodePowercycle(OpCode): @@ -932,6 +1004,7 @@ class OpNodeEvacuate(OpCode): ("mode", ht.NoDefault, ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES), "Node evacuation mode"), ] + OP_RESULT = TJobIdListOnly # instance opcodes @@ -1007,6 +1080,7 @@ class OpInstanceCreate(OpCode): ("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): @@ -1039,6 +1113,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): @@ -1242,6 +1317,7 @@ class OpInstanceSetParams(OpCode): ("wait_for_sync", True, ht.TBool, "Whether to wait for the disk to synchronize, when changing template"), ] + OP_RESULT = _TSetParamsResult class OpInstanceGrowDisk(OpCode): @@ -1256,6 +1332,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): @@ -1296,6 +1385,7 @@ class OpGroupSetParams(OpCode): _PNodeGroupAllocPolicy, _PGroupNodeParams, ] + OP_RESULT = _TSetParamsResult class OpGroupRemove(OpCode): @@ -1312,6 +1402,20 @@ class OpGroupRename(OpCode): _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 @@ -1433,6 +1537,7 @@ class OpTagsDel(OpCode): ("name", ht.NoDefault, ht.TMaybeString, None), ] + # Test opcodes class OpTestDelay(OpCode): """Sleeps for a configured amount of time. @@ -1492,8 +1597,6 @@ class OpTestAllocator(OpCode): ("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)), - None), ("instances", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), None), ("evac_mode", None,