4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 This module implements the data structures which define the cluster
25 operations - the so-called opcodes.
27 Every operation which modifies the cluster state is expressed via
32 # this are practically structures, so disable the message about too
34 # pylint: disable=R0903
40 from ganeti import constants
41 from ganeti import errors
43 from ganeti import objects
46 # Common opcode attributes
48 #: output fields for a query operation
49 _POutputFields = ("output_fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
50 "Selected output fields")
52 #: the shutdown timeout
54 ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TPositiveInt,
55 "How long to wait for instance to shut down")
57 #: the force parameter
58 _PForce = ("force", False, ht.TBool, "Whether to force the operation")
60 #: a required instance name (for single-instance LUs)
61 _PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString,
64 #: Whether to ignore offline nodes
65 _PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool,
66 "Whether to ignore offline nodes")
68 #: a required node name (for single-node LUs)
69 _PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString, "Node name")
71 #: a required node group name (for single-group LUs)
72 _PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString, "Group name")
74 #: Migration type (live/non-live)
75 _PMigrationMode = ("mode", None,
76 ht.TOr(ht.TNone, ht.TElemOf(constants.HT_MIGRATION_MODES)),
79 #: Obsolete 'live' migration mode (boolean)
80 _PMigrationLive = ("live", None, ht.TMaybeBool,
81 "Legacy setting for live migration, do not use")
84 _PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES),
87 #: List of tag strings
88 _PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
91 _PForceVariant = ("force_variant", False, ht.TBool,
92 "Whether to force an unknown OS variant")
94 _PWaitForSync = ("wait_for_sync", True, ht.TBool,
95 "Whether to wait for the disk to synchronize")
97 _PIgnoreConsistency = ("ignore_consistency", False, ht.TBool,
98 "Whether to ignore disk consistency")
100 _PStorageName = ("name", ht.NoDefault, ht.TMaybeString, "Storage name")
102 _PUseLocking = ("use_locking", False, ht.TBool,
103 "Whether to use synchronization")
105 _PNameCheck = ("name_check", True, ht.TBool, "Whether to check name")
107 _PNodeGroupAllocPolicy = \
108 ("alloc_policy", None,
109 ht.TOr(ht.TNone, ht.TElemOf(constants.VALID_ALLOC_POLICIES)),
110 "Instance allocation policy")
112 _PGroupNodeParams = ("ndparams", None, ht.TMaybeDict,
113 "Default node parameters for group")
115 _PQueryWhat = ("what", ht.NoDefault, ht.TElemOf(constants.QR_VIA_OP),
116 "Resource(s) to query for")
118 _PEarlyRelease = ("early_release", False, ht.TBool,
119 "Whether to release locks as soon as possible")
121 _PIpCheckDoc = "Whether to ensure instance's IP address is inactive"
123 #: Do not remember instance state changes
124 _PNoRemember = ("no_remember", False, ht.TBool,
125 "Do not remember the state change")
127 #: Target node for instance migration/failover
128 _PMigrationTargetNode = ("target_node", None, ht.TMaybeString,
129 "Target node for shared-storage instances")
131 _PStartupPaused = ("startup_paused", False, ht.TBool,
132 "Pause instance at startup")
134 _PVerbose = ("verbose", False, ht.TBool, "Verbose mode")
136 # Parameters for cluster verification
137 _PDebugSimulateErrors = ("debug_simulate_errors", False, ht.TBool,
138 "Whether to simulate errors (useful for debugging)")
139 _PErrorCodes = ("error_codes", False, ht.TBool, "Error codes")
140 _PSkipChecks = ("skip_checks", ht.EmptyList,
141 ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS)),
142 "Which checks to skip")
143 _PIgnoreErrors = ("ignore_errors", ht.EmptyList,
144 ht.TListOf(ht.TElemOf(constants.CV_ALL_ECODES_STRINGS)),
145 "List of error codes that should be treated as warnings")
148 _PDiskParams = ("diskparams", None,
150 ht.TDictOf(ht.TElemOf(constants.DISK_TEMPLATES), ht.TDict),
152 "Disk templates' parameter defaults")
154 # Parameters for node resource model
155 _PHvState = ("hv_state", None, ht.TMaybeDict, "Set hypervisor states")
156 _PDiskState = ("disk_state", None, ht.TMaybeDict, "Set disk states")
159 _PIgnoreIpolicy = ("ignore_ipolicy", False, ht.TBool,
160 "Whether to ignore ipolicy violations")
162 # Allow runtime changes while migrating
163 _PAllowRuntimeChgs = ("allow_runtime_changes", True, ht.TBool,
164 "Allow runtime changes (eg. memory ballooning)")
166 #: a required network name
167 _PNetworkName = ("network_name", ht.NoDefault, ht.TNonEmptyString,
170 #: OP_ID conversion regular expression
171 _OPID_RE = re.compile("([a-z])([A-Z])")
173 #: Utility function for L{OpClusterSetParams}
174 _TestClusterOsListItem = \
175 ht.TAnd(ht.TIsLength(2), ht.TItems([
176 ht.TElemOf(constants.DDMS_VALUES),
180 _TestClusterOsList = ht.TMaybeListOf(_TestClusterOsListItem)
182 # TODO: Generate check from constants.INIC_PARAMS_TYPES
183 #: Utility function for testing NIC definitions
185 ht.Comment("NIC parameters")(ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS),
186 ht.TOr(ht.TNone, ht.TNonEmptyString)))
188 _TSetParamsResultItemItems = [
189 ht.Comment("name of changed parameter")(ht.TNonEmptyString),
190 ht.Comment("new value")(ht.TAny),
193 _TSetParamsResult = \
194 ht.TListOf(ht.TAnd(ht.TIsLength(len(_TSetParamsResultItemItems)),
195 ht.TItems(_TSetParamsResultItemItems)))
197 # TODO: Generate check from constants.IDISK_PARAMS_TYPES (however, not all users
198 # of this check support all parameters)
200 ht.Comment("Disk parameters")(ht.TDictOf(ht.TElemOf(constants.IDISK_PARAMS),
201 ht.TOr(ht.TNonEmptyString, ht.TInt)))
204 ht.TListOf(ht.TAnd(ht.TIsLength(2),
205 ht.TItems([ht.TElemOf(constants.RS_ALL),
208 _TQueryResult = ht.TListOf(_TQueryRow)
210 _TOldQueryRow = ht.TListOf(ht.TAny)
212 _TOldQueryResult = ht.TListOf(_TOldQueryRow)
222 #: Attribute name for dependencies
223 DEPEND_ATTR = "depends"
225 #: Attribute name for comment
226 COMMENT_ATTR = "comment"
230 """Convert an opcode class name to an OP_ID.
233 @param name: the class name, as OpXxxYyy
235 @return: the name in the OP_XXXX_YYYY format
238 if not name.startswith("Op"):
240 # Note: (?<=[a-z])(?=[A-Z]) would be ideal, since it wouldn't
241 # consume any input, and hence we would just have all the elements
242 # in the list, one by one; but it seems that split doesn't work on
243 # non-consuming input, hence we have to process the input string a
245 name = _OPID_RE.sub(r"\1,\2", name)
246 elems = name.split(",")
247 return "_".join(n.upper() for n in elems)
250 def _GenerateObjectTypeCheck(obj, fields_types):
251 """Helper to generate type checks for objects.
253 @param obj: The object to generate type checks
254 @param fields_types: The fields and their types as a dict
255 @return: A ht type check function
258 assert set(obj.GetAllSlots()) == set(fields_types.keys()), \
259 "%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys()))
260 return ht.TStrictDict(True, True, fields_types)
264 _GenerateObjectTypeCheck(objects.QueryFieldDefinition, {
265 "name": ht.TNonEmptyString,
266 "title": ht.TNonEmptyString,
267 "kind": ht.TElemOf(constants.QFT_ALL),
268 "doc": ht.TNonEmptyString,
272 def RequireFileStorage():
273 """Checks that file storage is enabled.
275 While it doesn't really fit into this module, L{utils} was deemed too large
276 of a dependency to be imported for just one or two functions.
278 @raise errors.OpPrereqError: when file storage is disabled
281 if not constants.ENABLE_FILE_STORAGE:
282 raise errors.OpPrereqError("File storage disabled at configure time",
286 def RequireSharedFileStorage():
287 """Checks that shared file storage is enabled.
289 While it doesn't really fit into this module, L{utils} was deemed too large
290 of a dependency to be imported for just one or two functions.
292 @raise errors.OpPrereqError: when shared file storage is disabled
295 if not constants.ENABLE_SHARED_FILE_STORAGE:
296 raise errors.OpPrereqError("Shared file storage disabled at"
297 " configure time", errors.ECODE_INVAL)
300 @ht.WithDesc("CheckFileStorage")
301 def _CheckFileStorage(value):
302 """Ensures file storage is enabled if used.
305 if value == constants.DT_FILE:
307 elif value == constants.DT_SHARED_FILE:
308 RequireSharedFileStorage()
312 def _BuildDiskTemplateCheck(accept_none):
313 """Builds check for disk template.
315 @type accept_none: bool
316 @param accept_none: whether to accept None as a correct value
320 template_check = ht.TElemOf(constants.DISK_TEMPLATES)
323 template_check = ht.TOr(template_check, ht.TNone)
325 return ht.TAnd(template_check, _CheckFileStorage)
328 def _CheckStorageType(storage_type):
329 """Ensure a given storage type is valid.
332 if storage_type not in constants.VALID_STORAGE_TYPES:
333 raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
335 if storage_type == constants.ST_FILE:
340 #: Storage type parameter
341 _PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType,
344 _CheckNetworkType = ht.TElemOf(constants.NETWORK_VALID_TYPES)
346 #: Network type parameter
347 _PNetworkType = ("network_type", None, ht.TOr(ht.TNone, _CheckNetworkType),
350 def _CheckCIDRNetNotation(value):
351 """Ensure a given cidr notation type is valid.
355 ipaddr.IPv4Network(value)
356 except ipaddr.AddressValueError:
360 def _CheckCIDRAddrNotation(value):
361 """Ensure a given cidr notation type is valid.
365 ipaddr.IPv4Address(value)
366 except ipaddr.AddressValueError:
370 def _CheckCIDR6AddrNotation(value):
371 """Ensure a given cidr notation type is valid.
375 ipaddr.IPv6Address(value)
376 except ipaddr.AddressValueError:
380 def _CheckCIDR6NetNotation(value):
381 """Ensure a given cidr notation type is valid.
385 ipaddr.IPv6Network(value)
386 except ipaddr.AddressValueError:
390 class _AutoOpParamSlots(type):
391 """Meta class for opcode definitions.
394 def __new__(mcs, name, bases, attrs):
395 """Called when a class should be created.
397 @param mcs: The meta class
398 @param name: Name of created class
399 @param bases: Base classes
401 @param attrs: Class attributes
404 assert "__slots__" not in attrs, \
405 "Class '%s' defines __slots__ when it should use OP_PARAMS" % name
406 assert "OP_ID" not in attrs, "Class '%s' defining OP_ID" % name
408 attrs["OP_ID"] = _NameToId(name)
410 # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams
411 params = attrs.setdefault("OP_PARAMS", [])
413 # Use parameter names as slots
414 slots = [pname for (pname, _, _, _) in params]
416 assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
417 "Class '%s' uses unknown field in OP_DSC_FIELD" % name
419 attrs["__slots__"] = slots
421 return type.__new__(mcs, name, bases, attrs)
424 class BaseOpCode(object):
425 """A simple serializable object.
427 This object serves as a parent class for OpCode without any custom
431 # pylint: disable=E1101
432 # as OP_ID is dynamically defined
433 __metaclass__ = _AutoOpParamSlots
435 def __init__(self, **kwargs):
436 """Constructor for BaseOpCode.
438 The constructor takes only keyword arguments and will set
439 attributes on this object based on the passed arguments. As such,
440 it means that you should not pass arguments which are not in the
441 __slots__ attribute for this class.
444 slots = self._all_slots()
447 raise TypeError("Object %s doesn't support the parameter '%s'" %
448 (self.__class__.__name__, key))
449 setattr(self, key, kwargs[key])
451 def __getstate__(self):
452 """Generic serializer.
454 This method just returns the contents of the instance as a
458 @return: the instance attributes and their values
462 for name in self._all_slots():
463 if hasattr(self, name):
464 state[name] = getattr(self, name)
467 def __setstate__(self, state):
468 """Generic unserializer.
470 This method just restores from the serialized state the attributes
471 of the current instance.
473 @param state: the serialized opcode data
477 if not isinstance(state, dict):
478 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
481 for name in self._all_slots():
482 if name not in state and hasattr(self, name):
486 setattr(self, name, state[name])
490 """Compute the list of all declared slots for a class.
494 for parent in cls.__mro__:
495 slots.extend(getattr(parent, "__slots__", []))
499 def GetAllParams(cls):
500 """Compute list of all parameters for an opcode.
504 for parent in cls.__mro__:
505 slots.extend(getattr(parent, "OP_PARAMS", []))
508 def Validate(self, set_defaults):
509 """Validate opcode parameters, optionally setting default values.
511 @type set_defaults: bool
512 @param set_defaults: Whether to set default values
513 @raise errors.OpPrereqError: When a parameter value doesn't match
517 for (attr_name, default, test, _) in self.GetAllParams():
518 assert test == ht.NoType or callable(test)
520 if not hasattr(self, attr_name):
521 if default == ht.NoDefault:
522 raise errors.OpPrereqError("Required parameter '%s.%s' missing" %
523 (self.OP_ID, attr_name),
526 if callable(default):
530 setattr(self, attr_name, dval)
532 if test == ht.NoType:
536 if set_defaults or hasattr(self, attr_name):
537 attr_val = getattr(self, attr_name)
538 if not test(attr_val):
539 logging.error("OpCode %s, parameter %s, has invalid type %s/value %s",
540 self.OP_ID, attr_name, type(attr_val), attr_val)
541 raise errors.OpPrereqError("Parameter '%s.%s' fails validation" %
542 (self.OP_ID, attr_name),
546 def _BuildJobDepCheck(relative):
547 """Builds check for job dependencies (L{DEPEND_ATTR}).
550 @param relative: Whether to accept relative job IDs (negative)
555 job_id = ht.TOr(ht.TJobId, ht.TRelativeJobId)
560 ht.TAnd(ht.TIsLength(2),
562 ht.TListOf(ht.TElemOf(constants.JOBS_FINALIZED))]))
564 return ht.TMaybeListOf(job_dep)
567 TNoRelativeJobDependencies = _BuildJobDepCheck(False)
569 #: List of submission status and job ID as returned by C{SubmitManyJobs}
571 ht.TAnd(ht.TIsLength(2),
572 ht.TItems([ht.Comment("success")(ht.TBool),
573 ht.Comment("Job ID if successful, error message"
574 " otherwise")(ht.TOr(ht.TString,
576 TJobIdList = ht.TListOf(_TJobIdListItem)
578 #: Result containing only list of submitted jobs
579 TJobIdListOnly = ht.TStrictDict(True, True, {
580 constants.JOB_IDS_KEY: ht.Comment("List of submitted jobs")(TJobIdList),
584 class OpCode(BaseOpCode):
587 This is the root of the actual OpCode hierarchy. All clases derived
588 from this class should override OP_ID.
590 @cvar OP_ID: The ID of this opcode. This should be unique amongst all
591 children of this class.
592 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
593 string returned by Summary(); see the docstring of that
595 @cvar OP_PARAMS: List of opcode attributes, the default values they should
596 get if not already defined, and types they must match.
597 @cvar OP_RESULT: Callable to verify opcode result
598 @cvar WITH_LU: Boolean that specifies whether this should be included in
599 mcpu's dispatch table
600 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
602 @ivar priority: Opcode priority for queue
605 # pylint: disable=E1101
606 # as OP_ID is dynamically defined
609 ("dry_run", None, ht.TMaybeBool, "Run checks only, don't execute"),
610 ("debug_level", None, ht.TOr(ht.TNone, ht.TPositiveInt), "Debug level"),
611 ("priority", constants.OP_PRIO_DEFAULT,
612 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"),
613 (DEPEND_ATTR, None, _BuildJobDepCheck(True),
614 "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)"
615 " job IDs can be used; see :doc:`design document <design-chained-jobs>`"
617 (COMMENT_ATTR, None, ht.TMaybeString,
618 "Comment describing the purpose of the opcode"),
622 def __getstate__(self):
623 """Specialized getstate for opcodes.
625 This method adds to the state dictionary the OP_ID of the class,
626 so that on unload we can identify the correct class for
627 instantiating the opcode.
630 @return: the state as a dictionary
633 data = BaseOpCode.__getstate__(self)
634 data["OP_ID"] = self.OP_ID
638 def LoadOpCode(cls, data):
639 """Generic load opcode method.
641 The method identifies the correct opcode class from the dict-form
642 by looking for a OP_ID key, if this is not found, or its value is
643 not available in this module as a child of this class, we fail.
646 @param data: the serialized opcode
649 if not isinstance(data, dict):
650 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
651 if "OP_ID" not in data:
652 raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
653 op_id = data["OP_ID"]
655 if op_id in OP_MAPPING:
656 op_class = OP_MAPPING[op_id]
658 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
661 new_data = data.copy()
662 del new_data["OP_ID"]
663 op.__setstate__(new_data)
667 """Generates a summary description of this opcode.
669 The summary is the value of the OP_ID attribute (without the "OP_"
670 prefix), plus the value of the OP_DSC_FIELD attribute, if one was
671 defined; this field should allow to easily identify the operation
672 (for an instance creation job, e.g., it would be the instance
676 assert self.OP_ID is not None and len(self.OP_ID) > 3
677 # all OP_ID start with OP_, we remove that
679 field_name = getattr(self, "OP_DSC_FIELD", None)
681 field_value = getattr(self, field_name, None)
682 if isinstance(field_value, (list, tuple)):
683 field_value = ",".join(str(i) for i in field_value)
684 txt = "%s(%s)" % (txt, field_value)
687 def TinySummary(self):
688 """Generates a compact summary description of the opcode.
691 assert self.OP_ID.startswith("OP_")
693 text = self.OP_ID[3:]
695 for (prefix, supplement) in _SUMMARY_PREFIX.items():
696 if text.startswith(prefix):
697 return supplement + text[len(prefix):]
704 class OpClusterPostInit(OpCode):
705 """Post cluster initialization.
707 This opcode does not touch the cluster at all. Its purpose is to run hooks
708 after the cluster has been initialized.
714 class OpClusterDestroy(OpCode):
715 """Destroy the cluster.
717 This opcode has no other parameters. All the state is irreversibly
718 lost after the execution of this opcode.
721 OP_RESULT = ht.TNonEmptyString
724 class OpClusterQuery(OpCode):
725 """Query cluster information."""
726 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TAny)
729 class OpClusterVerify(OpCode):
730 """Submits all jobs necessary to verify the cluster.
734 _PDebugSimulateErrors,
739 ("group_name", None, ht.TMaybeString, "Group to verify")
741 OP_RESULT = TJobIdListOnly
744 class OpClusterVerifyConfig(OpCode):
745 """Verify the cluster config.
749 _PDebugSimulateErrors,
757 class OpClusterVerifyGroup(OpCode):
758 """Run verify on a node group from the cluster.
760 @type skip_checks: C{list}
761 @ivar skip_checks: steps to be skipped from the verify process; this
762 needs to be a subset of
763 L{constants.VERIFY_OPTIONAL_CHECKS}; currently
764 only L{constants.VERIFY_NPLUSONE_MEM} can be passed
767 OP_DSC_FIELD = "group_name"
770 _PDebugSimulateErrors,
779 class OpClusterVerifyDisks(OpCode):
780 """Verify the cluster disks.
783 OP_RESULT = TJobIdListOnly
786 class OpGroupVerifyDisks(OpCode):
787 """Verifies the status of all disks in a node group.
789 Result: a tuple of three elements:
790 - dict of node names with issues (values: error msg)
791 - list of instances with degraded disks (that should be activated)
792 - dict of instances with missing logical volumes (values: (node, vol)
793 pairs with details about the missing volumes)
795 In normal operation, all lists should be empty. A non-empty instance
796 list (3rd element of the result) is still ok (errors were fixed) but
797 non-empty node list means some node is down, and probably there are
798 unfixable drbd errors.
800 Note that only instances that are drbd-based are taken into
801 consideration. This might need to be revisited in the future.
804 OP_DSC_FIELD = "group_name"
809 ht.TAnd(ht.TIsLength(3),
810 ht.TItems([ht.TDictOf(ht.TString, ht.TString),
811 ht.TListOf(ht.TString),
812 ht.TDictOf(ht.TString,
813 ht.TListOf(ht.TListOf(ht.TString)))]))
816 class OpClusterRepairDiskSizes(OpCode):
817 """Verify the disk sizes of the instances and fixes configuration
820 Parameters: optional instances list, in case we want to restrict the
821 checks to only a subset of the instances.
823 Result: a list of tuples, (instance, disk, new-size) for changed
826 In normal operation, the list should be empty.
828 @type instances: list
829 @ivar instances: the list of instances to check, or empty for all instances
833 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
835 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3),
836 ht.TItems([ht.TNonEmptyString,
841 class OpClusterConfigQuery(OpCode):
842 """Query cluster configuration values."""
846 OP_RESULT = ht.TListOf(ht.TAny)
849 class OpClusterRename(OpCode):
850 """Rename the cluster.
853 @ivar name: The new name of the cluster. The name and/or the master IP
854 address will be changed to match the new name and its IP
858 OP_DSC_FIELD = "name"
860 ("name", ht.NoDefault, ht.TNonEmptyString, None),
862 OP_RESULT = ht.TNonEmptyString
865 class OpClusterSetParams(OpCode):
866 """Change the parameters of the cluster.
868 @type vg_name: C{str} or C{None}
869 @ivar vg_name: The new volume group name or None to disable LVM usage.
875 ("vg_name", None, ht.TMaybeString, "Volume group name"),
876 ("enabled_hypervisors", None,
877 ht.TOr(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)), ht.TTrue),
879 "List of enabled hypervisors"),
880 ("hvparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
882 "Cluster-wide hypervisor parameter defaults, hypervisor-dependent"),
883 ("beparams", None, ht.TOr(ht.TDict, ht.TNone),
884 "Cluster-wide backend parameter defaults"),
885 ("os_hvp", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
887 "Cluster-wide per-OS hypervisor parameter defaults"),
888 ("osparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
890 "Cluster-wide OS parameter defaults"),
892 ("candidate_pool_size", None, ht.TOr(ht.TStrictPositiveInt, ht.TNone),
893 "Master candidate pool size"),
894 ("uid_pool", None, ht.NoType,
895 "Set UID pool, must be list of lists describing UID ranges (two items,"
896 " start and end inclusive)"),
897 ("add_uids", None, ht.NoType,
898 "Extend UID pool, must be list of lists describing UID ranges (two"
899 " items, start and end inclusive) to be added"),
900 ("remove_uids", None, ht.NoType,
901 "Shrink UID pool, must be list of lists describing UID ranges (two"
902 " items, start and end inclusive) to be removed"),
903 ("maintain_node_health", None, ht.TMaybeBool,
904 "Whether to automatically maintain node health"),
905 ("prealloc_wipe_disks", None, ht.TMaybeBool,
906 "Whether to wipe disks before allocating them to instances"),
907 ("nicparams", None, ht.TMaybeDict, "Cluster-wide NIC parameter defaults"),
908 ("ndparams", None, ht.TMaybeDict, "Cluster-wide node parameter defaults"),
909 ("ipolicy", None, ht.TMaybeDict,
910 "Cluster-wide :ref:`instance policy <rapi-ipolicy>` specs"),
911 ("drbd_helper", None, ht.TOr(ht.TString, ht.TNone), "DRBD helper program"),
912 ("default_iallocator", None, ht.TOr(ht.TString, ht.TNone),
913 "Default iallocator for cluster"),
914 ("master_netdev", None, ht.TOr(ht.TString, ht.TNone),
915 "Master network device"),
916 ("master_netmask", None, ht.TOr(ht.TInt, ht.TNone),
917 "Netmask of the master IP"),
918 ("reserved_lvs", None, ht.TMaybeListOf(ht.TNonEmptyString),
919 "List of reserved LVs"),
920 ("hidden_os", None, _TestClusterOsList,
921 "Modify list of hidden operating systems: each modification must have"
922 " two items, the operation and the OS name; the operation can be"
923 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)),
924 ("blacklisted_os", None, _TestClusterOsList,
925 "Modify list of blacklisted operating systems: each modification must"
926 " have two items, the operation and the OS name; the operation can be"
927 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)),
928 ("use_external_mip_script", None, ht.TMaybeBool,
929 "Whether to use an external master IP address setup script"),
934 class OpClusterRedistConf(OpCode):
935 """Force a full push of the cluster configuration.
941 class OpClusterActivateMasterIp(OpCode):
942 """Activate the master IP on the master node.
948 class OpClusterDeactivateMasterIp(OpCode):
949 """Deactivate the master IP on the master node.
955 class OpQuery(OpCode):
956 """Query for resources/items.
958 @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP}
959 @ivar fields: List of fields to retrieve
960 @ivar qfilter: Query filter
963 OP_DSC_FIELD = "what"
967 ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
969 ("qfilter", None, ht.TOr(ht.TNone, ht.TList),
973 _GenerateObjectTypeCheck(objects.QueryResponse, {
974 "fields": ht.TListOf(_TQueryFieldDef),
975 "data": _TQueryResult,
979 class OpQueryFields(OpCode):
980 """Query for available resource/item fields.
982 @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP}
983 @ivar fields: List of fields to retrieve
986 OP_DSC_FIELD = "what"
989 ("fields", None, ht.TMaybeListOf(ht.TNonEmptyString),
990 "Requested fields; if not given, all are returned"),
993 _GenerateObjectTypeCheck(objects.QueryFieldsResponse, {
994 "fields": ht.TListOf(_TQueryFieldDef),
998 class OpOobCommand(OpCode):
999 """Interact with OOB."""
1001 ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1002 "List of nodes to run the OOB command against"),
1003 ("command", None, ht.TElemOf(constants.OOB_COMMANDS),
1004 "OOB command to be run"),
1005 ("timeout", constants.OOB_TIMEOUT, ht.TInt,
1006 "Timeout before the OOB helper will be terminated"),
1007 ("ignore_status", False, ht.TBool,
1008 "Ignores the node offline status for power off"),
1009 ("power_delay", constants.OOB_POWER_DELAY, ht.TPositiveFloat,
1010 "Time in seconds to wait between powering on nodes"),
1012 # Fixme: Make it more specific with all the special cases in LUOobCommand
1013 OP_RESULT = _TQueryResult
1018 class OpNodeRemove(OpCode):
1021 @type node_name: C{str}
1022 @ivar node_name: The name of the node to remove. If the node still has
1023 instances on it, the operation will fail.
1026 OP_DSC_FIELD = "node_name"
1030 OP_RESULT = ht.TNone
1033 class OpNodeAdd(OpCode):
1034 """Add a node to the cluster.
1036 @type node_name: C{str}
1037 @ivar node_name: The name of the node to add. This can be a short name,
1038 but it will be expanded to the FQDN.
1039 @type primary_ip: IP address
1040 @ivar primary_ip: The primary IP of the node. This will be ignored when the
1041 opcode is submitted, but will be filled during the node
1042 add (so it will be visible in the job query).
1043 @type secondary_ip: IP address
1044 @ivar secondary_ip: The secondary IP of the node. This needs to be passed
1045 if the cluster has been initialized in 'dual-network'
1046 mode, otherwise it must not be given.
1047 @type readd: C{bool}
1048 @ivar readd: Whether to re-add an existing node to the cluster. If
1049 this is not passed, then the operation will abort if the node
1050 name is already in the cluster; use this parameter to 'repair'
1051 a node that had its configuration broken, or was reinstalled
1052 without removal from the cluster.
1054 @ivar group: The node group to which this node will belong.
1055 @type vm_capable: C{bool}
1056 @ivar vm_capable: The vm_capable node attribute
1057 @type master_capable: C{bool}
1058 @ivar master_capable: The master_capable node attribute
1061 OP_DSC_FIELD = "node_name"
1066 ("primary_ip", None, ht.NoType, "Primary IP address"),
1067 ("secondary_ip", None, ht.TMaybeString, "Secondary IP address"),
1068 ("readd", False, ht.TBool, "Whether node is re-added to cluster"),
1069 ("group", None, ht.TMaybeString, "Initial node group"),
1070 ("master_capable", None, ht.TMaybeBool,
1071 "Whether node can become master or master candidate"),
1072 ("vm_capable", None, ht.TMaybeBool,
1073 "Whether node can host instances"),
1074 ("ndparams", None, ht.TMaybeDict, "Node parameters"),
1076 OP_RESULT = ht.TNone
1079 class OpNodeQuery(OpCode):
1080 """Compute the list of nodes."""
1084 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1085 "Empty list to query all nodes, node names otherwise"),
1087 OP_RESULT = _TOldQueryResult
1090 class OpNodeQueryvols(OpCode):
1091 """Get list of volumes on node."""
1094 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1095 "Empty list to query all nodes, node names otherwise"),
1097 OP_RESULT = ht.TListOf(ht.TAny)
1100 class OpNodeQueryStorage(OpCode):
1101 """Get information on storage for node(s)."""
1105 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "List of nodes"),
1106 ("name", None, ht.TMaybeString, "Storage name"),
1108 OP_RESULT = _TOldQueryResult
1111 class OpNodeModifyStorage(OpCode):
1112 """Modifies the properies of a storage unit"""
1117 ("changes", ht.NoDefault, ht.TDict, "Requested changes"),
1119 OP_RESULT = ht.TNone
1122 class OpRepairNodeStorage(OpCode):
1123 """Repairs the volume group on a node."""
1124 OP_DSC_FIELD = "node_name"
1129 _PIgnoreConsistency,
1131 OP_RESULT = ht.TNone
1134 class OpNodeSetParams(OpCode):
1135 """Change the parameters of a node."""
1136 OP_DSC_FIELD = "node_name"
1142 ("master_candidate", None, ht.TMaybeBool,
1143 "Whether the node should become a master candidate"),
1144 ("offline", None, ht.TMaybeBool,
1145 "Whether the node should be marked as offline"),
1146 ("drained", None, ht.TMaybeBool,
1147 "Whether the node should be marked as drained"),
1148 ("auto_promote", False, ht.TBool,
1149 "Whether node(s) should be promoted to master candidate if necessary"),
1150 ("master_capable", None, ht.TMaybeBool,
1151 "Denote whether node can become master or master candidate"),
1152 ("vm_capable", None, ht.TMaybeBool,
1153 "Denote whether node can host instances"),
1154 ("secondary_ip", None, ht.TMaybeString,
1155 "Change node's secondary IP address"),
1156 ("ndparams", None, ht.TMaybeDict, "Set node parameters"),
1157 ("powered", None, ht.TMaybeBool,
1158 "Whether the node should be marked as powered"),
1160 OP_RESULT = _TSetParamsResult
1163 class OpNodePowercycle(OpCode):
1164 """Tries to powercycle a node."""
1165 OP_DSC_FIELD = "node_name"
1170 OP_RESULT = ht.TMaybeString
1173 class OpNodeMigrate(OpCode):
1174 """Migrate all instances from a node."""
1175 OP_DSC_FIELD = "node_name"
1180 _PMigrationTargetNode,
1183 ("iallocator", None, ht.TMaybeString,
1184 "Iallocator for deciding the target node for shared-storage instances"),
1186 OP_RESULT = TJobIdListOnly
1189 class OpNodeEvacuate(OpCode):
1190 """Evacuate instances off a number of nodes."""
1191 OP_DSC_FIELD = "node_name"
1195 ("remote_node", None, ht.TMaybeString, "New secondary node"),
1196 ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"),
1197 ("mode", ht.NoDefault, ht.TElemOf(constants.NODE_EVAC_MODES),
1198 "Node evacuation mode"),
1200 OP_RESULT = TJobIdListOnly
1205 class OpInstanceCreate(OpCode):
1206 """Create an instance.
1208 @ivar instance_name: Instance name
1209 @ivar mode: Instance creation mode (one of L{constants.INSTANCE_CREATE_MODES})
1210 @ivar source_handshake: Signed handshake from source (remote import only)
1211 @ivar source_x509_ca: Source X509 CA in PEM format (remote import only)
1212 @ivar source_instance_name: Previous name of instance (remote import only)
1213 @ivar source_shutdown_timeout: Shutdown timeout used for source instance
1214 (remote import only)
1217 OP_DSC_FIELD = "instance_name"
1224 ("beparams", ht.EmptyDict, ht.TDict, "Backend parameters for instance"),
1225 ("disks", ht.NoDefault, ht.TListOf(_TDiskParams),
1226 "Disk descriptions, for example ``[{\"%s\": 100}, {\"%s\": 5}]``;"
1227 " each disk definition must contain a ``%s`` value and"
1228 " can contain an optional ``%s`` value denoting the disk access mode"
1230 (constants.IDISK_SIZE, constants.IDISK_SIZE, constants.IDISK_SIZE,
1231 constants.IDISK_MODE,
1232 " or ".join("``%s``" % i for i in sorted(constants.DISK_ACCESS_SET)))),
1233 ("disk_template", ht.NoDefault, _BuildDiskTemplateCheck(True),
1235 ("file_driver", None, ht.TOr(ht.TNone, ht.TElemOf(constants.FILE_DRIVER)),
1236 "Driver for file-backed disks"),
1237 ("file_storage_dir", None, ht.TMaybeString,
1238 "Directory for storing file-backed disks"),
1239 ("hvparams", ht.EmptyDict, ht.TDict,
1240 "Hypervisor parameters for instance, hypervisor-dependent"),
1241 ("hypervisor", None, ht.TMaybeString, "Hypervisor"),
1242 ("iallocator", None, ht.TMaybeString,
1243 "Iallocator for deciding which node(s) to use"),
1244 ("identify_defaults", False, ht.TBool,
1245 "Reset instance parameters to default if equal"),
1246 ("ip_check", True, ht.TBool, _PIpCheckDoc),
1247 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1248 ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES),
1249 "Instance creation mode"),
1250 ("nics", ht.NoDefault, ht.TListOf(_TestNicDef),
1251 "List of NIC (network interface) definitions, for example"
1252 " ``[{}, {}, {\"%s\": \"198.51.100.4\"}]``; each NIC definition can"
1253 " contain the optional values %s" %
1255 ", ".join("``%s``" % i for i in sorted(constants.INIC_PARAMS)))),
1256 ("no_install", None, ht.TMaybeBool,
1257 "Do not install the OS (will disable automatic start)"),
1258 ("osparams", ht.EmptyDict, ht.TDict, "OS parameters for instance"),
1259 ("os_type", None, ht.TMaybeString, "Operating system"),
1260 ("pnode", None, ht.TMaybeString, "Primary node"),
1261 ("snode", None, ht.TMaybeString, "Secondary node"),
1262 ("source_handshake", None, ht.TOr(ht.TList, ht.TNone),
1263 "Signed handshake from source (remote import only)"),
1264 ("source_instance_name", None, ht.TMaybeString,
1265 "Source instance name (remote import only)"),
1266 ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
1268 "How long source instance was given to shut down (remote import only)"),
1269 ("source_x509_ca", None, ht.TMaybeString,
1270 "Source X509 CA in PEM format (remote import only)"),
1271 ("src_node", None, ht.TMaybeString, "Source node for import"),
1272 ("src_path", None, ht.TMaybeString, "Source directory for import"),
1273 ("start", True, ht.TBool, "Whether to start instance after creation"),
1274 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Instance tags"),
1276 OP_RESULT = ht.Comment("instance nodes")(ht.TListOf(ht.TNonEmptyString))
1279 class OpInstanceReinstall(OpCode):
1280 """Reinstall an instance's OS."""
1281 OP_DSC_FIELD = "instance_name"
1285 ("os_type", None, ht.TMaybeString, "Instance operating system"),
1286 ("osparams", None, ht.TMaybeDict, "Temporary OS parameters"),
1288 OP_RESULT = ht.TNone
1291 class OpInstanceRemove(OpCode):
1292 """Remove an instance."""
1293 OP_DSC_FIELD = "instance_name"
1297 ("ignore_failures", False, ht.TBool,
1298 "Whether to ignore failures during removal"),
1300 OP_RESULT = ht.TNone
1303 class OpInstanceRename(OpCode):
1304 """Rename an instance."""
1308 ("new_name", ht.NoDefault, ht.TNonEmptyString, "New instance name"),
1309 ("ip_check", False, ht.TBool, _PIpCheckDoc),
1311 OP_RESULT = ht.Comment("New instance name")(ht.TNonEmptyString)
1314 class OpInstanceStartup(OpCode):
1315 """Startup an instance."""
1316 OP_DSC_FIELD = "instance_name"
1320 _PIgnoreOfflineNodes,
1321 ("hvparams", ht.EmptyDict, ht.TDict,
1322 "Temporary hypervisor parameters, hypervisor-dependent"),
1323 ("beparams", ht.EmptyDict, ht.TDict, "Temporary backend parameters"),
1327 OP_RESULT = ht.TNone
1330 class OpInstanceShutdown(OpCode):
1331 """Shutdown an instance."""
1332 OP_DSC_FIELD = "instance_name"
1335 _PIgnoreOfflineNodes,
1336 ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TPositiveInt,
1337 "How long to wait for instance to shut down"),
1340 OP_RESULT = ht.TNone
1343 class OpInstanceReboot(OpCode):
1344 """Reboot an instance."""
1345 OP_DSC_FIELD = "instance_name"
1349 ("ignore_secondaries", False, ht.TBool,
1350 "Whether to start the instance even if secondary disks are failing"),
1351 ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES),
1352 "How to reboot instance"),
1354 OP_RESULT = ht.TNone
1357 class OpInstanceReplaceDisks(OpCode):
1358 """Replace the disks of an instance."""
1359 OP_DSC_FIELD = "instance_name"
1364 ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES),
1365 "Replacement mode"),
1366 ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt),
1368 ("remote_node", None, ht.TMaybeString, "New secondary node"),
1369 ("iallocator", None, ht.TMaybeString,
1370 "Iallocator for deciding new secondary node"),
1372 OP_RESULT = ht.TNone
1375 class OpInstanceFailover(OpCode):
1376 """Failover an instance."""
1377 OP_DSC_FIELD = "instance_name"
1381 _PIgnoreConsistency,
1382 _PMigrationTargetNode,
1384 ("iallocator", None, ht.TMaybeString,
1385 "Iallocator for deciding the target node for shared-storage instances"),
1387 OP_RESULT = ht.TNone
1390 class OpInstanceMigrate(OpCode):
1391 """Migrate an instance.
1393 This migrates (without shutting down an instance) to its secondary
1396 @ivar instance_name: the name of the instance
1397 @ivar mode: the migration mode (live, non-live or None for auto)
1400 OP_DSC_FIELD = "instance_name"
1405 _PMigrationTargetNode,
1408 ("cleanup", False, ht.TBool,
1409 "Whether a previously failed migration should be cleaned up"),
1410 ("iallocator", None, ht.TMaybeString,
1411 "Iallocator for deciding the target node for shared-storage instances"),
1412 ("allow_failover", False, ht.TBool,
1413 "Whether we can fallback to failover if migration is not possible"),
1415 OP_RESULT = ht.TNone
1418 class OpInstanceMove(OpCode):
1419 """Move an instance.
1421 This move (with shutting down an instance and data copying) to an
1424 @ivar instance_name: the name of the instance
1425 @ivar target_node: the destination node
1428 OP_DSC_FIELD = "instance_name"
1433 ("target_node", ht.NoDefault, ht.TNonEmptyString, "Target node"),
1434 _PIgnoreConsistency,
1436 OP_RESULT = ht.TNone
1439 class OpInstanceConsole(OpCode):
1440 """Connect to an instance's console."""
1441 OP_DSC_FIELD = "instance_name"
1445 OP_RESULT = ht.TDict
1448 class OpInstanceActivateDisks(OpCode):
1449 """Activate an instance's disks."""
1450 OP_DSC_FIELD = "instance_name"
1453 ("ignore_size", False, ht.TBool, "Whether to ignore recorded size"),
1455 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3),
1456 ht.TItems([ht.TNonEmptyString,
1458 ht.TNonEmptyString])))
1461 class OpInstanceDeactivateDisks(OpCode):
1462 """Deactivate an instance's disks."""
1463 OP_DSC_FIELD = "instance_name"
1468 OP_RESULT = ht.TNone
1471 class OpInstanceRecreateDisks(OpCode):
1472 """Recreate an instance's disks."""
1474 ht.TAnd(ht.TIsLength(2),
1475 ht.TItems([ht.Comment("Disk index")(ht.TPositiveInt),
1476 ht.Comment("Parameters")(_TDiskParams)]))
1478 OP_DSC_FIELD = "instance_name"
1481 ("disks", ht.EmptyList,
1482 ht.TOr(ht.TListOf(ht.TPositiveInt), ht.TListOf(_TDiskChanges)),
1483 "List of disk indexes (deprecated) or a list of tuples containing a disk"
1484 " index and a possibly empty dictionary with disk parameter changes"),
1485 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1486 "New instance nodes, if relocation is desired"),
1488 OP_RESULT = ht.TNone
1491 class OpInstanceQuery(OpCode):
1492 """Compute the list of instances."""
1496 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1497 "Empty list to query all instances, instance names otherwise"),
1499 OP_RESULT = _TOldQueryResult
1502 class OpInstanceQueryData(OpCode):
1503 """Compute the run-time status of instances."""
1506 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1508 ("static", False, ht.TBool,
1509 "Whether to only return configuration data without querying"
1512 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TDict)
1515 def _TestInstSetParamsModList(fn):
1516 """Generates a check for modification lists.
1520 # TODO: Remove in version 2.8 including support in LUInstanceSetParams
1522 ht.TAnd(ht.TIsLength(2), ht.TItems([
1523 ht.TOr(ht.TElemOf(constants.DDMS_VALUES), ht.TPositiveInt),
1527 # New format, supporting adding/removing disks/NICs at arbitrary indices
1529 ht.TAnd(ht.TIsLength(3), ht.TItems([
1530 ht.TElemOf(constants.DDMS_VALUES_WITH_MODIFY),
1531 ht.Comment("Disk index, can be negative, e.g. -1 for last disk")(ht.TInt),
1535 return ht.TOr(ht.Comment("Recommended")(ht.TListOf(mod_item_fn)),
1536 ht.Comment("Deprecated")(ht.TListOf(old_mod_item_fn)))
1539 class OpInstanceSetParams(OpCode):
1540 """Change the parameters of an instance.
1543 TestNicModifications = _TestInstSetParamsModList(_TestNicDef)
1544 TestDiskModifications = _TestInstSetParamsModList(_TDiskParams)
1546 OP_DSC_FIELD = "instance_name"
1552 ("nics", ht.EmptyList, TestNicModifications,
1553 "List of NIC changes: each item is of the form ``(op, index, settings)``,"
1554 " ``op`` is one of ``%s``, ``%s`` or ``%s``, ``index`` can be either -1"
1555 " to refer to the last position, or a zero-based index number; a"
1556 " deprecated version of this parameter used the form ``(op, settings)``,"
1557 " where ``op`` can be ``%s`` to add a new NIC with the specified"
1558 " settings, ``%s`` to remove the last NIC or a number to modify the"
1559 " settings of the NIC with that index" %
1560 (constants.DDM_ADD, constants.DDM_MODIFY, constants.DDM_REMOVE,
1561 constants.DDM_ADD, constants.DDM_REMOVE)),
1562 ("disks", ht.EmptyList, TestDiskModifications,
1563 "List of disk changes; see ``nics``"),
1564 ("beparams", ht.EmptyDict, ht.TDict, "Per-instance backend parameters"),
1565 ("runtime_mem", None, ht.TMaybeStrictPositiveInt, "New runtime memory"),
1566 ("hvparams", ht.EmptyDict, ht.TDict,
1567 "Per-instance hypervisor parameters, hypervisor-dependent"),
1568 ("disk_template", None, ht.TOr(ht.TNone, _BuildDiskTemplateCheck(False)),
1569 "Disk template for instance"),
1570 ("remote_node", None, ht.TMaybeString,
1571 "Secondary node (used when changing disk template)"),
1572 ("os_name", None, ht.TMaybeString,
1573 "Change the instance's OS without reinstalling the instance"),
1574 ("osparams", None, ht.TMaybeDict, "Per-instance OS parameters"),
1575 ("wait_for_sync", True, ht.TBool,
1576 "Whether to wait for the disk to synchronize, when changing template"),
1577 ("offline", None, ht.TMaybeBool, "Whether to mark instance as offline"),
1578 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1580 OP_RESULT = _TSetParamsResult
1583 class OpInstanceGrowDisk(OpCode):
1584 """Grow a disk of an instance."""
1585 OP_DSC_FIELD = "instance_name"
1589 ("disk", ht.NoDefault, ht.TInt, "Disk index"),
1590 ("amount", ht.NoDefault, ht.TPositiveInt,
1591 "Amount of disk space to add (megabytes)"),
1592 ("absolute", False, ht.TBool,
1593 "Whether the amount parameter is an absolute target or a relative one"),
1595 OP_RESULT = ht.TNone
1598 class OpInstanceChangeGroup(OpCode):
1599 """Moves an instance to another node group."""
1600 OP_DSC_FIELD = "instance_name"
1604 ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"),
1605 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString),
1606 "Destination group names or UUIDs (defaults to \"all but current group\""),
1608 OP_RESULT = TJobIdListOnly
1611 # Node group opcodes
1613 class OpGroupAdd(OpCode):
1614 """Add a node group to the cluster."""
1615 OP_DSC_FIELD = "group_name"
1618 _PNodeGroupAllocPolicy,
1623 ("ipolicy", None, ht.TMaybeDict,
1624 "Group-wide :ref:`instance policy <rapi-ipolicy>` specs"),
1626 OP_RESULT = ht.TNone
1629 class OpGroupAssignNodes(OpCode):
1630 """Assign nodes to a node group."""
1631 OP_DSC_FIELD = "group_name"
1635 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
1636 "List of nodes to assign"),
1638 OP_RESULT = ht.TNone
1641 class OpGroupQuery(OpCode):
1642 """Compute the list of node groups."""
1645 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1646 "Empty list to query all groups, group names otherwise"),
1648 OP_RESULT = _TOldQueryResult
1651 class OpGroupSetParams(OpCode):
1652 """Change the parameters of a node group."""
1653 OP_DSC_FIELD = "group_name"
1656 _PNodeGroupAllocPolicy,
1661 ("ipolicy", None, ht.TMaybeDict, "Group-wide instance policy specs"),
1663 OP_RESULT = _TSetParamsResult
1666 class OpGroupRemove(OpCode):
1667 """Remove a node group from the cluster."""
1668 OP_DSC_FIELD = "group_name"
1672 OP_RESULT = ht.TNone
1675 class OpGroupRename(OpCode):
1676 """Rename a node group in the cluster."""
1679 ("new_name", ht.NoDefault, ht.TNonEmptyString, "New group name"),
1681 OP_RESULT = ht.Comment("New group name")(ht.TNonEmptyString)
1684 class OpGroupEvacuate(OpCode):
1685 """Evacuate a node group in the cluster."""
1686 OP_DSC_FIELD = "group_name"
1690 ("iallocator", None, ht.TMaybeString, "Iallocator for computing solution"),
1691 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString),
1692 "Destination group names or UUIDs"),
1694 OP_RESULT = TJobIdListOnly
1698 class OpOsDiagnose(OpCode):
1699 """Compute the list of guest operating systems."""
1702 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1703 "Which operating systems to diagnose"),
1705 OP_RESULT = _TOldQueryResult
1709 class OpBackupQuery(OpCode):
1710 """Compute the list of exported images."""
1713 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1714 "Empty list to query all nodes, node names otherwise"),
1716 OP_RESULT = ht.TDictOf(ht.TNonEmptyString,
1717 ht.TOr(ht.Comment("False on error")(ht.TBool),
1718 ht.TListOf(ht.TNonEmptyString)))
1721 class OpBackupPrepare(OpCode):
1722 """Prepares an instance export.
1724 @ivar instance_name: Instance name
1725 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1728 OP_DSC_FIELD = "instance_name"
1731 ("mode", ht.NoDefault, ht.TElemOf(constants.EXPORT_MODES),
1734 OP_RESULT = ht.TOr(ht.TNone, ht.TDict)
1737 class OpBackupExport(OpCode):
1738 """Export an instance.
1740 For local exports, the export destination is the node name. For remote
1741 exports, the export destination is a list of tuples, each consisting of
1742 hostname/IP address, port, HMAC and HMAC salt. The HMAC is calculated using
1743 the cluster domain secret over the value "${index}:${hostname}:${port}". The
1744 destination X509 CA must be a signed certificate.
1746 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1747 @ivar target_node: Export destination
1748 @ivar x509_key_name: X509 key to use (remote export only)
1749 @ivar destination_x509_ca: Destination X509 CA in PEM format (remote export
1753 OP_DSC_FIELD = "instance_name"
1757 # TODO: Rename target_node as it changes meaning for different export modes
1758 # (e.g. "destination")
1759 ("target_node", ht.NoDefault, ht.TOr(ht.TNonEmptyString, ht.TList),
1760 "Destination information, depends on export mode"),
1761 ("shutdown", True, ht.TBool, "Whether to shutdown instance before export"),
1762 ("remove_instance", False, ht.TBool,
1763 "Whether to remove instance after export"),
1764 ("ignore_remove_failures", False, ht.TBool,
1765 "Whether to ignore failures while removing instances"),
1766 ("mode", constants.EXPORT_MODE_LOCAL, ht.TElemOf(constants.EXPORT_MODES),
1768 ("x509_key_name", None, ht.TOr(ht.TList, ht.TNone),
1769 "Name of X509 key (remote export only)"),
1770 ("destination_x509_ca", None, ht.TMaybeString,
1771 "Destination X509 CA (remote export only)"),
1774 ht.TAnd(ht.TIsLength(2), ht.TItems([
1775 ht.Comment("Finalizing status")(ht.TBool),
1776 ht.Comment("Status for every exported disk")(ht.TListOf(ht.TBool)),
1780 class OpBackupRemove(OpCode):
1781 """Remove an instance's export."""
1782 OP_DSC_FIELD = "instance_name"
1786 OP_RESULT = ht.TNone
1790 class OpTagsGet(OpCode):
1791 """Returns the tags of the given object."""
1792 OP_DSC_FIELD = "name"
1795 # Not using _PUseLocking as the default is different for historical reasons
1796 ("use_locking", True, ht.TBool, "Whether to use synchronization"),
1797 # Name is only meaningful for nodes and instances
1798 ("name", ht.NoDefault, ht.TMaybeString,
1799 "Name of object to retrieve tags from"),
1801 OP_RESULT = ht.TListOf(ht.TNonEmptyString)
1804 class OpTagsSearch(OpCode):
1805 """Searches the tags in the cluster for a given pattern."""
1806 OP_DSC_FIELD = "pattern"
1808 ("pattern", ht.NoDefault, ht.TNonEmptyString,
1809 "Search pattern (regular expression)"),
1811 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(2), ht.TItems([
1817 class OpTagsSet(OpCode):
1818 """Add a list of tags on a given object."""
1822 # Name is only meaningful for nodes and instances
1823 ("name", ht.NoDefault, ht.TMaybeString,
1824 "Name of object where tag(s) should be added"),
1826 OP_RESULT = ht.TNone
1829 class OpTagsDel(OpCode):
1830 """Remove a list of tags from a given object."""
1834 # Name is only meaningful for nodes and instances
1835 ("name", ht.NoDefault, ht.TMaybeString,
1836 "Name of object where tag(s) should be deleted"),
1838 OP_RESULT = ht.TNone
1842 class OpTestDelay(OpCode):
1843 """Sleeps for a configured amount of time.
1845 This is used just for debugging and testing.
1848 - duration: the time to sleep
1849 - on_master: if true, sleep on the master
1850 - on_nodes: list of nodes in which to sleep
1852 If the on_master parameter is true, it will execute a sleep on the
1853 master (before any node sleep).
1855 If the on_nodes list is not empty, it will sleep on those nodes
1856 (after the sleep on the master, if that is enabled).
1858 As an additional feature, the case of duration < 0 will be reported
1859 as an execution error, so this opcode can be used as a failure
1860 generator. The case of duration == 0 will not be treated specially.
1863 OP_DSC_FIELD = "duration"
1865 ("duration", ht.NoDefault, ht.TNumber, None),
1866 ("on_master", True, ht.TBool, None),
1867 ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
1868 ("repeat", 0, ht.TPositiveInt, None),
1872 class OpTestAllocator(OpCode):
1873 """Allocator framework testing.
1875 This opcode has two modes:
1876 - gather and return allocator input for a given mode (allocate new
1877 or replace secondary) and a given instance definition (direction
1879 - run a selected allocator for a given operation (as above) and
1880 return the allocator output (direction 'out')
1883 OP_DSC_FIELD = "allocator"
1885 ("direction", ht.NoDefault,
1886 ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS), None),
1887 ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES), None),
1888 ("name", ht.NoDefault, ht.TNonEmptyString, None),
1889 ("nics", ht.NoDefault,
1890 ht.TMaybeListOf(ht.TDictOf(ht.TElemOf([constants.INIC_MAC,
1893 ht.TOr(ht.TNone, ht.TNonEmptyString))),
1895 ("disks", ht.NoDefault, ht.TOr(ht.TNone, ht.TList), None),
1896 ("hypervisor", None, ht.TMaybeString, None),
1897 ("allocator", None, ht.TMaybeString, None),
1898 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
1899 ("memory", None, ht.TOr(ht.TNone, ht.TPositiveInt), None),
1900 ("vcpus", None, ht.TOr(ht.TNone, ht.TPositiveInt), None),
1901 ("os", None, ht.TMaybeString, None),
1902 ("disk_template", None, ht.TMaybeString, None),
1903 ("instances", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
1905 ht.TOr(ht.TNone, ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)), None),
1906 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
1910 class OpTestJqueue(OpCode):
1911 """Utility opcode to test some aspects of the job queue.
1915 ("notify_waitlock", False, ht.TBool, None),
1916 ("notify_exec", False, ht.TBool, None),
1917 ("log_messages", ht.EmptyList, ht.TListOf(ht.TString), None),
1918 ("fail", False, ht.TBool, None),
1922 class OpTestDummy(OpCode):
1923 """Utility opcode used by unittests.
1927 ("result", ht.NoDefault, ht.NoType, None),
1928 ("messages", ht.NoDefault, ht.NoType, None),
1929 ("fail", ht.NoDefault, ht.NoType, None),
1930 ("submit_jobs", None, ht.NoType, None),
1936 # Add a new network in the cluster
1937 class OpNetworkAdd(OpCode):
1938 """Add an IP network to the cluster."""
1939 OP_DSC_FIELD = "network_name"
1943 ("network", None, ht.TAnd(ht.TString ,_CheckCIDRNetNotation), None),
1944 ("gateway", None, ht.TOr(ht.TNone, _CheckCIDRAddrNotation), None),
1945 ("network6", None, ht.TOr(ht.TNone, _CheckCIDR6NetNotation), None),
1946 ("gateway6", None, ht.TOr(ht.TNone, _CheckCIDR6AddrNotation), None),
1947 ("mac_prefix", None, ht.TMaybeString, None),
1948 ("add_reserved_ips", None,
1949 ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
1950 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Network tags"),
1953 class OpNetworkRemove(OpCode):
1954 """Remove an existing network from the cluster.
1955 Must not be connected to any nodegroup.
1958 OP_DSC_FIELD = "network_name"
1964 class OpNetworkSetParams(OpCode):
1965 """Modify Network's parameters except for IPv4 subnet"""
1966 OP_DSC_FIELD = "network_name"
1970 ("gateway", None, ht.TOr(ht.TNone, _CheckCIDRAddrNotation), None),
1971 ("network6", None, ht.TOr(ht.TNone, _CheckCIDR6NetNotation), None),
1972 ("gateway6", None, ht.TOr(ht.TNone, _CheckCIDR6AddrNotation), None),
1973 ("mac_prefix", None, ht.TMaybeString, None),
1974 ("add_reserved_ips", None,
1975 ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
1976 ("remove_reserved_ips", None,
1977 ht.TOr(ht.TNone, ht.TListOf(_CheckCIDRAddrNotation)), None),
1980 class OpNetworkConnect(OpCode):
1981 """Connect a Network to a specific Nodegroup with the defined netparams
1982 (mode, link). Nics in this Network will inherit those params.
1983 Produce errors if a NIC (that its not already assigned to a network)
1984 has an IP that is contained in the Network this will produce error unless
1985 --no-conflicts-check is passed.
1988 OP_DSC_FIELD = "network_name"
1992 ("network_mode", None, ht.TString, None),
1993 ("network_link", None, ht.TString, None),
1994 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1997 class OpNetworkDisconnect(OpCode):
1998 """Disconnect a Network from a Nodegroup. Produce errors if NICs are
1999 present in the Network unless --no-conficts-check option is passed.
2002 OP_DSC_FIELD = "network_name"
2006 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
2009 class OpNetworkQuery(OpCode):
2010 """Compute the list of networks."""
2013 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
2014 "Empty list to query all groups, group names otherwise"),
2019 """Returns list of all defined opcodes.
2021 Does not eliminate duplicates by C{OP_ID}.
2024 return [v for v in globals().values()
2025 if (isinstance(v, type) and issubclass(v, OpCode) and
2026 hasattr(v, "OP_ID") and v is not OpCode)]
2029 OP_MAPPING = dict((v.OP_ID, v) for v in _GetOpList())