1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """OpCodes module
23
24 This module implements the data structures which define the cluster
25 operations - the so-called opcodes.
26
27 Every operation which modifies the cluster state is expressed via
28 opcodes.
29
30 """
31
32
33
34
35
36 import logging
37 import re
38 import ipaddr
39
40 from ganeti import constants
41 from ganeti import errors
42 from ganeti import ht
43 from ganeti import objects
44 from ganeti import outils
45
46
47
48
49
50 _POutputFields = ("output_fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
51 "Selected output fields")
52
53
54 _PShutdownTimeout = \
55 ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TNonNegativeInt,
56 "How long to wait for instance to shut down")
57
58
59 _PForce = ("force", False, ht.TBool, "Whether to force the operation")
60
61
62 _PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString,
63 "Instance name")
64
65
66 _PInstanceUuid = ("instance_uuid", None, ht.TMaybeString,
67 "Instance UUID")
68
69
70 _PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool,
71 "Whether to ignore offline nodes")
72
73
74 _PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString, "Node name")
75
76
77 _PNodeUuid = ("node_uuid", None, ht.TMaybeString, "Node UUID")
78
79
80 _PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString, "Group name")
81
82
83 _PMigrationMode = ("mode", None,
84 ht.TMaybe(ht.TElemOf(constants.HT_MIGRATION_MODES)),
85 "Migration mode")
86
87
88 _PMigrationLive = ("live", None, ht.TMaybeBool,
89 "Legacy setting for live migration, do not use")
90
91
92 _PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES),
93 "Tag kind")
94
95
96 _PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
97 "List of tag names")
98
99 _PForceVariant = ("force_variant", False, ht.TBool,
100 "Whether to force an unknown OS variant")
101
102 _PWaitForSync = ("wait_for_sync", True, ht.TBool,
103 "Whether to wait for the disk to synchronize")
104
105 _PWaitForSyncFalse = ("wait_for_sync", False, ht.TBool,
106 "Whether to wait for the disk to synchronize"
107 " (defaults to false)")
108
109 _PIgnoreConsistency = ("ignore_consistency", False, ht.TBool,
110 "Whether to ignore disk consistency")
111
112 _PStorageName = ("name", ht.NoDefault, ht.TMaybeString, "Storage name")
113
114 _PUseLocking = ("use_locking", False, ht.TBool,
115 "Whether to use synchronization")
116
117 _PNameCheck = ("name_check", True, ht.TBool, "Whether to check name")
118
119 _PNodeGroupAllocPolicy = \
120 ("alloc_policy", None,
121 ht.TMaybe(ht.TElemOf(constants.VALID_ALLOC_POLICIES)),
122 "Instance allocation policy")
123
124 _PGroupNodeParams = ("ndparams", None, ht.TMaybeDict,
125 "Default node parameters for group")
126
127 _PQueryWhat = ("what", ht.NoDefault, ht.TElemOf(constants.QR_VIA_OP),
128 "Resource(s) to query for")
129
130 _PEarlyRelease = ("early_release", False, ht.TBool,
131 "Whether to release locks as soon as possible")
132
133 _PIpCheckDoc = "Whether to ensure instance's IP address is inactive"
134
135
136 _PNoRemember = ("no_remember", False, ht.TBool,
137 "Do not remember the state change")
138
139
140 _PMigrationTargetNode = ("target_node", None, ht.TMaybeString,
141 "Target node for shared-storage instances")
142
143 _PMigrationTargetNodeUuid = ("target_node_uuid", None, ht.TMaybeString,
144 "Target node UUID for shared-storage instances")
145
146 _PStartupPaused = ("startup_paused", False, ht.TBool,
147 "Pause instance at startup")
148
149 _PVerbose = ("verbose", False, ht.TBool, "Verbose mode")
150
151
152 _PDebugSimulateErrors = ("debug_simulate_errors", False, ht.TBool,
153 "Whether to simulate errors (useful for debugging)")
154 _PErrorCodes = ("error_codes", False, ht.TBool, "Error codes")
155 _PSkipChecks = ("skip_checks", ht.EmptyList,
156 ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS)),
157 "Which checks to skip")
158 _PIgnoreErrors = ("ignore_errors", ht.EmptyList,
159 ht.TListOf(ht.TElemOf(constants.CV_ALL_ECODES_STRINGS)),
160 "List of error codes that should be treated as warnings")
161
162
163 _PDiskParams = \
164 ("diskparams", None,
165 ht.TMaybe(ht.TDictOf(ht.TElemOf(constants.DISK_TEMPLATES), ht.TDict)),
166 "Disk templates' parameter defaults")
167
168
169 _PHvState = ("hv_state", None, ht.TMaybeDict, "Set hypervisor states")
170 _PDiskState = ("disk_state", None, ht.TMaybeDict, "Set disk states")
171
172
173 _POpportunisticLocking = \
174 ("opportunistic_locking", False, ht.TBool,
175 ("Whether to employ opportunistic locking for nodes, meaning nodes"
176 " already locked by another opcode won't be considered for instance"
177 " allocation (only when an iallocator is used)"))
178
179 _PIgnoreIpolicy = ("ignore_ipolicy", False, ht.TBool,
180 "Whether to ignore ipolicy violations")
181
182
183 _PAllowRuntimeChgs = ("allow_runtime_changes", True, ht.TBool,
184 "Allow runtime changes (eg. memory ballooning)")
185
186
187 _PIAllocFromDesc = lambda desc: ("iallocator", None, ht.TMaybeString, desc)
188
189
190 _PNetworkName = ("network_name", ht.NoDefault, ht.TNonEmptyString,
191 "Set network name")
192
193 _PTargetGroups = \
194 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString),
195 "Destination group names or UUIDs (defaults to \"all but current group\")")
196
197
198 _OPID_RE = re.compile("([a-z])([A-Z])")
199
200
201 _TestClusterOsListItem = \
202 ht.TAnd(ht.TIsLength(2), ht.TItems([
203 ht.TElemOf(constants.DDMS_VALUES),
204 ht.TNonEmptyString,
205 ]))
206
207 _TestClusterOsList = ht.TMaybeListOf(_TestClusterOsListItem)
208
209
210
211 _TestNicDef = \
212 ht.Comment("NIC parameters")(ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS),
213 ht.TMaybeString))
214
215 _TSetParamsResultItemItems = [
216 ht.Comment("name of changed parameter")(ht.TNonEmptyString),
217 ht.Comment("new value")(ht.TAny),
218 ]
219
220 _TSetParamsResult = \
221 ht.TListOf(ht.TAnd(ht.TIsLength(len(_TSetParamsResultItemItems)),
222 ht.TItems(_TSetParamsResultItemItems)))
223
224
225
226
227
228 _TDiskParams = \
229 ht.Comment("Disk parameters")(ht.TDictOf(ht.TNonEmptyString,
230 ht.TOr(ht.TNonEmptyString, ht.TInt)))
231
232 _TQueryRow = \
233 ht.TListOf(ht.TAnd(ht.TIsLength(2),
234 ht.TItems([ht.TElemOf(constants.RS_ALL),
235 ht.TAny])))
236
237 _TQueryResult = ht.TListOf(_TQueryRow)
238
239 _TOldQueryRow = ht.TListOf(ht.TAny)
240
241 _TOldQueryResult = ht.TListOf(_TOldQueryRow)
242
243
244 _SUMMARY_PREFIX = {
245 "CLUSTER_": "C_",
246 "GROUP_": "G_",
247 "NODE_": "N_",
248 "INSTANCE_": "I_",
249 }
250
251
252 DEPEND_ATTR = "depends"
253
254
255 COMMENT_ATTR = "comment"
259 """Split an opcode class name into its components
260
261 @type name: string
262 @param name: the class name, as OpXxxYyy
263 @rtype: array of strings
264 @return: the components of the name
265
266 """
267 assert name.startswith("Op")
268
269
270
271
272
273 name = _OPID_RE.sub(r"\1,\2", name)
274 elems = name.split(",")
275 return elems
276
279 """Convert an opcode class name to an OP_ID.
280
281 @type name: string
282 @param name: the class name, as OpXxxYyy
283 @rtype: string
284 @return: the name in the OP_XXXX_YYYY format
285
286 """
287 if not name.startswith("Op"):
288 return None
289 return "_".join(n.upper() for n in _NameComponents(name))
290
293 """Convert an opcode class name to a source string for the reason trail
294
295 @type name: string
296 @param name: the class name, as OpXxxYyy
297 @rtype: string
298 @return: the name in the OP_XXXX_YYYY format
299
300 """
301 if not name.startswith("Op"):
302 return None
303 return "%s:%s" % (constants.OPCODE_REASON_SRC_OPCODE,
304 "_".join(n.lower() for n in _NameComponents(name)))
305
308 """Helper to generate type checks for objects.
309
310 @param obj: The object to generate type checks
311 @param fields_types: The fields and their types as a dict
312 @return: A ht type check function
313
314 """
315 assert set(obj.GetAllSlots()) == set(fields_types.keys()), \
316 "%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys()))
317 return ht.TStrictDict(True, True, fields_types)
318
319
320 _TQueryFieldDef = \
321 _GenerateObjectTypeCheck(objects.QueryFieldDefinition, {
322 "name": ht.TNonEmptyString,
323 "title": ht.TNonEmptyString,
324 "kind": ht.TElemOf(constants.QFT_ALL),
325 "doc": ht.TNonEmptyString,
326 })
330 """Builds check for disk template.
331
332 @type accept_none: bool
333 @param accept_none: whether to accept None as a correct value
334 @rtype: callable
335
336 """
337 template_check = ht.TElemOf(constants.DISK_TEMPLATES)
338
339 if accept_none:
340 template_check = ht.TMaybe(template_check)
341
342 return template_check
343
353
354
355
356 _PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType,
357 "Storage type")
362 """Ensure a given CIDR notation type is valid.
363
364 """
365 try:
366 ipaddr.IPv4Network(value)
367 except ipaddr.AddressValueError:
368 return False
369 return True
370
374 """Ensure a given CIDR notation type is valid.
375
376 """
377 try:
378 ipaddr.IPv4Address(value)
379 except ipaddr.AddressValueError:
380 return False
381 return True
382
386 """Ensure a given CIDR notation type is valid.
387
388 """
389 try:
390 ipaddr.IPv6Address(value)
391 except ipaddr.AddressValueError:
392 return False
393 return True
394
398 """Ensure a given CIDR notation type is valid.
399
400 """
401 try:
402 ipaddr.IPv6Network(value)
403 except ipaddr.AddressValueError:
404 return False
405 return True
406
407
408 _TIpAddress4 = ht.TAnd(ht.TString, _CheckCIDRAddrNotation)
409 _TIpAddress6 = ht.TAnd(ht.TString, _CheckCIDR6AddrNotation)
410 _TIpNetwork4 = ht.TAnd(ht.TString, _CheckCIDRNetNotation)
411 _TIpNetwork6 = ht.TAnd(ht.TString, _CheckCIDR6NetNotation)
412 _TMaybeAddr4List = ht.TMaybe(ht.TListOf(_TIpAddress4))
416 """Meta class for opcode definitions.
417
418 """
419 - def __new__(mcs, name, bases, attrs):
420 """Called when a class should be created.
421
422 @param mcs: The meta class
423 @param name: Name of created class
424 @param bases: Base classes
425 @type attrs: dict
426 @param attrs: Class attributes
427
428 """
429 assert "OP_ID" not in attrs, "Class '%s' defining OP_ID" % name
430
431 slots = mcs._GetSlots(attrs)
432 assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
433 "Class '%s' uses unknown field in OP_DSC_FIELD" % name
434 assert ("OP_DSC_FORMATTER" not in attrs or
435 callable(attrs["OP_DSC_FORMATTER"])), \
436 ("Class '%s' uses non-callable in OP_DSC_FORMATTER (%s)" %
437 (name, type(attrs["OP_DSC_FORMATTER"])))
438
439 attrs["OP_ID"] = _NameToId(name)
440
441 return outils.AutoSlots.__new__(mcs, name, bases, attrs)
442
443 @classmethod
445 """Build the slots out of OP_PARAMS.
446
447 """
448
449 params = attrs.setdefault("OP_PARAMS", [])
450
451
452 return [pname for (pname, _, _, _) in params]
453
456 """A simple serializable object.
457
458 This object serves as a parent class for OpCode without any custom
459 field handling.
460
461 """
462
463
464 __metaclass__ = _AutoOpParamSlots
465
467 """Generic serializer.
468
469 This method just returns the contents of the instance as a
470 dictionary.
471
472 @rtype: C{dict}
473 @return: the instance attributes and their values
474
475 """
476 state = {}
477 for name in self.GetAllSlots():
478 if hasattr(self, name):
479 state[name] = getattr(self, name)
480 return state
481
483 """Generic unserializer.
484
485 This method just restores from the serialized state the attributes
486 of the current instance.
487
488 @param state: the serialized opcode data
489 @type state: C{dict}
490
491 """
492 if not isinstance(state, dict):
493 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
494 type(state))
495
496 for name in self.GetAllSlots():
497 if name not in state and hasattr(self, name):
498 delattr(self, name)
499
500 for name in state:
501 setattr(self, name, state[name])
502
503 @classmethod
505 """Compute list of all parameters for an opcode.
506
507 """
508 slots = []
509 for parent in cls.__mro__:
510 slots.extend(getattr(parent, "OP_PARAMS", []))
511 return slots
512
514 """Validate opcode parameters, optionally setting default values.
515
516 @type set_defaults: bool
517 @param set_defaults: Whether to set default values
518 @raise errors.OpPrereqError: When a parameter value doesn't match
519 requirements
520
521 """
522 for (attr_name, default, test, _) in self.GetAllParams():
523 assert test == ht.NoType or callable(test)
524
525 if not hasattr(self, attr_name):
526 if default == ht.NoDefault:
527 raise errors.OpPrereqError("Required parameter '%s.%s' missing" %
528 (self.OP_ID, attr_name),
529 errors.ECODE_INVAL)
530 elif set_defaults:
531 if callable(default):
532 dval = default()
533 else:
534 dval = default
535 setattr(self, attr_name, dval)
536
537 if test == ht.NoType:
538
539 continue
540
541 if set_defaults or hasattr(self, attr_name):
542 attr_val = getattr(self, attr_name)
543 if not test(attr_val):
544 logging.error("OpCode %s, parameter %s, has invalid type %s/value"
545 " '%s' expecting type %s",
546 self.OP_ID, attr_name, type(attr_val), attr_val, test)
547 raise errors.OpPrereqError("Parameter '%s.%s' fails validation" %
548 (self.OP_ID, attr_name),
549 errors.ECODE_INVAL)
550
572
573
574 TNoRelativeJobDependencies = _BuildJobDepCheck(False)
575
576
577 _TJobIdListItem = \
578 ht.TAnd(ht.TIsLength(2),
579 ht.TItems([ht.Comment("success")(ht.TBool),
580 ht.Comment("Job ID if successful, error message"
581 " otherwise")(ht.TOr(ht.TString,
582 ht.TJobId))]))
583 TJobIdList = ht.TListOf(_TJobIdListItem)
584
585
586 TJobIdListOnly = ht.TStrictDict(True, True, {
587 constants.JOB_IDS_KEY: ht.Comment("List of submitted jobs")(TJobIdList),
588 })
589
590
591 -class OpCode(BaseOpCode):
592 """Abstract OpCode.
593
594 This is the root of the actual OpCode hierarchy. All clases derived
595 from this class should override OP_ID.
596
597 @cvar OP_ID: The ID of this opcode. This should be unique amongst all
598 children of this class.
599 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
600 string returned by Summary(); see the docstring of that
601 method for details).
602 @cvar OP_DSC_FORMATTER: A callable that should format the OP_DSC_FIELD; if
603 not present, then the field will be simply converted
604 to string
605 @cvar OP_PARAMS: List of opcode attributes, the default values they should
606 get if not already defined, and types they must match.
607 @cvar OP_RESULT: Callable to verify opcode result
608 @cvar WITH_LU: Boolean that specifies whether this should be included in
609 mcpu's dispatch table
610 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
611 the check steps
612 @ivar priority: Opcode priority for queue
613
614 """
615
616
617 WITH_LU = True
618 OP_PARAMS = [
619 ("dry_run", None, ht.TMaybeBool, "Run checks only, don't execute"),
620 ("debug_level", None, ht.TMaybe(ht.TNonNegativeInt), "Debug level"),
621 ("priority", constants.OP_PRIO_DEFAULT,
622 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"),
623 (DEPEND_ATTR, None, _BuildJobDepCheck(True),
624 "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)"
625 " job IDs can be used; see :doc:`design document <design-chained-jobs>`"
626 " for details"),
627 (COMMENT_ATTR, None, ht.TMaybeString,
628 "Comment describing the purpose of the opcode"),
629 (constants.OPCODE_REASON, ht.EmptyList, ht.TMaybeList,
630 "The reason trail, describing why the OpCode is executed"),
631 ]
632 OP_RESULT = None
633
635 """Specialized getstate for opcodes.
636
637 This method adds to the state dictionary the OP_ID of the class,
638 so that on unload we can identify the correct class for
639 instantiating the opcode.
640
641 @rtype: C{dict}
642 @return: the state as a dictionary
643
644 """
645 data = BaseOpCode.__getstate__(self)
646 data["OP_ID"] = self.OP_ID
647 return data
648
649 @classmethod
651 """Generic load opcode method.
652
653 The method identifies the correct opcode class from the dict-form
654 by looking for a OP_ID key, if this is not found, or its value is
655 not available in this module as a child of this class, we fail.
656
657 @type data: C{dict}
658 @param data: the serialized opcode
659
660 """
661 if not isinstance(data, dict):
662 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
663 if "OP_ID" not in data:
664 raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
665 op_id = data["OP_ID"]
666 op_class = None
667 if op_id in OP_MAPPING:
668 op_class = OP_MAPPING[op_id]
669 else:
670 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
671 op_id)
672 op = op_class()
673 new_data = data.copy()
674 del new_data["OP_ID"]
675 op.__setstate__(new_data)
676 return op
677
679 """Generates a summary description of this opcode.
680
681 The summary is the value of the OP_ID attribute (without the "OP_"
682 prefix), plus the value of the OP_DSC_FIELD attribute, if one was
683 defined; this field should allow to easily identify the operation
684 (for an instance creation job, e.g., it would be the instance
685 name).
686
687 """
688 assert self.OP_ID is not None and len(self.OP_ID) > 3
689
690 txt = self.OP_ID[3:]
691 field_name = getattr(self, "OP_DSC_FIELD", None)
692 if field_name:
693 field_value = getattr(self, field_name, None)
694 field_formatter = getattr(self, "OP_DSC_FORMATTER", None)
695 if callable(field_formatter):
696 field_value = field_formatter(field_value)
697 elif isinstance(field_value, (list, tuple)):
698 field_value = ",".join(str(i) for i in field_value)
699 txt = "%s(%s)" % (txt, field_value)
700 return txt
701
703 """Generates a compact summary description of the opcode.
704
705 """
706 assert self.OP_ID.startswith("OP_")
707
708 text = self.OP_ID[3:]
709
710 for (prefix, supplement) in _SUMMARY_PREFIX.items():
711 if text.startswith(prefix):
712 return supplement + text[len(prefix):]
713
714 return text
715
716
717
718
719 -class OpClusterPostInit(OpCode):
720 """Post cluster initialization.
721
722 This opcode does not touch the cluster at all. Its purpose is to run hooks
723 after the cluster has been initialized.
724
725 """
726 OP_RESULT = ht.TBool
727
730 """Destroy the cluster.
731
732 This opcode has no other parameters. All the state is irreversibly
733 lost after the execution of this opcode.
734
735 """
736 OP_RESULT = ht.TNonEmptyString
737
742
757
770
792
799
802 """Verifies the status of all disks in a node group.
803
804 Result: a tuple of three elements:
805 - dict of node names with issues (values: error msg)
806 - list of instances with degraded disks (that should be activated)
807 - dict of instances with missing logical volumes (values: (node, vol)
808 pairs with details about the missing volumes)
809
810 In normal operation, all lists should be empty. A non-empty instance
811 list (3rd element of the result) is still ok (errors were fixed) but
812 non-empty node list means some node is down, and probably there are
813 unfixable drbd errors.
814
815 Note that only instances that are drbd-based are taken into
816 consideration. This might need to be revisited in the future.
817
818 """
819 OP_DSC_FIELD = "group_name"
820 OP_PARAMS = [
821 _PGroupName,
822 ]
823 OP_RESULT = \
824 ht.TAnd(ht.TIsLength(3),
825 ht.TItems([ht.TDictOf(ht.TString, ht.TString),
826 ht.TListOf(ht.TString),
827 ht.TDictOf(ht.TString,
828 ht.TListOf(ht.TListOf(ht.TString)))]))
829
832 """Verify the disk sizes of the instances and fixes configuration
833 mimatches.
834
835 Parameters: optional instances list, in case we want to restrict the
836 checks to only a subset of the instances.
837
838 Result: a list of tuples, (instance, disk, parameter, new-size) for changed
839 configurations.
840
841 In normal operation, the list should be empty.
842
843 @type instances: list
844 @ivar instances: the list of instances to check, or empty for all instances
845
846 """
847 OP_PARAMS = [
848 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
849 ]
850 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(4),
851 ht.TItems([ht.TNonEmptyString,
852 ht.TNonNegativeInt,
853 ht.TNonEmptyString,
854 ht.TNonNegativeInt])))
855
863
879
882 """Change the parameters of the cluster.
883
884 @type vg_name: C{str} or C{None}
885 @ivar vg_name: The new volume group name or None to disable LVM usage.
886
887 """
888 OP_PARAMS = [
889 _PForce,
890 _PHvState,
891 _PDiskState,
892 ("vg_name", None, ht.TMaybe(ht.TString), "Volume group name"),
893 ("enabled_hypervisors", None,
894 ht.TMaybe(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)),
895 ht.TTrue)),
896 "List of enabled hypervisors"),
897 ("hvparams", None,
898 ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)),
899 "Cluster-wide hypervisor parameter defaults, hypervisor-dependent"),
900 ("beparams", None, ht.TMaybeDict,
901 "Cluster-wide backend parameter defaults"),
902 ("os_hvp", None, ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)),
903 "Cluster-wide per-OS hypervisor parameter defaults"),
904 ("osparams", None,
905 ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)),
906 "Cluster-wide OS parameter defaults"),
907 _PDiskParams,
908 ("candidate_pool_size", None, ht.TMaybe(ht.TPositiveInt),
909 "Master candidate pool size"),
910 ("uid_pool", None, ht.NoType,
911 "Set UID pool, must be list of lists describing UID ranges (two items,"
912 " start and end inclusive)"),
913 ("add_uids", None, ht.NoType,
914 "Extend UID pool, must be list of lists describing UID ranges (two"
915 " items, start and end inclusive) to be added"),
916 ("remove_uids", None, ht.NoType,
917 "Shrink UID pool, must be list of lists describing UID ranges (two"
918 " items, start and end inclusive) to be removed"),
919 ("maintain_node_health", None, ht.TMaybeBool,
920 "Whether to automatically maintain node health"),
921 ("prealloc_wipe_disks", None, ht.TMaybeBool,
922 "Whether to wipe disks before allocating them to instances"),
923 ("nicparams", None, ht.TMaybeDict, "Cluster-wide NIC parameter defaults"),
924 ("ndparams", None, ht.TMaybeDict, "Cluster-wide node parameter defaults"),
925 ("ipolicy", None, ht.TMaybeDict,
926 "Cluster-wide :ref:`instance policy <rapi-ipolicy>` specs"),
927 ("drbd_helper", None, ht.TMaybe(ht.TString), "DRBD helper program"),
928 ("default_iallocator", None, ht.TMaybe(ht.TString),
929 "Default iallocator for cluster"),
930 ("master_netdev", None, ht.TMaybe(ht.TString),
931 "Master network device"),
932 ("master_netmask", None, ht.TMaybe(ht.TNonNegativeInt),
933 "Netmask of the master IP"),
934 ("reserved_lvs", None, ht.TMaybeListOf(ht.TNonEmptyString),
935 "List of reserved LVs"),
936 ("hidden_os", None, _TestClusterOsList,
937 "Modify list of hidden operating systems: each modification must have"
938 " two items, the operation and the OS name; the operation can be"
939 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)),
940 ("blacklisted_os", None, _TestClusterOsList,
941 "Modify list of blacklisted operating systems: each modification must"
942 " have two items, the operation and the OS name; the operation can be"
943 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)),
944 ("use_external_mip_script", None, ht.TMaybeBool,
945 "Whether to use an external master IP address setup script"),
946 ("enabled_disk_templates", None,
947 ht.TMaybe(ht.TAnd(ht.TListOf(ht.TElemOf(constants.DISK_TEMPLATES)),
948 ht.TTrue)),
949 "List of enabled disk templates"),
950 ("modify_etc_hosts", None, ht.TMaybeBool,
951 "Whether the cluster can modify and keep in sync the /etc/hosts files"),
952 ("file_storage_dir", None, ht.TMaybe(ht.TString),
953 "Default directory for storing file-backed disks"),
954 ("shared_file_storage_dir", None, ht.TMaybe(ht.TString),
955 "Default directory for storing shared-file-backed disks"),
956 ]
957 OP_RESULT = ht.TNone
958
961 """Force a full push of the cluster configuration.
962
963 """
964 OP_RESULT = ht.TNone
965
968 """Activate the master IP on the master node.
969
970 """
971 OP_RESULT = ht.TNone
972
975 """Deactivate the master IP on the master node.
976
977 """
978 OP_RESULT = ht.TNone
979
982 """Query for resources/items.
983
984 @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP}
985 @ivar fields: List of fields to retrieve
986 @ivar qfilter: Query filter
987
988 """
989 OP_DSC_FIELD = "what"
990 OP_PARAMS = [
991 _PQueryWhat,
992 _PUseLocking,
993 ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
994 "Requested fields"),
995 ("qfilter", None, ht.TMaybe(ht.TList),
996 "Query filter"),
997 ]
998 OP_RESULT = \
999 _GenerateObjectTypeCheck(objects.QueryResponse, {
1000 "fields": ht.TListOf(_TQueryFieldDef),
1001 "data": _TQueryResult,
1002 })
1003
1022
1025 """Interact with OOB."""
1026 OP_PARAMS = [
1027 ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1028 "List of node names to run the OOB command against"),
1029 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString),
1030 "List of node UUIDs to run the OOB command against"),
1031 ("command", ht.NoDefault, ht.TElemOf(constants.OOB_COMMANDS),
1032 "OOB command to be run"),
1033 ("timeout", constants.OOB_TIMEOUT, ht.TInt,
1034 "Timeout before the OOB helper will be terminated"),
1035 ("ignore_status", False, ht.TBool,
1036 "Ignores the node offline status for power off"),
1037 ("power_delay", constants.OOB_POWER_DELAY, ht.TNonNegativeFloat,
1038 "Time in seconds to wait between powering on nodes"),
1039 ]
1040
1041 OP_RESULT = _TQueryResult
1042
1045 """Runs a restricted command on node(s).
1046
1047 """
1048 OP_PARAMS = [
1049 _PUseLocking,
1050 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
1051 "Nodes on which the command should be run (at least one)"),
1052 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString),
1053 "Node UUIDs on which the command should be run (at least one)"),
1054 ("command", ht.NoDefault, ht.TNonEmptyString,
1055 "Command name (no parameters)"),
1056 ]
1057
1058 _RESULT_ITEMS = [
1059 ht.Comment("success")(ht.TBool),
1060 ht.Comment("output or error message")(ht.TString),
1061 ]
1062
1063 OP_RESULT = \
1064 ht.TListOf(ht.TAnd(ht.TIsLength(len(_RESULT_ITEMS)),
1065 ht.TItems(_RESULT_ITEMS)))
1066
1071 """Remove a node.
1072
1073 @type node_name: C{str}
1074 @ivar node_name: The name of the node to remove. If the node still has
1075 instances on it, the operation will fail.
1076
1077 """
1078 OP_DSC_FIELD = "node_name"
1079 OP_PARAMS = [
1080 _PNodeName,
1081 _PNodeUuid
1082 ]
1083 OP_RESULT = ht.TNone
1084
1087 """Add a node to the cluster.
1088
1089 @type node_name: C{str}
1090 @ivar node_name: The name of the node to add. This can be a short name,
1091 but it will be expanded to the FQDN.
1092 @type primary_ip: IP address
1093 @ivar primary_ip: The primary IP of the node. This will be ignored when the
1094 opcode is submitted, but will be filled during the node
1095 add (so it will be visible in the job query).
1096 @type secondary_ip: IP address
1097 @ivar secondary_ip: The secondary IP of the node. This needs to be passed
1098 if the cluster has been initialized in 'dual-network'
1099 mode, otherwise it must not be given.
1100 @type readd: C{bool}
1101 @ivar readd: Whether to re-add an existing node to the cluster. If
1102 this is not passed, then the operation will abort if the node
1103 name is already in the cluster; use this parameter to 'repair'
1104 a node that had its configuration broken, or was reinstalled
1105 without removal from the cluster.
1106 @type group: C{str}
1107 @ivar group: The node group to which this node will belong.
1108 @type vm_capable: C{bool}
1109 @ivar vm_capable: The vm_capable node attribute
1110 @type master_capable: C{bool}
1111 @ivar master_capable: The master_capable node attribute
1112
1113 """
1114 OP_DSC_FIELD = "node_name"
1115 OP_PARAMS = [
1116 _PNodeName,
1117 _PHvState,
1118 _PDiskState,
1119 ("primary_ip", None, ht.NoType, "Primary IP address"),
1120 ("secondary_ip", None, ht.TMaybeString, "Secondary IP address"),
1121 ("readd", False, ht.TBool, "Whether node is re-added to cluster"),
1122 ("group", None, ht.TMaybeString, "Initial node group"),
1123 ("master_capable", None, ht.TMaybeBool,
1124 "Whether node can become master or master candidate"),
1125 ("vm_capable", None, ht.TMaybeBool,
1126 "Whether node can host instances"),
1127 ("ndparams", None, ht.TMaybeDict, "Node parameters"),
1128 ]
1129 OP_RESULT = ht.TNone
1130
1141
1151
1154 """Get information on storage for node(s)."""
1155 OP_PARAMS = [
1156 _POutputFields,
1157 _PStorageType,
1158 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "List of nodes"),
1159 ("name", None, ht.TMaybeString, "Storage name"),
1160 ]
1161 OP_RESULT = _TOldQueryResult
1162
1175
1188
1191 """Change the parameters of a node."""
1192 OP_DSC_FIELD = "node_name"
1193 OP_PARAMS = [
1194 _PNodeName,
1195 _PNodeUuid,
1196 _PForce,
1197 _PHvState,
1198 _PDiskState,
1199 ("master_candidate", None, ht.TMaybeBool,
1200 "Whether the node should become a master candidate"),
1201 ("offline", None, ht.TMaybeBool,
1202 "Whether the node should be marked as offline"),
1203 ("drained", None, ht.TMaybeBool,
1204 "Whether the node should be marked as drained"),
1205 ("auto_promote", False, ht.TBool,
1206 "Whether node(s) should be promoted to master candidate if necessary"),
1207 ("master_capable", None, ht.TMaybeBool,
1208 "Denote whether node can become master or master candidate"),
1209 ("vm_capable", None, ht.TMaybeBool,
1210 "Denote whether node can host instances"),
1211 ("secondary_ip", None, ht.TMaybeString,
1212 "Change node's secondary IP address"),
1213 ("ndparams", None, ht.TMaybeDict, "Set node parameters"),
1214 ("powered", None, ht.TMaybeBool,
1215 "Whether the node should be marked as powered"),
1216 ]
1217 OP_RESULT = _TSetParamsResult
1218
1229
1247
1250 """Evacuate instances off a number of nodes."""
1251 OP_DSC_FIELD = "node_name"
1252 OP_PARAMS = [
1253 _PEarlyRelease,
1254 _PNodeName,
1255 _PNodeUuid,
1256 ("remote_node", None, ht.TMaybeString, "New secondary node"),
1257 ("remote_node_uuid", None, ht.TMaybeString, "New secondary node UUID"),
1258 _PIAllocFromDesc("Iallocator for computing solution"),
1259 ("mode", ht.NoDefault, ht.TElemOf(constants.NODE_EVAC_MODES),
1260 "Node evacuation mode"),
1261 ]
1262 OP_RESULT = TJobIdListOnly
1263
1268 """Create an instance.
1269
1270 @ivar instance_name: Instance name
1271 @ivar mode: Instance creation mode (one of L{constants.INSTANCE_CREATE_MODES})
1272 @ivar source_handshake: Signed handshake from source (remote import only)
1273 @ivar source_x509_ca: Source X509 CA in PEM format (remote import only)
1274 @ivar source_instance_name: Previous name of instance (remote import only)
1275 @ivar source_shutdown_timeout: Shutdown timeout used for source instance
1276 (remote import only)
1277
1278 """
1279 OP_DSC_FIELD = "instance_name"
1280 OP_PARAMS = [
1281 _PInstanceName,
1282 _PForceVariant,
1283 _PWaitForSync,
1284 _PNameCheck,
1285 _PIgnoreIpolicy,
1286 _POpportunisticLocking,
1287 ("beparams", ht.EmptyDict, ht.TDict, "Backend parameters for instance"),
1288 ("disks", ht.NoDefault, ht.TListOf(_TDiskParams),
1289 "Disk descriptions, for example ``[{\"%s\": 100}, {\"%s\": 5}]``;"
1290 " each disk definition must contain a ``%s`` value and"
1291 " can contain an optional ``%s`` value denoting the disk access mode"
1292 " (%s)" %
1293 (constants.IDISK_SIZE, constants.IDISK_SIZE, constants.IDISK_SIZE,
1294 constants.IDISK_MODE,
1295 " or ".join("``%s``" % i for i in sorted(constants.DISK_ACCESS_SET)))),
1296 ("disk_template", ht.NoDefault, _BuildDiskTemplateCheck(True),
1297 "Disk template"),
1298 ("file_driver", None, ht.TMaybe(ht.TElemOf(constants.FILE_DRIVER)),
1299 "Driver for file-backed disks"),
1300 ("file_storage_dir", None, ht.TMaybeString,
1301 "Directory for storing file-backed disks"),
1302 ("hvparams", ht.EmptyDict, ht.TDict,
1303 "Hypervisor parameters for instance, hypervisor-dependent"),
1304 ("hypervisor", None, ht.TMaybeString, "Hypervisor"),
1305 _PIAllocFromDesc("Iallocator for deciding which node(s) to use"),
1306 ("identify_defaults", False, ht.TBool,
1307 "Reset instance parameters to default if equal"),
1308 ("ip_check", True, ht.TBool, _PIpCheckDoc),
1309 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1310 ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES),
1311 "Instance creation mode"),
1312 ("nics", ht.NoDefault, ht.TListOf(_TestNicDef),
1313 "List of NIC (network interface) definitions, for example"
1314 " ``[{}, {}, {\"%s\": \"198.51.100.4\"}]``; each NIC definition can"
1315 " contain the optional values %s" %
1316 (constants.INIC_IP,
1317 ", ".join("``%s``" % i for i in sorted(constants.INIC_PARAMS)))),
1318 ("no_install", None, ht.TMaybeBool,
1319 "Do not install the OS (will disable automatic start)"),
1320 ("osparams", ht.EmptyDict, ht.TDict, "OS parameters for instance"),
1321 ("os_type", None, ht.TMaybeString, "Operating system"),
1322 ("pnode", None, ht.TMaybeString, "Primary node"),
1323 ("pnode_uuid", None, ht.TMaybeString, "Primary node UUID"),
1324 ("snode", None, ht.TMaybeString, "Secondary node"),
1325 ("snode_uuid", None, ht.TMaybeString, "Secondary node UUID"),
1326 ("source_handshake", None, ht.TMaybe(ht.TList),
1327 "Signed handshake from source (remote import only)"),
1328 ("source_instance_name", None, ht.TMaybeString,
1329 "Source instance name (remote import only)"),
1330 ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
1331 ht.TNonNegativeInt,
1332 "How long source instance was given to shut down (remote import only)"),
1333 ("source_x509_ca", None, ht.TMaybeString,
1334 "Source X509 CA in PEM format (remote import only)"),
1335 ("src_node", None, ht.TMaybeString, "Source node for import"),
1336 ("src_node_uuid", None, ht.TMaybeString, "Source node UUID for import"),
1337 ("src_path", None, ht.TMaybeString, "Source directory for import"),
1338 ("start", True, ht.TBool, "Whether to start instance after creation"),
1339 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Instance tags"),
1340 ]
1341 OP_RESULT = ht.Comment("instance nodes")(ht.TListOf(ht.TNonEmptyString))
1342
1345 """Allocates multiple instances.
1346
1347 """
1348 OP_PARAMS = [
1349 _POpportunisticLocking,
1350 _PIAllocFromDesc("Iallocator used to allocate all the instances"),
1351 ("instances", ht.EmptyList, ht.TListOf(ht.TInstanceOf(OpInstanceCreate)),
1352 "List of instance create opcodes describing the instances to allocate"),
1353 ]
1354 _JOB_LIST = ht.Comment("List of submitted jobs")(TJobIdList)
1355 ALLOCATABLE_KEY = "allocatable"
1356 FAILED_KEY = "allocatable"
1357 OP_RESULT = ht.TStrictDict(True, True, {
1358 constants.JOB_IDS_KEY: _JOB_LIST,
1359 ALLOCATABLE_KEY: ht.TListOf(ht.TNonEmptyString),
1360 FAILED_KEY: ht.TListOf(ht.TNonEmptyString),
1361 })
1362
1372
1374 """Generic unserializer.
1375
1376 This method just restores from the serialized state the attributes
1377 of the current instance.
1378
1379 @param state: the serialized opcode data
1380 @type state: C{dict}
1381
1382 """
1383 if not isinstance(state, dict):
1384 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
1385 type(state))
1386
1387 if "instances" in state:
1388 state["instances"] = map(OpCode.LoadOpCode, state["instances"])
1389
1390 return OpCode.__setstate__(self, state)
1391
1393 """Validates this opcode.
1394
1395 We do this recursively.
1396
1397 """
1398 OpCode.Validate(self, set_defaults)
1399
1400 for inst in self.instances:
1401 inst.Validate(set_defaults)
1402
1405 """Reinstall an instance's OS."""
1406 OP_DSC_FIELD = "instance_name"
1407 OP_PARAMS = [
1408 _PInstanceName,
1409 _PInstanceUuid,
1410 _PForceVariant,
1411 ("os_type", None, ht.TMaybeString, "Instance operating system"),
1412 ("osparams", None, ht.TMaybeDict, "Temporary OS parameters"),
1413 ]
1414 OP_RESULT = ht.TNone
1415
1428
1431 """Rename an instance."""
1432 OP_PARAMS = [
1433 _PInstanceName,
1434 _PInstanceUuid,
1435 _PNameCheck,
1436 ("new_name", ht.NoDefault, ht.TNonEmptyString, "New instance name"),
1437 ("ip_check", False, ht.TBool, _PIpCheckDoc),
1438 ]
1439 OP_RESULT = ht.Comment("New instance name")(ht.TNonEmptyString)
1440
1443 """Startup an instance."""
1444 OP_DSC_FIELD = "instance_name"
1445 OP_PARAMS = [
1446 _PInstanceName,
1447 _PInstanceUuid,
1448 _PForce,
1449 _PIgnoreOfflineNodes,
1450 ("hvparams", ht.EmptyDict, ht.TDict,
1451 "Temporary hypervisor parameters, hypervisor-dependent"),
1452 ("beparams", ht.EmptyDict, ht.TDict, "Temporary backend parameters"),
1453 _PNoRemember,
1454 _PStartupPaused,
1455 ]
1456 OP_RESULT = ht.TNone
1457
1472
1475 """Reboot an instance."""
1476 OP_DSC_FIELD = "instance_name"
1477 OP_PARAMS = [
1478 _PInstanceName,
1479 _PInstanceUuid,
1480 _PShutdownTimeout,
1481 ("ignore_secondaries", False, ht.TBool,
1482 "Whether to start the instance even if secondary disks are failing"),
1483 ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES),
1484 "How to reboot instance"),
1485 ]
1486 OP_RESULT = ht.TNone
1487
1490 """Replace the disks of an instance."""
1491 OP_DSC_FIELD = "instance_name"
1492 OP_PARAMS = [
1493 _PInstanceName,
1494 _PInstanceUuid,
1495 _PEarlyRelease,
1496 _PIgnoreIpolicy,
1497 ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES),
1498 "Replacement mode"),
1499 ("disks", ht.EmptyList, ht.TListOf(ht.TNonNegativeInt),
1500 "Disk indexes"),
1501 ("remote_node", None, ht.TMaybeString, "New secondary node"),
1502 ("remote_node_uuid", None, ht.TMaybeString, "New secondary node UUID"),
1503 _PIAllocFromDesc("Iallocator for deciding new secondary node"),
1504 ]
1505 OP_RESULT = ht.TNone
1506
1509 """Failover an instance."""
1510 OP_DSC_FIELD = "instance_name"
1511 OP_PARAMS = [
1512 _PInstanceName,
1513 _PInstanceUuid,
1514 _PShutdownTimeout,
1515 _PIgnoreConsistency,
1516 _PMigrationTargetNode,
1517 _PMigrationTargetNodeUuid,
1518 _PIgnoreIpolicy,
1519 _PIAllocFromDesc("Iallocator for deciding the target node for"
1520 " shared-storage instances"),
1521 ("cleanup", False, ht.TBool,
1522 "Whether a previously failed failover should be cleaned up"),
1523 ]
1524 OP_RESULT = ht.TNone
1525
1528 """Migrate an instance.
1529
1530 This migrates (without shutting down an instance) to its secondary
1531 node.
1532
1533 @ivar instance_name: the name of the instance
1534 @ivar mode: the migration mode (live, non-live or None for auto)
1535
1536 """
1537 OP_DSC_FIELD = "instance_name"
1538 OP_PARAMS = [
1539 _PInstanceName,
1540 _PInstanceUuid,
1541 _PMigrationMode,
1542 _PMigrationLive,
1543 _PMigrationTargetNode,
1544 _PMigrationTargetNodeUuid,
1545 _PAllowRuntimeChgs,
1546 _PIgnoreIpolicy,
1547 ("cleanup", False, ht.TBool,
1548 "Whether a previously failed migration should be cleaned up"),
1549 _PIAllocFromDesc("Iallocator for deciding the target node for"
1550 " shared-storage instances"),
1551 ("allow_failover", False, ht.TBool,
1552 "Whether we can fallback to failover if migration is not possible"),
1553 ]
1554 OP_RESULT = ht.TNone
1555
1558 """Move an instance.
1559
1560 This move (with shutting down an instance and data copying) to an
1561 arbitrary node.
1562
1563 @ivar instance_name: the name of the instance
1564 @ivar target_node: the destination node
1565
1566 """
1567 OP_DSC_FIELD = "instance_name"
1568 OP_PARAMS = [
1569 _PInstanceName,
1570 _PInstanceUuid,
1571 _PShutdownTimeout,
1572 _PIgnoreIpolicy,
1573 ("target_node", ht.NoDefault, ht.TNonEmptyString, "Target node"),
1574 ("target_node_uuid", None, ht.TMaybeString, "Target node UUID"),
1575 _PIgnoreConsistency,
1576 ]
1577 OP_RESULT = ht.TNone
1578
1588
1591 """Activate an instance's disks."""
1592 OP_DSC_FIELD = "instance_name"
1593 OP_PARAMS = [
1594 _PInstanceName,
1595 _PInstanceUuid,
1596 ("ignore_size", False, ht.TBool, "Whether to ignore recorded size"),
1597 _PWaitForSyncFalse,
1598 ]
1599 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3),
1600 ht.TItems([ht.TNonEmptyString,
1601 ht.TNonEmptyString,
1602 ht.TNonEmptyString])))
1603
1614
1617 """Recreate an instance's disks."""
1618 _TDiskChanges = \
1619 ht.TAnd(ht.TIsLength(2),
1620 ht.TItems([ht.Comment("Disk index")(ht.TNonNegativeInt),
1621 ht.Comment("Parameters")(_TDiskParams)]))
1622
1623 OP_DSC_FIELD = "instance_name"
1624 OP_PARAMS = [
1625 _PInstanceName,
1626 _PInstanceUuid,
1627 ("disks", ht.EmptyList,
1628 ht.TOr(ht.TListOf(ht.TNonNegativeInt), ht.TListOf(_TDiskChanges)),
1629 "List of disk indexes (deprecated) or a list of tuples containing a disk"
1630 " index and a possibly empty dictionary with disk parameter changes"),
1631 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1632 "New instance nodes, if relocation is desired"),
1633 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString),
1634 "New instance node UUIDs, if relocation is desired"),
1635 _PIAllocFromDesc("Iallocator for deciding new nodes"),
1636 ]
1637 OP_RESULT = ht.TNone
1638
1649
1652 """Compute the run-time status of instances."""
1653 OP_PARAMS = [
1654 _PUseLocking,
1655 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1656 "Instance names"),
1657 ("static", False, ht.TBool,
1658 "Whether to only return configuration data without querying"
1659 " nodes"),
1660 ]
1661 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TDict)
1662
1665 """Generates a check for modification lists.
1666
1667 """
1668
1669
1670 old_mod_item_fn = \
1671 ht.TAnd(ht.TIsLength(2), ht.TItems([
1672 ht.TOr(ht.TElemOf(constants.DDMS_VALUES), ht.TNonNegativeInt),
1673 fn,
1674 ]))
1675
1676
1677 mod_item_fn = \
1678 ht.TAnd(ht.TIsLength(3), ht.TItems([
1679 ht.TElemOf(constants.DDMS_VALUES_WITH_MODIFY),
1680 ht.Comment("Device index, can be negative, e.g. -1 for last disk")
1681 (ht.TOr(ht.TInt, ht.TString)),
1682 fn,
1683 ]))
1684
1685 return ht.TOr(ht.Comment("Recommended")(ht.TListOf(mod_item_fn)),
1686 ht.Comment("Deprecated")(ht.TListOf(old_mod_item_fn)))
1687
1690 """Change the parameters of an instance.
1691
1692 """
1693 TestNicModifications = _TestInstSetParamsModList(_TestNicDef)
1694 TestDiskModifications = _TestInstSetParamsModList(_TDiskParams)
1695
1696 OP_DSC_FIELD = "instance_name"
1697 OP_PARAMS = [
1698 _PInstanceName,
1699 _PInstanceUuid,
1700 _PForce,
1701 _PForceVariant,
1702 _PIgnoreIpolicy,
1703 ("nics", ht.EmptyList, TestNicModifications,
1704 "List of NIC changes: each item is of the form"
1705 " ``(op, identifier, settings)``, ``op`` is one of ``%s``, ``%s`` or"
1706 " ``%s``, ``identifier`` can be a zero-based index number (or -1 to refer"
1707 " to the last position), the NIC's UUID of the NIC's name; a"
1708 " deprecated version of this parameter used the form ``(op, settings)``,"
1709 " where ``op`` can be ``%s`` to add a new NIC with the specified"
1710 " settings, ``%s`` to remove the last NIC or a number to modify the"
1711 " settings of the NIC with that index" %
1712 (constants.DDM_ADD, constants.DDM_MODIFY, constants.DDM_REMOVE,
1713 constants.DDM_ADD, constants.DDM_REMOVE)),
1714 ("disks", ht.EmptyList, TestDiskModifications,
1715 "List of disk changes; see ``nics``"),
1716 ("beparams", ht.EmptyDict, ht.TDict, "Per-instance backend parameters"),
1717 ("runtime_mem", None, ht.TMaybePositiveInt, "New runtime memory"),
1718 ("hvparams", ht.EmptyDict, ht.TDict,
1719 "Per-instance hypervisor parameters, hypervisor-dependent"),
1720 ("disk_template", None, ht.TMaybe(_BuildDiskTemplateCheck(False)),
1721 "Disk template for instance"),
1722 ("pnode", None, ht.TMaybeString, "New primary node"),
1723 ("pnode_uuid", None, ht.TMaybeString, "New primary node UUID"),
1724 ("remote_node", None, ht.TMaybeString,
1725 "Secondary node (used when changing disk template)"),
1726 ("remote_node_uuid", None, ht.TMaybeString,
1727 "Secondary node UUID (used when changing disk template)"),
1728 ("os_name", None, ht.TMaybeString,
1729 "Change the instance's OS without reinstalling the instance"),
1730 ("osparams", None, ht.TMaybeDict, "Per-instance OS parameters"),
1731 ("wait_for_sync", True, ht.TBool,
1732 "Whether to wait for the disk to synchronize, when changing template"),
1733 ("offline", None, ht.TMaybeBool, "Whether to mark instance as offline"),
1734 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1735 ]
1736 OP_RESULT = _TSetParamsResult
1737
1740 """Grow a disk of an instance."""
1741 OP_DSC_FIELD = "instance_name"
1742 OP_PARAMS = [
1743 _PInstanceName,
1744 _PInstanceUuid,
1745 _PWaitForSync,
1746 ("disk", ht.NoDefault, ht.TInt, "Disk index"),
1747 ("amount", ht.NoDefault, ht.TNonNegativeInt,
1748 "Amount of disk space to add (megabytes)"),
1749 ("absolute", False, ht.TBool,
1750 "Whether the amount parameter is an absolute target or a relative one"),
1751 ]
1752 OP_RESULT = ht.TNone
1753
1766
1771 """Add a node group to the cluster."""
1772 OP_DSC_FIELD = "group_name"
1773 OP_PARAMS = [
1774 _PGroupName,
1775 _PNodeGroupAllocPolicy,
1776 _PGroupNodeParams,
1777 _PDiskParams,
1778 _PHvState,
1779 _PDiskState,
1780 ("ipolicy", None, ht.TMaybeDict,
1781 "Group-wide :ref:`instance policy <rapi-ipolicy>` specs"),
1782 ]
1783 OP_RESULT = ht.TNone
1784
1787 """Assign nodes to a node group."""
1788 OP_DSC_FIELD = "group_name"
1789 OP_PARAMS = [
1790 _PGroupName,
1791 _PForce,
1792 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
1793 "List of nodes to assign"),
1794 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString),
1795 "List of node UUIDs to assign"),
1796 ]
1797 OP_RESULT = ht.TNone
1798
1808
1811 """Change the parameters of a node group."""
1812 OP_DSC_FIELD = "group_name"
1813 OP_PARAMS = [
1814 _PGroupName,
1815 _PNodeGroupAllocPolicy,
1816 _PGroupNodeParams,
1817 _PDiskParams,
1818 _PHvState,
1819 _PDiskState,
1820 ("ipolicy", None, ht.TMaybeDict, "Group-wide instance policy specs"),
1821 ]
1822 OP_RESULT = _TSetParamsResult
1823
1832
1841
1853
1864
1875
1888
1905
1908 """Export an instance.
1909
1910 For local exports, the export destination is the node name. For
1911 remote exports, the export destination is a list of tuples, each
1912 consisting of hostname/IP address, port, magic, HMAC and HMAC
1913 salt. The HMAC is calculated using the cluster domain secret over
1914 the value "${index}:${hostname}:${port}". The destination X509 CA
1915 must be a signed certificate.
1916
1917 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1918 @ivar target_node: Export destination
1919 @ivar x509_key_name: X509 key to use (remote export only)
1920 @ivar destination_x509_ca: Destination X509 CA in PEM format (remote export
1921 only)
1922
1923 """
1924 OP_DSC_FIELD = "instance_name"
1925 OP_PARAMS = [
1926 _PInstanceName,
1927 _PInstanceUuid,
1928 _PShutdownTimeout,
1929
1930
1931 ("target_node", ht.NoDefault, ht.TOr(ht.TNonEmptyString, ht.TList),
1932 "Destination information, depends on export mode"),
1933 ("target_node_uuid", None, ht.TMaybeString,
1934 "Target node UUID (if local export)"),
1935 ("shutdown", True, ht.TBool, "Whether to shutdown instance before export"),
1936 ("remove_instance", False, ht.TBool,
1937 "Whether to remove instance after export"),
1938 ("ignore_remove_failures", False, ht.TBool,
1939 "Whether to ignore failures while removing instances"),
1940 ("mode", constants.EXPORT_MODE_LOCAL, ht.TElemOf(constants.EXPORT_MODES),
1941 "Export mode"),
1942 ("x509_key_name", None, ht.TMaybe(ht.TList),
1943 "Name of X509 key (remote export only)"),
1944 ("destination_x509_ca", None, ht.TMaybeString,
1945 "Destination X509 CA (remote export only)"),
1946 ]
1947 OP_RESULT = \
1948 ht.TAnd(ht.TIsLength(2), ht.TItems([
1949 ht.Comment("Finalizing status")(ht.TBool),
1950 ht.Comment("Status for every exported disk")(ht.TListOf(ht.TBool)),
1951 ]))
1952
1962
1977
1990
2002
2014
2018 """Sleeps for a configured amount of time.
2019
2020 This is used just for debugging and testing.
2021
2022 Parameters:
2023 - duration: the time to sleep, in seconds
2024 - on_master: if true, sleep on the master
2025 - on_nodes: list of nodes in which to sleep
2026
2027 If the on_master parameter is true, it will execute a sleep on the
2028 master (before any node sleep).
2029
2030 If the on_nodes list is not empty, it will sleep on those nodes
2031 (after the sleep on the master, if that is enabled).
2032
2033 As an additional feature, the case of duration < 0 will be reported
2034 as an execution error, so this opcode can be used as a failure
2035 generator. The case of duration == 0 will not be treated specially.
2036
2037 """
2038 OP_DSC_FIELD = "duration"
2039 OP_PARAMS = [
2040 ("duration", ht.NoDefault, ht.TNumber, None),
2041 ("on_master", True, ht.TBool, None),
2042 ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
2043 ("on_node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
2044 ("repeat", 0, ht.TNonNegativeInt, None),
2045 ]
2046
2048 """Custom formatter for duration.
2049
2050 """
2051 try:
2052 v = float(value)
2053 except TypeError:
2054 v = value
2055 return str(v)
2056
2059 """Allocator framework testing.
2060
2061 This opcode has two modes:
2062 - gather and return allocator input for a given mode (allocate new
2063 or replace secondary) and a given instance definition (direction
2064 'in')
2065 - run a selected allocator for a given operation (as above) and
2066 return the allocator output (direction 'out')
2067
2068 """
2069 OP_DSC_FIELD = "iallocator"
2070 OP_PARAMS = [
2071 ("direction", ht.NoDefault,
2072 ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS), None),
2073 ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES), None),
2074 ("name", ht.NoDefault, ht.TNonEmptyString, None),
2075 ("nics", ht.NoDefault,
2076 ht.TMaybeListOf(ht.TDictOf(ht.TElemOf([constants.INIC_MAC,
2077 constants.INIC_IP,
2078 "bridge"]),
2079 ht.TMaybeString)),
2080 None),
2081 ("disks", ht.NoDefault, ht.TMaybe(ht.TList), None),
2082 ("hypervisor", None, ht.TMaybeString, None),
2083 _PIAllocFromDesc(None),
2084 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
2085 ("memory", None, ht.TMaybe(ht.TNonNegativeInt), None),
2086 ("vcpus", None, ht.TMaybe(ht.TNonNegativeInt), None),
2087 ("os", None, ht.TMaybeString, None),
2088 ("disk_template", None, ht.TMaybeString, None),
2089 ("instances", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
2090 ("evac_mode", None,
2091 ht.TMaybe(ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)), None),
2092 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
2093 ("spindle_use", 1, ht.TNonNegativeInt, None),
2094 ("count", 1, ht.TNonNegativeInt, None),
2095 ]
2096
2099 """Utility opcode to test some aspects of the job queue.
2100
2101 """
2102 OP_PARAMS = [
2103 ("notify_waitlock", False, ht.TBool, None),
2104 ("notify_exec", False, ht.TBool, None),
2105 ("log_messages", ht.EmptyList, ht.TListOf(ht.TString), None),
2106 ("fail", False, ht.TBool, None),
2107 ]
2108
2111 """Utility opcode used by unittests.
2112
2113 """
2114 OP_PARAMS = [
2115 ("result", ht.NoDefault, ht.NoType, None),
2116 ("messages", ht.NoDefault, ht.NoType, None),
2117 ("fail", ht.NoDefault, ht.NoType, None),
2118 ("submit_jobs", None, ht.NoType, None),
2119 ]
2120 WITH_LU = False
2121
2126 """Add an IP network to the cluster."""
2127 OP_DSC_FIELD = "network_name"
2128 OP_PARAMS = [
2129 _PNetworkName,
2130 ("network", ht.NoDefault, _TIpNetwork4, "IPv4 subnet"),
2131 ("gateway", None, ht.TMaybe(_TIpAddress4), "IPv4 gateway"),
2132 ("network6", None, ht.TMaybe(_TIpNetwork6), "IPv6 subnet"),
2133 ("gateway6", None, ht.TMaybe(_TIpAddress6), "IPv6 gateway"),
2134 ("mac_prefix", None, ht.TMaybeString,
2135 "MAC address prefix that overrides cluster one"),
2136 ("add_reserved_ips", None, _TMaybeAddr4List,
2137 "Which IP addresses to reserve"),
2138 ("conflicts_check", True, ht.TBool,
2139 "Whether to check for conflicting IP addresses"),
2140 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Network tags"),
2141 ]
2142 OP_RESULT = ht.TNone
2143
2156
2159 """Modify Network's parameters except for IPv4 subnet"""
2160 OP_DSC_FIELD = "network_name"
2161 OP_PARAMS = [
2162 _PNetworkName,
2163 ("gateway", None, ht.TMaybeValueNone(_TIpAddress4), "IPv4 gateway"),
2164 ("network6", None, ht.TMaybeValueNone(_TIpNetwork6), "IPv6 subnet"),
2165 ("gateway6", None, ht.TMaybeValueNone(_TIpAddress6), "IPv6 gateway"),
2166 ("mac_prefix", None, ht.TMaybeValueNone(ht.TString),
2167 "MAC address prefix that overrides cluster one"),
2168 ("add_reserved_ips", None, _TMaybeAddr4List,
2169 "Which external IP addresses to reserve"),
2170 ("remove_reserved_ips", None, _TMaybeAddr4List,
2171 "Which external IP addresses to release"),
2172 ]
2173 OP_RESULT = ht.TNone
2174
2177 """Connect a Network to a specific Nodegroup with the defined netparams
2178 (mode, link). Nics in this Network will inherit those params.
2179 Produce errors if a NIC (that its not already assigned to a network)
2180 has an IP that is contained in the Network this will produce error unless
2181 --no-conflicts-check is passed.
2182
2183 """
2184 OP_DSC_FIELD = "network_name"
2185 OP_PARAMS = [
2186 _PGroupName,
2187 _PNetworkName,
2188 ("network_mode", ht.NoDefault, ht.TElemOf(constants.NIC_VALID_MODES),
2189 "Connectivity mode"),
2190 ("network_link", ht.NoDefault, ht.TString, "Connectivity link"),
2191 ("conflicts_check", True, ht.TBool, "Whether to check for conflicting IPs"),
2192 ]
2193 OP_RESULT = ht.TNone
2194
2207
2218
2221 """Returns list of all defined opcodes.
2222
2223 Does not eliminate duplicates by C{OP_ID}.
2224
2225 """
2226 return [v for v in globals().values()
2227 if (isinstance(v, type) and issubclass(v, OpCode) and
2228 hasattr(v, "OP_ID") and v is not OpCode)]
2229
2230
2231 OP_MAPPING = dict((v.OP_ID, v) for v in _GetOpList())
2232