X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/1ce03fb1f2453e8a55941bcc95ab9c934a631fd1..b09cce6429a36523e37b902023d037f9258b7296:/lib/opcodes.py diff --git a/lib/opcodes.py b/lib/opcodes.py index e00d651..2995bc2 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -31,15 +31,15 @@ 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 constants from ganeti import errors from ganeti import ht +from ganeti import objects # Common opcode attributes @@ -80,10 +80,12 @@ _PMigrationLive = ("live", None, ht.TMaybeBool, "Legacy setting for live migration, do not use") #: Tag type -_PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES), None) +_PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES), + "Tag kind") #: List of tag strings -_PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), None) +_PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), + "List of tag names") _PForceVariant = ("force_variant", False, ht.TBool, "Whether to force an unknown OS variant") @@ -91,6 +93,10 @@ _PForceVariant = ("force_variant", False, ht.TBool, _PWaitForSync = ("wait_for_sync", True, ht.TBool, "Whether to wait for the disk to synchronize") +_PWaitForSyncFalse = ("wait_for_sync", False, ht.TBool, + "Whether to wait for the disk to synchronize" + " (defaults to false)") + _PIgnoreConsistency = ("ignore_consistency", False, ht.TBool, "Whether to ignore disk consistency") @@ -128,21 +134,83 @@ _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") +_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") + +# Parameters for node resource model +_PHvState = ("hv_state", None, ht.TMaybeDict, "Set hypervisor states") +_PDiskState = ("disk_state", None, ht.TMaybeDict, "Set disk states") + + +_PIgnoreIpolicy = ("ignore_ipolicy", False, ht.TBool, + "Whether to ignore ipolicy violations") + +# Allow runtime changes while migrating +_PAllowRuntimeChgs = ("allow_runtime_changes", True, ht.TBool, + "Allow runtime changes (eg. memory ballooning)") + #: 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.TElemOf(constants.DDMS_VALUES))))) +_TestClusterOsListItem = \ + ht.TAnd(ht.TIsLength(2), ht.TItems([ + ht.TElemOf(constants.DDMS_VALUES), + ht.TNonEmptyString, + ])) +_TestClusterOsList = ht.TMaybeListOf(_TestClusterOsListItem) # 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)) +_TestNicDef = \ + ht.Comment("NIC parameters")(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))) + +# TODO: Generate check from constants.IDISK_PARAMS_TYPES (however, not all users +# of this check support all parameters) +_TDiskParams = \ + ht.Comment("Disk parameters")(ht.TDictOf(ht.TElemOf(constants.IDISK_PARAMS), + ht.TOr(ht.TNonEmptyString, ht.TInt))) + +_TQueryRow = \ + ht.TListOf(ht.TAnd(ht.TIsLength(2), + ht.TItems([ht.TElemOf(constants.RS_ALL), + ht.TAny]))) + +_TQueryResult = ht.TListOf(_TQueryRow) + +_TOldQueryRow = ht.TListOf(ht.TAny) + +_TOldQueryResult = ht.TListOf(_TOldQueryRow) + _SUMMARY_PREFIX = { "CLUSTER_": "C_", @@ -179,6 +247,28 @@ def _NameToId(name): return "_".join(n.upper() for n in elems) +def _GenerateObjectTypeCheck(obj, fields_types): + """Helper to generate type checks for objects. + + @param obj: The object to generate type checks + @param fields_types: The fields and their types as a dict + @return: A ht type check function + + """ + assert set(obj.GetAllSlots()) == set(fields_types.keys()), \ + "%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys())) + return ht.TStrictDict(True, True, fields_types) + + +_TQueryFieldDef = \ + _GenerateObjectTypeCheck(objects.QueryFieldDefinition, { + "name": ht.TNonEmptyString, + "title": ht.TNonEmptyString, + "kind": ht.TElemOf(constants.QFT_ALL), + "doc": ht.TNonEmptyString, + }) + + def RequireFileStorage(): """Checks that file storage is enabled. @@ -219,8 +309,20 @@ def _CheckFileStorage(value): 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): @@ -281,7 +383,7 @@ class BaseOpCode(object): field handling. """ - # pylint: disable-msg=E1101 + # pylint: disable=E1101 # as OP_ID is dynamically defined __metaclass__ = _AutoOpParamSlots @@ -414,13 +516,24 @@ def _BuildJobDepCheck(relative): ht.TItems([job_id, ht.TListOf(ht.TElemOf(constants.JOBS_FINALIZED))])) - return ht.TOr(ht.TNone, ht.TListOf(job_dep)) + return ht.TMaybeListOf(job_dep) TNoRelativeJobDependencies = _BuildJobDepCheck(False) #: List of submission status and job ID as returned by C{SubmitManyJobs} -TJobIdList = ht.TListOf(ht.TItems([ht.TBool, ht.TOr(ht.TString, ht.TJobId)])) +_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): @@ -444,7 +557,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 = [ @@ -454,7 +567,8 @@ class OpCode(BaseOpCode): 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"), + " job IDs can be used; see :doc:`design document `" + " for details"), (COMMENT_ATTR, None, ht.TMaybeString, "Comment describing the purpose of the opcode"), ] @@ -549,6 +663,7 @@ class OpClusterPostInit(OpCode): after the cluster has been initialized. """ + OP_RESULT = ht.TBool class OpClusterDestroy(OpCode): @@ -558,10 +673,27 @@ class OpClusterDestroy(OpCode): lost after the execution of this opcode. """ + OP_RESULT = ht.TNonEmptyString class OpClusterQuery(OpCode): """Query cluster information.""" + OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TAny) + + +class OpClusterVerify(OpCode): + """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): @@ -569,10 +701,12 @@ class OpClusterVerifyConfig(OpCode): """ OP_PARAMS = [ - ("verbose", False, ht.TBool, None), - ("error_codes", False, ht.TBool, None), - ("debug_simulate_errors", False, ht.TBool, None), + _PDebugSimulateErrors, + _PErrorCodes, + _PIgnoreErrors, + _PVerbose, ] + OP_RESULT = ht.TBool class OpClusterVerifyGroup(OpCode): @@ -587,22 +721,21 @@ 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, + _PIgnoreErrors, + _PVerbose, ] + OP_RESULT = ht.TBool class OpClusterVerifyDisks(OpCode): """Verify the cluster disks. """ - OP_RESULT = ht.TStrictDict(True, True, { - constants.JOB_IDS_KEY: TJobIdList, - }) + OP_RESULT = TJobIdListOnly class OpGroupVerifyDisks(OpCode): @@ -631,7 +764,8 @@ class OpGroupVerifyDisks(OpCode): ht.TAnd(ht.TIsLength(3), ht.TItems([ht.TDictOf(ht.TString, ht.TString), ht.TListOf(ht.TString), - ht.TDictOf(ht.TString, ht.TListOf(ht.TString))])) + ht.TDictOf(ht.TString, + ht.TListOf(ht.TListOf(ht.TString)))])) class OpClusterRepairDiskSizes(OpCode): @@ -653,6 +787,10 @@ class OpClusterRepairDiskSizes(OpCode): OP_PARAMS = [ ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), ] + OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3), + ht.TItems([ht.TNonEmptyString, + ht.TPositiveInt, + ht.TPositiveInt]))) class OpClusterConfigQuery(OpCode): @@ -660,6 +798,7 @@ class OpClusterConfigQuery(OpCode): OP_PARAMS = [ _POutputFields ] + OP_RESULT = ht.TListOf(ht.TAny) class OpClusterRename(OpCode): @@ -675,6 +814,7 @@ class OpClusterRename(OpCode): OP_PARAMS = [ ("name", ht.NoDefault, ht.TNonEmptyString, None), ] + OP_RESULT = ht.TNonEmptyString class OpClusterSetParams(OpCode): @@ -685,6 +825,8 @@ class OpClusterSetParams(OpCode): """ OP_PARAMS = [ + _PHvState, + _PDiskState, ("vg_name", None, ht.TMaybeString, "Volume group name"), ("enabled_hypervisors", None, ht.TOr(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)), ht.TTrue), @@ -701,6 +843,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, @@ -718,28 +861,50 @@ class OpClusterSetParams(OpCode): "Whether to wipe disks before allocating them to instances"), ("nicparams", None, ht.TMaybeDict, "Cluster-wide NIC parameter defaults"), ("ndparams", None, ht.TMaybeDict, "Cluster-wide node parameter defaults"), + ("ipolicy", None, ht.TMaybeDict, + "Cluster-wide :ref:`instance policy ` specs"), ("drbd_helper", None, ht.TOr(ht.TString, ht.TNone), "DRBD helper program"), ("default_iallocator", None, ht.TOr(ht.TString, ht.TNone), "Default iallocator for cluster"), ("master_netdev", None, ht.TOr(ht.TString, ht.TNone), "Master network device"), - ("reserved_lvs", None, ht.TOr(ht.TListOf(ht.TNonEmptyString), ht.TNone), + ("master_netmask", None, ht.TOr(ht.TInt, ht.TNone), + "Netmask of the master IP"), + ("reserved_lvs", None, ht.TMaybeListOf(ht.TNonEmptyString), "List of reserved LVs"), ("hidden_os", None, _TestClusterOsList, - "Modify list of hidden 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)), + "Modify list of hidden 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)), ("blacklisted_os", None, _TestClusterOsList, - "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)), + "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"), ] + OP_RESULT = ht.TNone class OpClusterRedistConf(OpCode): """Force a full push of the cluster configuration. """ + OP_RESULT = ht.TNone + + +class OpClusterActivateMasterIp(OpCode): + """Activate the master IP on the master node. + + """ + OP_RESULT = ht.TNone + + +class OpClusterDeactivateMasterIp(OpCode): + """Deactivate the master IP on the master node. + + """ + OP_RESULT = ht.TNone class OpQuery(OpCode): @@ -747,16 +912,23 @@ class OpQuery(OpCode): @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 = [ _PQueryWhat, + _PUseLocking, ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), "Requested fields"), - ("filter", None, ht.TOr(ht.TNone, ht.TListOf), + ("qfilter", None, ht.TOr(ht.TNone, ht.TList), "Query filter"), ] + OP_RESULT = \ + _GenerateObjectTypeCheck(objects.QueryResponse, { + "fields": ht.TListOf(_TQueryFieldDef), + "data": _TQueryResult, + }) class OpQueryFields(OpCode): @@ -766,11 +938,16 @@ 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)), + ("fields", None, ht.TMaybeListOf(ht.TNonEmptyString), "Requested fields; if not given, all are returned"), ] + OP_RESULT = \ + _GenerateObjectTypeCheck(objects.QueryFieldsResponse, { + "fields": ht.TListOf(_TQueryFieldDef), + }) class OpOobCommand(OpCode): @@ -787,6 +964,8 @@ class OpOobCommand(OpCode): ("power_delay", constants.OOB_POWER_DELAY, ht.TPositiveFloat, "Time in seconds to wait between powering on nodes"), ] + # Fixme: Make it more specific with all the special cases in LUOobCommand + OP_RESULT = _TQueryResult # node opcodes @@ -803,6 +982,7 @@ class OpNodeRemove(OpCode): OP_PARAMS = [ _PNodeName, ] + OP_RESULT = ht.TNone class OpNodeAdd(OpCode): @@ -836,6 +1016,8 @@ class OpNodeAdd(OpCode): OP_DSC_FIELD = "node_name" OP_PARAMS = [ _PNodeName, + _PHvState, + _PDiskState, ("primary_ip", None, ht.NoType, "Primary IP address"), ("secondary_ip", None, ht.TMaybeString, "Secondary IP address"), ("readd", False, ht.TBool, "Whether node is re-added to cluster"), @@ -846,6 +1028,7 @@ class OpNodeAdd(OpCode): "Whether node can host instances"), ("ndparams", None, ht.TMaybeDict, "Node parameters"), ] + OP_RESULT = ht.TNone class OpNodeQuery(OpCode): @@ -856,6 +1039,7 @@ class OpNodeQuery(OpCode): ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Empty list to query all nodes, node names otherwise"), ] + OP_RESULT = _TOldQueryResult class OpNodeQueryvols(OpCode): @@ -865,6 +1049,7 @@ class OpNodeQueryvols(OpCode): ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Empty list to query all nodes, node names otherwise"), ] + OP_RESULT = ht.TListOf(ht.TAny) class OpNodeQueryStorage(OpCode): @@ -875,16 +1060,19 @@ class OpNodeQueryStorage(OpCode): ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "List of nodes"), ("name", None, ht.TMaybeString, "Storage name"), ] + OP_RESULT = _TOldQueryResult class OpNodeModifyStorage(OpCode): """Modifies the properies of a storage unit""" + OP_DSC_FIELD = "node_name" OP_PARAMS = [ _PNodeName, _PStorageType, _PStorageName, ("changes", ht.NoDefault, ht.TDict, "Requested changes"), ] + OP_RESULT = ht.TNone class OpRepairNodeStorage(OpCode): @@ -896,6 +1084,7 @@ class OpRepairNodeStorage(OpCode): _PStorageName, _PIgnoreConsistency, ] + OP_RESULT = ht.TNone class OpNodeSetParams(OpCode): @@ -904,6 +1093,8 @@ class OpNodeSetParams(OpCode): OP_PARAMS = [ _PNodeName, _PForce, + _PHvState, + _PDiskState, ("master_candidate", None, ht.TMaybeBool, "Whether the node should become a master candidate"), ("offline", None, ht.TMaybeBool, @@ -922,6 +1113,7 @@ class OpNodeSetParams(OpCode): ("powered", None, ht.TMaybeBool, "Whether the node should be marked as powered"), ] + OP_RESULT = _TSetParamsResult class OpNodePowercycle(OpCode): @@ -931,6 +1123,7 @@ class OpNodePowercycle(OpCode): _PNodeName, _PForce, ] + OP_RESULT = ht.TMaybeString class OpNodeMigrate(OpCode): @@ -941,9 +1134,12 @@ class OpNodeMigrate(OpCode): _PMigrationMode, _PMigrationLive, _PMigrationTargetNode, + _PAllowRuntimeChgs, + _PIgnoreIpolicy, ("iallocator", None, ht.TMaybeString, "Iallocator for deciding the target node for shared-storage instances"), ] + OP_RESULT = TJobIdListOnly class OpNodeEvacuate(OpCode): @@ -954,9 +1150,10 @@ class OpNodeEvacuate(OpCode): _PNodeName, ("remote_node", None, ht.TMaybeString, "New secondary node"), ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"), - ("mode", ht.NoDefault, ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES), + ("mode", ht.NoDefault, ht.TElemOf(constants.NODE_EVAC_MODES), "Node evacuation mode"), ] + OP_RESULT = TJobIdListOnly # instance opcodes @@ -979,11 +1176,9 @@ class OpInstanceCreate(OpCode): _PForceVariant, _PWaitForSync, _PNameCheck, + _PIgnoreIpolicy, ("beparams", ht.EmptyDict, ht.TDict, "Backend parameters for instance"), - ("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))), + ("disks", ht.NoDefault, ht.TListOf(_TDiskParams), "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" @@ -991,7 +1186,8 @@ class OpInstanceCreate(OpCode): (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, _CheckDiskTemplate, "Disk template"), + ("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, @@ -1032,6 +1228,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): @@ -1043,6 +1240,7 @@ class OpInstanceReinstall(OpCode): ("os_type", None, ht.TMaybeString, "Instance operating system"), ("osparams", None, ht.TMaybeDict, "Temporary OS parameters"), ] + OP_RESULT = ht.TNone class OpInstanceRemove(OpCode): @@ -1054,6 +1252,7 @@ class OpInstanceRemove(OpCode): ("ignore_failures", False, ht.TBool, "Whether to ignore failures during removal"), ] + OP_RESULT = ht.TNone class OpInstanceRename(OpCode): @@ -1064,6 +1263,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): @@ -1079,6 +1279,7 @@ class OpInstanceStartup(OpCode): _PNoRemember, _PStartupPaused, ] + OP_RESULT = ht.TNone class OpInstanceShutdown(OpCode): @@ -1091,6 +1292,7 @@ class OpInstanceShutdown(OpCode): "How long to wait for instance to shut down"), _PNoRemember, ] + OP_RESULT = ht.TNone class OpInstanceReboot(OpCode): @@ -1104,6 +1306,7 @@ class OpInstanceReboot(OpCode): ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES), "How to reboot instance"), ] + OP_RESULT = ht.TNone class OpInstanceReplaceDisks(OpCode): @@ -1112,6 +1315,7 @@ class OpInstanceReplaceDisks(OpCode): OP_PARAMS = [ _PInstanceName, _PEarlyRelease, + _PIgnoreIpolicy, ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES), "Replacement mode"), ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt), @@ -1120,6 +1324,7 @@ class OpInstanceReplaceDisks(OpCode): ("iallocator", None, ht.TMaybeString, "Iallocator for deciding new secondary node"), ] + OP_RESULT = ht.TNone class OpInstanceFailover(OpCode): @@ -1130,9 +1335,11 @@ class OpInstanceFailover(OpCode): _PShutdownTimeout, _PIgnoreConsistency, _PMigrationTargetNode, + _PIgnoreIpolicy, ("iallocator", None, ht.TMaybeString, "Iallocator for deciding the target node for shared-storage instances"), ] + OP_RESULT = ht.TNone class OpInstanceMigrate(OpCode): @@ -1151,6 +1358,8 @@ class OpInstanceMigrate(OpCode): _PMigrationMode, _PMigrationLive, _PMigrationTargetNode, + _PAllowRuntimeChgs, + _PIgnoreIpolicy, ("cleanup", False, ht.TBool, "Whether a previously failed migration should be cleaned up"), ("iallocator", None, ht.TMaybeString, @@ -1158,6 +1367,7 @@ class OpInstanceMigrate(OpCode): ("allow_failover", False, ht.TBool, "Whether we can fallback to failover if migration is not possible"), ] + OP_RESULT = ht.TNone class OpInstanceMove(OpCode): @@ -1174,9 +1384,11 @@ class OpInstanceMove(OpCode): OP_PARAMS = [ _PInstanceName, _PShutdownTimeout, + _PIgnoreIpolicy, ("target_node", ht.NoDefault, ht.TNonEmptyString, "Target node"), _PIgnoreConsistency, ] + OP_RESULT = ht.TNone class OpInstanceConsole(OpCode): @@ -1185,6 +1397,7 @@ class OpInstanceConsole(OpCode): OP_PARAMS = [ _PInstanceName ] + OP_RESULT = ht.TDict class OpInstanceActivateDisks(OpCode): @@ -1193,7 +1406,12 @@ class OpInstanceActivateDisks(OpCode): OP_PARAMS = [ _PInstanceName, ("ignore_size", False, ht.TBool, "Whether to ignore recorded size"), + _PWaitForSyncFalse, ] + OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3), + ht.TItems([ht.TNonEmptyString, + ht.TNonEmptyString, + ht.TNonEmptyString]))) class OpInstanceDeactivateDisks(OpCode): @@ -1203,18 +1421,29 @@ class OpInstanceDeactivateDisks(OpCode): _PInstanceName, _PForce, ] + OP_RESULT = ht.TNone class OpInstanceRecreateDisks(OpCode): - """Deactivate an instance's disks.""" + """Recreate an instance's disks.""" + _TDiskChanges = \ + ht.TAnd(ht.TIsLength(2), + ht.TItems([ht.Comment("Disk index")(ht.TPositiveInt), + ht.Comment("Parameters")(_TDiskParams)])) + OP_DSC_FIELD = "instance_name" OP_PARAMS = [ _PInstanceName, - ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt), - "List of disk indexes"), + ("disks", ht.EmptyList, + ht.TOr(ht.TListOf(ht.TPositiveInt), ht.TListOf(_TDiskChanges)), + "List of disk indexes (deprecated) or a list of tuples containing a disk" + " index and a possibly empty dictionary with disk parameter changes"), ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "New instance nodes, if relocation is desired"), + ("iallocator", None, ht.TMaybeString, + "Iallocator for deciding new nodes"), ] + OP_RESULT = ht.TNone class OpInstanceQuery(OpCode): @@ -1225,6 +1454,7 @@ class OpInstanceQuery(OpCode): ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Empty list to query all instances, instance names otherwise"), ] + OP_RESULT = _TOldQueryResult class OpInstanceQueryData(OpCode): @@ -1237,36 +1467,74 @@ class OpInstanceQueryData(OpCode): "Whether to only return configuration data without querying" " nodes"), ] + OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TDict) + + +def _TestInstSetParamsModList(fn): + """Generates a check for modification lists. + + """ + # Old format + # TODO: Remove in version 2.8 including support in LUInstanceSetParams + old_mod_item_fn = \ + ht.TAnd(ht.TIsLength(2), ht.TItems([ + ht.TOr(ht.TElemOf(constants.DDMS_VALUES), ht.TPositiveInt), + fn, + ])) + + # New format, supporting adding/removing disks/NICs at arbitrary indices + mod_item_fn = \ + ht.TAnd(ht.TIsLength(3), ht.TItems([ + ht.TElemOf(constants.DDMS_VALUES_WITH_MODIFY), + ht.Comment("Disk index, can be negative, e.g. -1 for last disk")(ht.TInt), + fn, + ])) + + return ht.TOr(ht.Comment("Recommended")(ht.TListOf(mod_item_fn)), + ht.Comment("Deprecated")(ht.TListOf(old_mod_item_fn))) class OpInstanceSetParams(OpCode): - """Change the parameters of an instance.""" + """Change the parameters of an instance. + + """ + TestNicModifications = _TestInstSetParamsModList(_TestNicDef) + TestDiskModifications = _TestInstSetParamsModList(_TDiskParams) + OP_DSC_FIELD = "instance_name" OP_PARAMS = [ _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," - " ``%s`` to remove the last NIC or a number to modify the settings" - " of the NIC with that index." % - (constants.DDM_ADD, constants.DDM_REMOVE)), - ("disks", ht.EmptyList, ht.TList, "List of disk changes. See ``nics``."), + _PIgnoreIpolicy, + ("nics", ht.EmptyList, TestNicModifications, + "List of NIC changes: each item is of the form ``(op, index, settings)``," + " ``op`` is one of ``%s``, ``%s`` or ``%s``, ``index`` can be either -1" + " to refer to the last position, or a zero-based index number; a" + " deprecated version of this parameter used the form ``(op, settings)``," + " where ``op`` can be ``%s`` to add a new NIC with the specified" + " settings, ``%s`` to remove the last NIC or a number to modify the" + " settings of the NIC with that index" % + (constants.DDM_ADD, constants.DDM_MODIFY, constants.DDM_REMOVE, + constants.DDM_ADD, constants.DDM_REMOVE)), + ("disks", ht.EmptyList, TestDiskModifications, + "List of disk changes; see ``nics``"), ("beparams", ht.EmptyDict, ht.TDict, "Per-instance backend parameters"), + ("runtime_mem", None, ht.TMaybeStrictPositiveInt, "New runtime memory"), ("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."), + "Change the instance's OS without reinstalling 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", None, ht.TMaybeBool, "Whether to mark instance as offline"), ] + OP_RESULT = _TSetParamsResult class OpInstanceGrowDisk(OpCode): @@ -1276,9 +1544,25 @@ class OpInstanceGrowDisk(OpCode): _PInstanceName, _PWaitForSync, ("disk", ht.NoDefault, ht.TInt, "Disk index"), - ("amount", ht.NoDefault, ht.TInt, + ("amount", ht.NoDefault, ht.TPositiveInt, "Amount of disk space to add (megabytes)"), + ("absolute", False, ht.TBool, + "Whether the amount parameter is an absolute target or a relative one"), ] + OP_RESULT = ht.TNone + + +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.TMaybeListOf(ht.TNonEmptyString), + "Destination group names or UUIDs (defaults to \"all but current group\""), + ] + OP_RESULT = TJobIdListOnly # Node group opcodes @@ -1290,7 +1574,13 @@ class OpGroupAdd(OpCode): _PGroupName, _PNodeGroupAllocPolicy, _PGroupNodeParams, + _PDiskParams, + _PHvState, + _PDiskState, + ("ipolicy", None, ht.TMaybeDict, + "Group-wide :ref:`instance policy ` specs"), ] + OP_RESULT = ht.TNone class OpGroupAssignNodes(OpCode): @@ -1302,6 +1592,7 @@ class OpGroupAssignNodes(OpCode): ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), "List of nodes to assign"), ] + OP_RESULT = ht.TNone class OpGroupQuery(OpCode): @@ -1311,6 +1602,7 @@ class OpGroupQuery(OpCode): ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Empty list to query all groups, group names otherwise"), ] + OP_RESULT = _TOldQueryResult class OpGroupSetParams(OpCode): @@ -1320,7 +1612,12 @@ class OpGroupSetParams(OpCode): _PGroupName, _PNodeGroupAllocPolicy, _PGroupNodeParams, + _PDiskParams, + _PHvState, + _PDiskState, + ("ipolicy", None, ht.TMaybeDict, "Group-wide instance policy specs"), ] + OP_RESULT = _TSetParamsResult class OpGroupRemove(OpCode): @@ -1329,6 +1626,7 @@ class OpGroupRemove(OpCode): OP_PARAMS = [ _PGroupName, ] + OP_RESULT = ht.TNone class OpGroupRename(OpCode): @@ -1337,6 +1635,7 @@ 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): @@ -1346,9 +1645,10 @@ class OpGroupEvacuate(OpCode): _PGroupName, _PEarlyRelease, ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"), - ("target_groups", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)), + ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), "Destination group names or UUIDs"), ] + OP_RESULT = TJobIdListOnly # OS opcodes @@ -1359,6 +1659,7 @@ class OpOsDiagnose(OpCode): ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Which operating systems to diagnose"), ] + OP_RESULT = _TOldQueryResult # Exports opcodes @@ -1369,6 +1670,9 @@ class OpBackupQuery(OpCode): ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Empty list to query all nodes, node names otherwise"), ] + OP_RESULT = ht.TDictOf(ht.TNonEmptyString, + ht.TOr(ht.Comment("False on error")(ht.TBool), + ht.TListOf(ht.TNonEmptyString))) class OpBackupPrepare(OpCode): @@ -1384,6 +1688,7 @@ class OpBackupPrepare(OpCode): ("mode", ht.NoDefault, ht.TElemOf(constants.EXPORT_MODES), "Export mode"), ] + OP_RESULT = ht.TOr(ht.TNone, ht.TDict) class OpBackupExport(OpCode): @@ -1422,6 +1727,11 @@ class OpBackupExport(OpCode): ("destination_x509_ca", None, ht.TMaybeString, "Destination X509 CA (remote export only)"), ] + OP_RESULT = \ + ht.TAnd(ht.TIsLength(2), ht.TItems([ + ht.Comment("Finalizing status")(ht.TBool), + ht.Comment("Status for every exported disk")(ht.TListOf(ht.TBool)), + ])) class OpBackupRemove(OpCode): @@ -1430,6 +1740,7 @@ class OpBackupRemove(OpCode): OP_PARAMS = [ _PInstanceName, ] + OP_RESULT = ht.TNone # Tags opcodes @@ -1438,17 +1749,26 @@ class OpTagsGet(OpCode): OP_DSC_FIELD = "name" OP_PARAMS = [ _PTagKind, + # Not using _PUseLocking as the default is different for historical reasons + ("use_locking", True, ht.TBool, "Whether to use synchronization"), # Name is only meaningful for nodes and instances - ("name", ht.NoDefault, ht.TMaybeString, None), + ("name", ht.NoDefault, ht.TMaybeString, + "Name of object to retrieve tags from"), ] + OP_RESULT = ht.TListOf(ht.TNonEmptyString) class OpTagsSearch(OpCode): """Searches the tags in the cluster for a given pattern.""" OP_DSC_FIELD = "pattern" OP_PARAMS = [ - ("pattern", ht.NoDefault, ht.TNonEmptyString, None), + ("pattern", ht.NoDefault, ht.TNonEmptyString, + "Search pattern (regular expression)"), ] + OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(2), ht.TItems([ + ht.TNonEmptyString, + ht.TNonEmptyString, + ]))) class OpTagsSet(OpCode): @@ -1457,8 +1777,10 @@ class OpTagsSet(OpCode): _PTagKind, _PTags, # Name is only meaningful for nodes and instances - ("name", ht.NoDefault, ht.TMaybeString, None), + ("name", ht.NoDefault, ht.TMaybeString, + "Name of object where tag(s) should be added"), ] + OP_RESULT = ht.TNone class OpTagsDel(OpCode): @@ -1467,8 +1789,11 @@ class OpTagsDel(OpCode): _PTagKind, _PTags, # Name is only meaningful for nodes and instances - ("name", ht.NoDefault, ht.TMaybeString, None), + ("name", ht.NoDefault, ht.TMaybeString, + "Name of object where tag(s) should be deleted"), ] + OP_RESULT = ht.TNone + # Test opcodes class OpTestDelay(OpCode): @@ -1518,9 +1843,12 @@ class OpTestAllocator(OpCode): ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS), None), ("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([constants.INIC_MAC, constants.INIC_IP, "bridge"]), - ht.TOr(ht.TNone, ht.TNonEmptyString)))), None), + ("nics", ht.NoDefault, + ht.TMaybeListOf(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), @@ -1529,14 +1857,10 @@ 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), + ("instances", None, ht.TMaybeListOf(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), + ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), None), ]