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 _PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool,
67 "Whether to ignore offline nodes")
68
69
70 _PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString, "Node name")
71
72
73 _PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString, "Group name")
74
75
76 _PMigrationMode = ("mode", None,
77 ht.TMaybe(ht.TElemOf(constants.HT_MIGRATION_MODES)),
78 "Migration mode")
79
80
81 _PMigrationLive = ("live", None, ht.TMaybeBool,
82 "Legacy setting for live migration, do not use")
83
84
85 _PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES),
86 "Tag kind")
87
88
89 _PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
90 "List of tag names")
91
92 _PForceVariant = ("force_variant", False, ht.TBool,
93 "Whether to force an unknown OS variant")
94
95 _PWaitForSync = ("wait_for_sync", True, ht.TBool,
96 "Whether to wait for the disk to synchronize")
97
98 _PWaitForSyncFalse = ("wait_for_sync", False, ht.TBool,
99 "Whether to wait for the disk to synchronize"
100 " (defaults to false)")
101
102 _PIgnoreConsistency = ("ignore_consistency", False, ht.TBool,
103 "Whether to ignore disk consistency")
104
105 _PStorageName = ("name", ht.NoDefault, ht.TMaybeString, "Storage name")
106
107 _PUseLocking = ("use_locking", False, ht.TBool,
108 "Whether to use synchronization")
109
110 _PNameCheck = ("name_check", True, ht.TBool, "Whether to check name")
111
112 _PNodeGroupAllocPolicy = \
113 ("alloc_policy", None,
114 ht.TMaybe(ht.TElemOf(constants.VALID_ALLOC_POLICIES)),
115 "Instance allocation policy")
116
117 _PGroupNodeParams = ("ndparams", None, ht.TMaybeDict,
118 "Default node parameters for group")
119
120 _PQueryWhat = ("what", ht.NoDefault, ht.TElemOf(constants.QR_VIA_OP),
121 "Resource(s) to query for")
122
123 _PEarlyRelease = ("early_release", False, ht.TBool,
124 "Whether to release locks as soon as possible")
125
126 _PIpCheckDoc = "Whether to ensure instance's IP address is inactive"
127
128
129 _PNoRemember = ("no_remember", False, ht.TBool,
130 "Do not remember the state change")
131
132
133 _PMigrationTargetNode = ("target_node", None, ht.TMaybeString,
134 "Target node for shared-storage instances")
135
136 _PStartupPaused = ("startup_paused", False, ht.TBool,
137 "Pause instance at startup")
138
139 _PVerbose = ("verbose", False, ht.TBool, "Verbose mode")
140
141
142 _PDebugSimulateErrors = ("debug_simulate_errors", False, ht.TBool,
143 "Whether to simulate errors (useful for debugging)")
144 _PErrorCodes = ("error_codes", False, ht.TBool, "Error codes")
145 _PSkipChecks = ("skip_checks", ht.EmptyList,
146 ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS)),
147 "Which checks to skip")
148 _PIgnoreErrors = ("ignore_errors", ht.EmptyList,
149 ht.TListOf(ht.TElemOf(constants.CV_ALL_ECODES_STRINGS)),
150 "List of error codes that should be treated as warnings")
151
152
153 _PDiskParams = \
154 ("diskparams", None,
155 ht.TMaybe(ht.TDictOf(ht.TElemOf(constants.DISK_TEMPLATES), ht.TDict)),
156 "Disk templates' parameter defaults")
157
158
159 _PHvState = ("hv_state", None, ht.TMaybeDict, "Set hypervisor states")
160 _PDiskState = ("disk_state", None, ht.TMaybeDict, "Set disk states")
161
162
163 _POpportunisticLocking = \
164 ("opportunistic_locking", False, ht.TBool,
165 ("Whether to employ opportunistic locking for nodes, meaning nodes"
166 " already locked by another opcode won't be considered for instance"
167 " allocation (only when an iallocator is used)"))
168
169 _PIgnoreIpolicy = ("ignore_ipolicy", False, ht.TBool,
170 "Whether to ignore ipolicy violations")
171
172
173 _PAllowRuntimeChgs = ("allow_runtime_changes", True, ht.TBool,
174 "Allow runtime changes (eg. memory ballooning)")
175
176
177 _PIAllocFromDesc = lambda desc: ("iallocator", None, ht.TMaybeString, desc)
178
179
180 _PNetworkName = ("network_name", ht.NoDefault, ht.TNonEmptyString,
181 "Set network name")
182
183 _PTargetGroups = \
184 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString),
185 "Destination group names or UUIDs (defaults to \"all but current group\")")
186
187
188 _OPID_RE = re.compile("([a-z])([A-Z])")
189
190
191 _TestClusterOsListItem = \
192 ht.TAnd(ht.TIsLength(2), ht.TItems([
193 ht.TElemOf(constants.DDMS_VALUES),
194 ht.TNonEmptyString,
195 ]))
196
197 _TestClusterOsList = ht.TMaybeListOf(_TestClusterOsListItem)
198
199
200
201 _TestNicDef = \
202 ht.Comment("NIC parameters")(ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS),
203 ht.TMaybeString))
204
205 _TSetParamsResultItemItems = [
206 ht.Comment("name of changed parameter")(ht.TNonEmptyString),
207 ht.Comment("new value")(ht.TAny),
208 ]
209
210 _TSetParamsResult = \
211 ht.TListOf(ht.TAnd(ht.TIsLength(len(_TSetParamsResultItemItems)),
212 ht.TItems(_TSetParamsResultItemItems)))
213
214
215
216
217
218 _TDiskParams = \
219 ht.Comment("Disk parameters")(ht.TDictOf(ht.TNonEmptyString,
220 ht.TOr(ht.TNonEmptyString, ht.TInt)))
221
222 _TQueryRow = \
223 ht.TListOf(ht.TAnd(ht.TIsLength(2),
224 ht.TItems([ht.TElemOf(constants.RS_ALL),
225 ht.TAny])))
226
227 _TQueryResult = ht.TListOf(_TQueryRow)
228
229 _TOldQueryRow = ht.TListOf(ht.TAny)
230
231 _TOldQueryResult = ht.TListOf(_TOldQueryRow)
232
233
234 _SUMMARY_PREFIX = {
235 "CLUSTER_": "C_",
236 "GROUP_": "G_",
237 "NODE_": "N_",
238 "INSTANCE_": "I_",
239 }
240
241
242 DEPEND_ATTR = "depends"
243
244
245 COMMENT_ATTR = "comment"
249 """Split an opcode class name into its components
250
251 @type name: string
252 @param name: the class name, as OpXxxYyy
253 @rtype: array of strings
254 @return: the components of the name
255
256 """
257 assert name.startswith("Op")
258
259
260
261
262
263 name = _OPID_RE.sub(r"\1,\2", name)
264 elems = name.split(",")
265 return elems
266
269 """Convert an opcode class name to an OP_ID.
270
271 @type name: string
272 @param name: the class name, as OpXxxYyy
273 @rtype: string
274 @return: the name in the OP_XXXX_YYYY format
275
276 """
277 if not name.startswith("Op"):
278 return None
279 return "_".join(n.upper() for n in _NameComponents(name))
280
283 """Convert an opcode class name to a source string for the reason trail
284
285 @type name: string
286 @param name: the class name, as OpXxxYyy
287 @rtype: string
288 @return: the name in the OP_XXXX_YYYY format
289
290 """
291 if not name.startswith("Op"):
292 return None
293 return "%s:%s" % (constants.OPCODE_REASON_SRC_OPCODE,
294 "_".join(n.lower() for n in _NameComponents(name)))
295
298 """Helper to generate type checks for objects.
299
300 @param obj: The object to generate type checks
301 @param fields_types: The fields and their types as a dict
302 @return: A ht type check function
303
304 """
305 assert set(obj.GetAllSlots()) == set(fields_types.keys()), \
306 "%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys()))
307 return ht.TStrictDict(True, True, fields_types)
308
309
310 _TQueryFieldDef = \
311 _GenerateObjectTypeCheck(objects.QueryFieldDefinition, {
312 "name": ht.TNonEmptyString,
313 "title": ht.TNonEmptyString,
314 "kind": ht.TElemOf(constants.QFT_ALL),
315 "doc": ht.TNonEmptyString,
316 })
320 """Checks that file storage is enabled.
321
322 While it doesn't really fit into this module, L{utils} was deemed too large
323 of a dependency to be imported for just one or two functions.
324
325 @raise errors.OpPrereqError: when file storage is disabled
326
327 """
328 if not constants.ENABLE_FILE_STORAGE:
329 raise errors.OpPrereqError("File storage disabled at configure time",
330 errors.ECODE_INVAL)
331
334 """Checks that shared file storage is enabled.
335
336 While it doesn't really fit into this module, L{utils} was deemed too large
337 of a dependency to be imported for just one or two functions.
338
339 @raise errors.OpPrereqError: when shared file storage is disabled
340
341 """
342 if not constants.ENABLE_SHARED_FILE_STORAGE:
343 raise errors.OpPrereqError("Shared file storage disabled at"
344 " configure time", errors.ECODE_INVAL)
345
357
360 """Builds check for disk template.
361
362 @type accept_none: bool
363 @param accept_none: whether to accept None as a correct value
364 @rtype: callable
365
366 """
367 template_check = ht.TElemOf(constants.DISK_TEMPLATES)
368
369 if accept_none:
370 template_check = ht.TMaybe(template_check)
371
372 return ht.TAnd(template_check, _CheckFileStorage)
373
386
387
388
389 _PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType,
390 "Storage type")
395 """Ensure a given CIDR notation type is valid.
396
397 """
398 try:
399 ipaddr.IPv4Network(value)
400 except ipaddr.AddressValueError:
401 return False
402 return True
403
407 """Ensure a given CIDR notation type is valid.
408
409 """
410 try:
411 ipaddr.IPv4Address(value)
412 except ipaddr.AddressValueError:
413 return False
414 return True
415
419 """Ensure a given CIDR notation type is valid.
420
421 """
422 try:
423 ipaddr.IPv6Address(value)
424 except ipaddr.AddressValueError:
425 return False
426 return True
427
431 """Ensure a given CIDR notation type is valid.
432
433 """
434 try:
435 ipaddr.IPv6Network(value)
436 except ipaddr.AddressValueError:
437 return False
438 return True
439
440
441 _TIpAddress4 = ht.TAnd(ht.TString, _CheckCIDRAddrNotation)
442 _TIpAddress6 = ht.TAnd(ht.TString, _CheckCIDR6AddrNotation)
443 _TIpNetwork4 = ht.TAnd(ht.TString, _CheckCIDRNetNotation)
444 _TIpNetwork6 = ht.TAnd(ht.TString, _CheckCIDR6NetNotation)
445 _TMaybeAddr4List = ht.TMaybe(ht.TListOf(_TIpAddress4))
449 """Meta class for opcode definitions.
450
451 """
452 - def __new__(mcs, name, bases, attrs):
453 """Called when a class should be created.
454
455 @param mcs: The meta class
456 @param name: Name of created class
457 @param bases: Base classes
458 @type attrs: dict
459 @param attrs: Class attributes
460
461 """
462 assert "OP_ID" not in attrs, "Class '%s' defining OP_ID" % name
463
464 slots = mcs._GetSlots(attrs)
465 assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
466 "Class '%s' uses unknown field in OP_DSC_FIELD" % name
467 assert ("OP_DSC_FORMATTER" not in attrs or
468 callable(attrs["OP_DSC_FORMATTER"])), \
469 ("Class '%s' uses non-callable in OP_DSC_FORMATTER (%s)" %
470 (name, type(attrs["OP_DSC_FORMATTER"])))
471
472 attrs["OP_ID"] = _NameToId(name)
473
474 return outils.AutoSlots.__new__(mcs, name, bases, attrs)
475
476 @classmethod
478 """Build the slots out of OP_PARAMS.
479
480 """
481
482 params = attrs.setdefault("OP_PARAMS", [])
483
484
485 return [pname for (pname, _, _, _) in params]
486
489 """A simple serializable object.
490
491 This object serves as a parent class for OpCode without any custom
492 field handling.
493
494 """
495
496
497 __metaclass__ = _AutoOpParamSlots
498
500 """Generic serializer.
501
502 This method just returns the contents of the instance as a
503 dictionary.
504
505 @rtype: C{dict}
506 @return: the instance attributes and their values
507
508 """
509 state = {}
510 for name in self.GetAllSlots():
511 if hasattr(self, name):
512 state[name] = getattr(self, name)
513 return state
514
516 """Generic unserializer.
517
518 This method just restores from the serialized state the attributes
519 of the current instance.
520
521 @param state: the serialized opcode data
522 @type state: C{dict}
523
524 """
525 if not isinstance(state, dict):
526 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
527 type(state))
528
529 for name in self.GetAllSlots():
530 if name not in state and hasattr(self, name):
531 delattr(self, name)
532
533 for name in state:
534 setattr(self, name, state[name])
535
536 @classmethod
538 """Compute list of all parameters for an opcode.
539
540 """
541 slots = []
542 for parent in cls.__mro__:
543 slots.extend(getattr(parent, "OP_PARAMS", []))
544 return slots
545
547 """Validate opcode parameters, optionally setting default values.
548
549 @type set_defaults: bool
550 @param set_defaults: Whether to set default values
551 @raise errors.OpPrereqError: When a parameter value doesn't match
552 requirements
553
554 """
555 for (attr_name, default, test, _) in self.GetAllParams():
556 assert test == ht.NoType or callable(test)
557
558 if not hasattr(self, attr_name):
559 if default == ht.NoDefault:
560 raise errors.OpPrereqError("Required parameter '%s.%s' missing" %
561 (self.OP_ID, attr_name),
562 errors.ECODE_INVAL)
563 elif set_defaults:
564 if callable(default):
565 dval = default()
566 else:
567 dval = default
568 setattr(self, attr_name, dval)
569
570 if test == ht.NoType:
571
572 continue
573
574 if set_defaults or hasattr(self, attr_name):
575 attr_val = getattr(self, attr_name)
576 if not test(attr_val):
577 logging.error("OpCode %s, parameter %s, has invalid type %s/value"
578 " '%s' expecting type %s",
579 self.OP_ID, attr_name, type(attr_val), attr_val, test)
580 raise errors.OpPrereqError("Parameter '%s.%s' fails validation" %
581 (self.OP_ID, attr_name),
582 errors.ECODE_INVAL)
583
605
606
607 TNoRelativeJobDependencies = _BuildJobDepCheck(False)
608
609
610 _TJobIdListItem = \
611 ht.TAnd(ht.TIsLength(2),
612 ht.TItems([ht.Comment("success")(ht.TBool),
613 ht.Comment("Job ID if successful, error message"
614 " otherwise")(ht.TOr(ht.TString,
615 ht.TJobId))]))
616 TJobIdList = ht.TListOf(_TJobIdListItem)
617
618
619 TJobIdListOnly = ht.TStrictDict(True, True, {
620 constants.JOB_IDS_KEY: ht.Comment("List of submitted jobs")(TJobIdList),
621 })
622
623
624 -class OpCode(BaseOpCode):
625 """Abstract OpCode.
626
627 This is the root of the actual OpCode hierarchy. All clases derived
628 from this class should override OP_ID.
629
630 @cvar OP_ID: The ID of this opcode. This should be unique amongst all
631 children of this class.
632 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
633 string returned by Summary(); see the docstring of that
634 method for details).
635 @cvar OP_DSC_FORMATTER: A callable that should format the OP_DSC_FIELD; if
636 not present, then the field will be simply converted
637 to string
638 @cvar OP_PARAMS: List of opcode attributes, the default values they should
639 get if not already defined, and types they must match.
640 @cvar OP_RESULT: Callable to verify opcode result
641 @cvar WITH_LU: Boolean that specifies whether this should be included in
642 mcpu's dispatch table
643 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
644 the check steps
645 @ivar priority: Opcode priority for queue
646
647 """
648
649
650 WITH_LU = True
651 OP_PARAMS = [
652 ("dry_run", None, ht.TMaybeBool, "Run checks only, don't execute"),
653 ("debug_level", None, ht.TMaybe(ht.TNonNegativeInt), "Debug level"),
654 ("priority", constants.OP_PRIO_DEFAULT,
655 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"),
656 (DEPEND_ATTR, None, _BuildJobDepCheck(True),
657 "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)"
658 " job IDs can be used; see :doc:`design document <design-chained-jobs>`"
659 " for details"),
660 (COMMENT_ATTR, None, ht.TMaybeString,
661 "Comment describing the purpose of the opcode"),
662 (constants.OPCODE_REASON, ht.EmptyList, ht.TMaybeList,
663 "The reason trail, describing why the OpCode is executed"),
664 ]
665 OP_RESULT = None
666
668 """Specialized getstate for opcodes.
669
670 This method adds to the state dictionary the OP_ID of the class,
671 so that on unload we can identify the correct class for
672 instantiating the opcode.
673
674 @rtype: C{dict}
675 @return: the state as a dictionary
676
677 """
678 data = BaseOpCode.__getstate__(self)
679 data["OP_ID"] = self.OP_ID
680 return data
681
682 @classmethod
684 """Generic load opcode method.
685
686 The method identifies the correct opcode class from the dict-form
687 by looking for a OP_ID key, if this is not found, or its value is
688 not available in this module as a child of this class, we fail.
689
690 @type data: C{dict}
691 @param data: the serialized opcode
692
693 """
694 if not isinstance(data, dict):
695 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
696 if "OP_ID" not in data:
697 raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
698 op_id = data["OP_ID"]
699 op_class = None
700 if op_id in OP_MAPPING:
701 op_class = OP_MAPPING[op_id]
702 else:
703 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
704 op_id)
705 op = op_class()
706 new_data = data.copy()
707 del new_data["OP_ID"]
708 op.__setstate__(new_data)
709 return op
710
712 """Generates a summary description of this opcode.
713
714 The summary is the value of the OP_ID attribute (without the "OP_"
715 prefix), plus the value of the OP_DSC_FIELD attribute, if one was
716 defined; this field should allow to easily identify the operation
717 (for an instance creation job, e.g., it would be the instance
718 name).
719
720 """
721 assert self.OP_ID is not None and len(self.OP_ID) > 3
722
723 txt = self.OP_ID[3:]
724 field_name = getattr(self, "OP_DSC_FIELD", None)
725 if field_name:
726 field_value = getattr(self, field_name, None)
727 field_formatter = getattr(self, "OP_DSC_FORMATTER", None)
728 if callable(field_formatter):
729 field_value = field_formatter(field_value)
730 elif isinstance(field_value, (list, tuple)):
731 field_value = ",".join(str(i) for i in field_value)
732 txt = "%s(%s)" % (txt, field_value)
733 return txt
734
736 """Generates a compact summary description of the opcode.
737
738 """
739 assert self.OP_ID.startswith("OP_")
740
741 text = self.OP_ID[3:]
742
743 for (prefix, supplement) in _SUMMARY_PREFIX.items():
744 if text.startswith(prefix):
745 return supplement + text[len(prefix):]
746
747 return text
748
749
750
751
752 -class OpClusterPostInit(OpCode):
753 """Post cluster initialization.
754
755 This opcode does not touch the cluster at all. Its purpose is to run hooks
756 after the cluster has been initialized.
757
758 """
759 OP_RESULT = ht.TBool
760
763 """Destroy the cluster.
764
765 This opcode has no other parameters. All the state is irreversibly
766 lost after the execution of this opcode.
767
768 """
769 OP_RESULT = ht.TNonEmptyString
770
775
790
803
825
832
835 """Verifies the status of all disks in a node group.
836
837 Result: a tuple of three elements:
838 - dict of node names with issues (values: error msg)
839 - list of instances with degraded disks (that should be activated)
840 - dict of instances with missing logical volumes (values: (node, vol)
841 pairs with details about the missing volumes)
842
843 In normal operation, all lists should be empty. A non-empty instance
844 list (3rd element of the result) is still ok (errors were fixed) but
845 non-empty node list means some node is down, and probably there are
846 unfixable drbd errors.
847
848 Note that only instances that are drbd-based are taken into
849 consideration. This might need to be revisited in the future.
850
851 """
852 OP_DSC_FIELD = "group_name"
853 OP_PARAMS = [
854 _PGroupName,
855 ]
856 OP_RESULT = \
857 ht.TAnd(ht.TIsLength(3),
858 ht.TItems([ht.TDictOf(ht.TString, ht.TString),
859 ht.TListOf(ht.TString),
860 ht.TDictOf(ht.TString,
861 ht.TListOf(ht.TListOf(ht.TString)))]))
862
865 """Verify the disk sizes of the instances and fixes configuration
866 mimatches.
867
868 Parameters: optional instances list, in case we want to restrict the
869 checks to only a subset of the instances.
870
871 Result: a list of tuples, (instance, disk, new-size) for changed
872 configurations.
873
874 In normal operation, the list should be empty.
875
876 @type instances: list
877 @ivar instances: the list of instances to check, or empty for all instances
878
879 """
880 OP_PARAMS = [
881 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
882 ]
883 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3),
884 ht.TItems([ht.TNonEmptyString,
885 ht.TNonNegativeInt,
886 ht.TNonNegativeInt])))
887
895
911
914 """Change the parameters of the cluster.
915
916 @type vg_name: C{str} or C{None}
917 @ivar vg_name: The new volume group name or None to disable LVM usage.
918
919 """
920 OP_PARAMS = [
921 _PForce,
922 _PHvState,
923 _PDiskState,
924 ("vg_name", None, ht.TMaybe(ht.TString), "Volume group name"),
925 ("enabled_hypervisors", None,
926 ht.TMaybe(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)),
927 ht.TTrue)),
928 "List of enabled hypervisors"),
929 ("hvparams", None,
930 ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)),
931 "Cluster-wide hypervisor parameter defaults, hypervisor-dependent"),
932 ("beparams", None, ht.TMaybeDict,
933 "Cluster-wide backend parameter defaults"),
934 ("os_hvp", None, ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)),
935 "Cluster-wide per-OS hypervisor parameter defaults"),
936 ("osparams", None,
937 ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)),
938 "Cluster-wide OS parameter defaults"),
939 _PDiskParams,
940 ("candidate_pool_size", None, ht.TMaybe(ht.TPositiveInt),
941 "Master candidate pool size"),
942 ("uid_pool", None, ht.NoType,
943 "Set UID pool, must be list of lists describing UID ranges (two items,"
944 " start and end inclusive)"),
945 ("add_uids", None, ht.NoType,
946 "Extend UID pool, must be list of lists describing UID ranges (two"
947 " items, start and end inclusive) to be added"),
948 ("remove_uids", None, ht.NoType,
949 "Shrink UID pool, must be list of lists describing UID ranges (two"
950 " items, start and end inclusive) to be removed"),
951 ("maintain_node_health", None, ht.TMaybeBool,
952 "Whether to automatically maintain node health"),
953 ("prealloc_wipe_disks", None, ht.TMaybeBool,
954 "Whether to wipe disks before allocating them to instances"),
955 ("nicparams", None, ht.TMaybeDict, "Cluster-wide NIC parameter defaults"),
956 ("ndparams", None, ht.TMaybeDict, "Cluster-wide node parameter defaults"),
957 ("ipolicy", None, ht.TMaybeDict,
958 "Cluster-wide :ref:`instance policy <rapi-ipolicy>` specs"),
959 ("drbd_helper", None, ht.TMaybe(ht.TString), "DRBD helper program"),
960 ("default_iallocator", None, ht.TMaybe(ht.TString),
961 "Default iallocator for cluster"),
962 ("master_netdev", None, ht.TMaybe(ht.TString),
963 "Master network device"),
964 ("master_netmask", None, ht.TMaybe(ht.TNonNegativeInt),
965 "Netmask of the master IP"),
966 ("reserved_lvs", None, ht.TMaybeListOf(ht.TNonEmptyString),
967 "List of reserved LVs"),
968 ("hidden_os", None, _TestClusterOsList,
969 "Modify list of hidden operating systems: each modification must have"
970 " two items, the operation and the OS name; the operation can be"
971 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)),
972 ("blacklisted_os", None, _TestClusterOsList,
973 "Modify list of blacklisted operating systems: each modification must"
974 " have two items, the operation and the OS name; the operation can be"
975 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)),
976 ("use_external_mip_script", None, ht.TMaybeBool,
977 "Whether to use an external master IP address setup script"),
978 ("enabled_disk_templates", None,
979 ht.TMaybe(ht.TAnd(ht.TListOf(ht.TElemOf(constants.DISK_TEMPLATES)),
980 ht.TTrue)),
981 "List of enabled disk templates"),
982 ("modify_etc_hosts", None, ht.TMaybeBool,
983 "Whether the cluster can modify and keep in sync the /etc/hosts files"),
984 ]
985 OP_RESULT = ht.TNone
986
989 """Force a full push of the cluster configuration.
990
991 """
992 OP_RESULT = ht.TNone
993
996 """Activate the master IP on the master node.
997
998 """
999 OP_RESULT = ht.TNone
1000
1003 """Deactivate the master IP on the master node.
1004
1005 """
1006 OP_RESULT = ht.TNone
1007
1010 """Query for resources/items.
1011
1012 @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP}
1013 @ivar fields: List of fields to retrieve
1014 @ivar qfilter: Query filter
1015
1016 """
1017 OP_DSC_FIELD = "what"
1018 OP_PARAMS = [
1019 _PQueryWhat,
1020 _PUseLocking,
1021 ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
1022 "Requested fields"),
1023 ("qfilter", None, ht.TMaybe(ht.TList),
1024 "Query filter"),
1025 ]
1026 OP_RESULT = \
1027 _GenerateObjectTypeCheck(objects.QueryResponse, {
1028 "fields": ht.TListOf(_TQueryFieldDef),
1029 "data": _TQueryResult,
1030 })
1031
1050
1053 """Interact with OOB."""
1054 OP_PARAMS = [
1055 ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1056 "List of nodes to run the OOB command against"),
1057 ("command", ht.NoDefault, ht.TElemOf(constants.OOB_COMMANDS),
1058 "OOB command to be run"),
1059 ("timeout", constants.OOB_TIMEOUT, ht.TInt,
1060 "Timeout before the OOB helper will be terminated"),
1061 ("ignore_status", False, ht.TBool,
1062 "Ignores the node offline status for power off"),
1063 ("power_delay", constants.OOB_POWER_DELAY, ht.TNonNegativeFloat,
1064 "Time in seconds to wait between powering on nodes"),
1065 ]
1066
1067 OP_RESULT = _TQueryResult
1068
1071 """Runs a restricted command on node(s).
1072
1073 """
1074 OP_PARAMS = [
1075 _PUseLocking,
1076 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString),
1077 "Nodes on which the command should be run (at least one)"),
1078 ("command", ht.NoDefault, ht.TNonEmptyString,
1079 "Command name (no parameters)"),
1080 ]
1081
1082 _RESULT_ITEMS = [
1083 ht.Comment("success")(ht.TBool),
1084 ht.Comment("output or error message")(ht.TString),
1085 ]
1086
1087 OP_RESULT = \
1088 ht.TListOf(ht.TAnd(ht.TIsLength(len(_RESULT_ITEMS)),
1089 ht.TItems(_RESULT_ITEMS)))
1090
1095 """Remove a node.
1096
1097 @type node_name: C{str}
1098 @ivar node_name: The name of the node to remove. If the node still has
1099 instances on it, the operation will fail.
1100
1101 """
1102 OP_DSC_FIELD = "node_name"
1103 OP_PARAMS = [
1104 _PNodeName,
1105 ]
1106 OP_RESULT = ht.TNone
1107
1110 """Add a node to the cluster.
1111
1112 @type node_name: C{str}
1113 @ivar node_name: The name of the node to add. This can be a short name,
1114 but it will be expanded to the FQDN.
1115 @type primary_ip: IP address
1116 @ivar primary_ip: The primary IP of the node. This will be ignored when the
1117 opcode is submitted, but will be filled during the node
1118 add (so it will be visible in the job query).
1119 @type secondary_ip: IP address
1120 @ivar secondary_ip: The secondary IP of the node. This needs to be passed
1121 if the cluster has been initialized in 'dual-network'
1122 mode, otherwise it must not be given.
1123 @type readd: C{bool}
1124 @ivar readd: Whether to re-add an existing node to the cluster. If
1125 this is not passed, then the operation will abort if the node
1126 name is already in the cluster; use this parameter to 'repair'
1127 a node that had its configuration broken, or was reinstalled
1128 without removal from the cluster.
1129 @type group: C{str}
1130 @ivar group: The node group to which this node will belong.
1131 @type vm_capable: C{bool}
1132 @ivar vm_capable: The vm_capable node attribute
1133 @type master_capable: C{bool}
1134 @ivar master_capable: The master_capable node attribute
1135
1136 """
1137 OP_DSC_FIELD = "node_name"
1138 OP_PARAMS = [
1139 _PNodeName,
1140 _PHvState,
1141 _PDiskState,
1142 ("primary_ip", None, ht.NoType, "Primary IP address"),
1143 ("secondary_ip", None, ht.TMaybeString, "Secondary IP address"),
1144 ("readd", False, ht.TBool, "Whether node is re-added to cluster"),
1145 ("group", None, ht.TMaybeString, "Initial node group"),
1146 ("master_capable", None, ht.TMaybeBool,
1147 "Whether node can become master or master candidate"),
1148 ("vm_capable", None, ht.TMaybeBool,
1149 "Whether node can host instances"),
1150 ("ndparams", None, ht.TMaybeDict, "Node parameters"),
1151 ]
1152 OP_RESULT = ht.TNone
1153
1164
1174
1177 """Get information on storage for node(s)."""
1178 OP_PARAMS = [
1179 _POutputFields,
1180 _PStorageType,
1181 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "List of nodes"),
1182 ("name", None, ht.TMaybeString, "Storage name"),
1183 ]
1184 OP_RESULT = _TOldQueryResult
1185
1197
1209
1212 """Change the parameters of a node."""
1213 OP_DSC_FIELD = "node_name"
1214 OP_PARAMS = [
1215 _PNodeName,
1216 _PForce,
1217 _PHvState,
1218 _PDiskState,
1219 ("master_candidate", None, ht.TMaybeBool,
1220 "Whether the node should become a master candidate"),
1221 ("offline", None, ht.TMaybeBool,
1222 "Whether the node should be marked as offline"),
1223 ("drained", None, ht.TMaybeBool,
1224 "Whether the node should be marked as drained"),
1225 ("auto_promote", False, ht.TBool,
1226 "Whether node(s) should be promoted to master candidate if necessary"),
1227 ("master_capable", None, ht.TMaybeBool,
1228 "Denote whether node can become master or master candidate"),
1229 ("vm_capable", None, ht.TMaybeBool,
1230 "Denote whether node can host instances"),
1231 ("secondary_ip", None, ht.TMaybeString,
1232 "Change node's secondary IP address"),
1233 ("ndparams", None, ht.TMaybeDict, "Set node parameters"),
1234 ("powered", None, ht.TMaybeBool,
1235 "Whether the node should be marked as powered"),
1236 ]
1237 OP_RESULT = _TSetParamsResult
1238
1248
1264
1267 """Evacuate instances off a number of nodes."""
1268 OP_DSC_FIELD = "node_name"
1269 OP_PARAMS = [
1270 _PEarlyRelease,
1271 _PNodeName,
1272 ("remote_node", None, ht.TMaybeString, "New secondary node"),
1273 _PIAllocFromDesc("Iallocator for computing solution"),
1274 ("mode", ht.NoDefault, ht.TElemOf(constants.NODE_EVAC_MODES),
1275 "Node evacuation mode"),
1276 ]
1277 OP_RESULT = TJobIdListOnly
1278
1283 """Create an instance.
1284
1285 @ivar instance_name: Instance name
1286 @ivar mode: Instance creation mode (one of L{constants.INSTANCE_CREATE_MODES})
1287 @ivar source_handshake: Signed handshake from source (remote import only)
1288 @ivar source_x509_ca: Source X509 CA in PEM format (remote import only)
1289 @ivar source_instance_name: Previous name of instance (remote import only)
1290 @ivar source_shutdown_timeout: Shutdown timeout used for source instance
1291 (remote import only)
1292
1293 """
1294 OP_DSC_FIELD = "instance_name"
1295 OP_PARAMS = [
1296 _PInstanceName,
1297 _PForceVariant,
1298 _PWaitForSync,
1299 _PNameCheck,
1300 _PIgnoreIpolicy,
1301 _POpportunisticLocking,
1302 ("beparams", ht.EmptyDict, ht.TDict, "Backend parameters for instance"),
1303 ("disks", ht.NoDefault, ht.TListOf(_TDiskParams),
1304 "Disk descriptions, for example ``[{\"%s\": 100}, {\"%s\": 5}]``;"
1305 " each disk definition must contain a ``%s`` value and"
1306 " can contain an optional ``%s`` value denoting the disk access mode"
1307 " (%s)" %
1308 (constants.IDISK_SIZE, constants.IDISK_SIZE, constants.IDISK_SIZE,
1309 constants.IDISK_MODE,
1310 " or ".join("``%s``" % i for i in sorted(constants.DISK_ACCESS_SET)))),
1311 ("disk_template", ht.NoDefault, _BuildDiskTemplateCheck(True),
1312 "Disk template"),
1313 ("file_driver", None, ht.TMaybe(ht.TElemOf(constants.FILE_DRIVER)),
1314 "Driver for file-backed disks"),
1315 ("file_storage_dir", None, ht.TMaybeString,
1316 "Directory for storing file-backed disks"),
1317 ("hvparams", ht.EmptyDict, ht.TDict,
1318 "Hypervisor parameters for instance, hypervisor-dependent"),
1319 ("hypervisor", None, ht.TMaybeString, "Hypervisor"),
1320 _PIAllocFromDesc("Iallocator for deciding which node(s) to use"),
1321 ("identify_defaults", False, ht.TBool,
1322 "Reset instance parameters to default if equal"),
1323 ("ip_check", True, ht.TBool, _PIpCheckDoc),
1324 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1325 ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES),
1326 "Instance creation mode"),
1327 ("nics", ht.NoDefault, ht.TListOf(_TestNicDef),
1328 "List of NIC (network interface) definitions, for example"
1329 " ``[{}, {}, {\"%s\": \"198.51.100.4\"}]``; each NIC definition can"
1330 " contain the optional values %s" %
1331 (constants.INIC_IP,
1332 ", ".join("``%s``" % i for i in sorted(constants.INIC_PARAMS)))),
1333 ("no_install", None, ht.TMaybeBool,
1334 "Do not install the OS (will disable automatic start)"),
1335 ("osparams", ht.EmptyDict, ht.TDict, "OS parameters for instance"),
1336 ("os_type", None, ht.TMaybeString, "Operating system"),
1337 ("pnode", None, ht.TMaybeString, "Primary node"),
1338 ("snode", None, ht.TMaybeString, "Secondary node"),
1339 ("source_handshake", None, ht.TMaybe(ht.TList),
1340 "Signed handshake from source (remote import only)"),
1341 ("source_instance_name", None, ht.TMaybeString,
1342 "Source instance name (remote import only)"),
1343 ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
1344 ht.TNonNegativeInt,
1345 "How long source instance was given to shut down (remote import only)"),
1346 ("source_x509_ca", None, ht.TMaybeString,
1347 "Source X509 CA in PEM format (remote import only)"),
1348 ("src_node", None, ht.TMaybeString, "Source node for import"),
1349 ("src_path", None, ht.TMaybeString, "Source directory for import"),
1350 ("start", True, ht.TBool, "Whether to start instance after creation"),
1351 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Instance tags"),
1352 ]
1353 OP_RESULT = ht.Comment("instance nodes")(ht.TListOf(ht.TNonEmptyString))
1354
1357 """Allocates multiple instances.
1358
1359 """
1360 OP_PARAMS = [
1361 _POpportunisticLocking,
1362 _PIAllocFromDesc("Iallocator used to allocate all the instances"),
1363 ("instances", ht.EmptyList, ht.TListOf(ht.TInstanceOf(OpInstanceCreate)),
1364 "List of instance create opcodes describing the instances to allocate"),
1365 ]
1366 _JOB_LIST = ht.Comment("List of submitted jobs")(TJobIdList)
1367 ALLOCATABLE_KEY = "allocatable"
1368 FAILED_KEY = "allocatable"
1369 OP_RESULT = ht.TStrictDict(True, True, {
1370 constants.JOB_IDS_KEY: _JOB_LIST,
1371 ALLOCATABLE_KEY: ht.TListOf(ht.TNonEmptyString),
1372 FAILED_KEY: ht.TListOf(ht.TNonEmptyString),
1373 })
1374
1384
1386 """Generic unserializer.
1387
1388 This method just restores from the serialized state the attributes
1389 of the current instance.
1390
1391 @param state: the serialized opcode data
1392 @type state: C{dict}
1393
1394 """
1395 if not isinstance(state, dict):
1396 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
1397 type(state))
1398
1399 if "instances" in state:
1400 state["instances"] = map(OpCode.LoadOpCode, state["instances"])
1401
1402 return OpCode.__setstate__(self, state)
1403
1405 """Validates this opcode.
1406
1407 We do this recursively.
1408
1409 """
1410 OpCode.Validate(self, set_defaults)
1411
1412 for inst in self.instances:
1413 inst.Validate(set_defaults)
1414
1417 """Reinstall an instance's OS."""
1418 OP_DSC_FIELD = "instance_name"
1419 OP_PARAMS = [
1420 _PInstanceName,
1421 _PForceVariant,
1422 ("os_type", None, ht.TMaybeString, "Instance operating system"),
1423 ("osparams", None, ht.TMaybeDict, "Temporary OS parameters"),
1424 ]
1425 OP_RESULT = ht.TNone
1426
1438
1441 """Rename an instance."""
1442 OP_PARAMS = [
1443 _PInstanceName,
1444 _PNameCheck,
1445 ("new_name", ht.NoDefault, ht.TNonEmptyString, "New instance name"),
1446 ("ip_check", False, ht.TBool, _PIpCheckDoc),
1447 ]
1448 OP_RESULT = ht.Comment("New instance name")(ht.TNonEmptyString)
1449
1452 """Startup an instance."""
1453 OP_DSC_FIELD = "instance_name"
1454 OP_PARAMS = [
1455 _PInstanceName,
1456 _PForce,
1457 _PIgnoreOfflineNodes,
1458 ("hvparams", ht.EmptyDict, ht.TDict,
1459 "Temporary hypervisor parameters, hypervisor-dependent"),
1460 ("beparams", ht.EmptyDict, ht.TDict, "Temporary backend parameters"),
1461 _PNoRemember,
1462 _PStartupPaused,
1463 ]
1464 OP_RESULT = ht.TNone
1465
1479
1482 """Reboot an instance."""
1483 OP_DSC_FIELD = "instance_name"
1484 OP_PARAMS = [
1485 _PInstanceName,
1486 _PShutdownTimeout,
1487 ("ignore_secondaries", False, ht.TBool,
1488 "Whether to start the instance even if secondary disks are failing"),
1489 ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES),
1490 "How to reboot instance"),
1491 ]
1492 OP_RESULT = ht.TNone
1493
1496 """Replace the disks of an instance."""
1497 OP_DSC_FIELD = "instance_name"
1498 OP_PARAMS = [
1499 _PInstanceName,
1500 _PEarlyRelease,
1501 _PIgnoreIpolicy,
1502 ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES),
1503 "Replacement mode"),
1504 ("disks", ht.EmptyList, ht.TListOf(ht.TNonNegativeInt),
1505 "Disk indexes"),
1506 ("remote_node", None, ht.TMaybeString, "New secondary node"),
1507 _PIAllocFromDesc("Iallocator for deciding new secondary node"),
1508 ]
1509 OP_RESULT = ht.TNone
1510
1513 """Failover an instance."""
1514 OP_DSC_FIELD = "instance_name"
1515 OP_PARAMS = [
1516 _PInstanceName,
1517 _PShutdownTimeout,
1518 _PIgnoreConsistency,
1519 _PMigrationTargetNode,
1520 _PIgnoreIpolicy,
1521 _PIAllocFromDesc("Iallocator for deciding the target node for"
1522 " shared-storage instances"),
1523 ("cleanup", False, ht.TBool,
1524 "Whether a previously failed failover should be cleaned up"),
1525 ]
1526 OP_RESULT = ht.TNone
1527
1530 """Migrate an instance.
1531
1532 This migrates (without shutting down an instance) to its secondary
1533 node.
1534
1535 @ivar instance_name: the name of the instance
1536 @ivar mode: the migration mode (live, non-live or None for auto)
1537
1538 """
1539 OP_DSC_FIELD = "instance_name"
1540 OP_PARAMS = [
1541 _PInstanceName,
1542 _PMigrationMode,
1543 _PMigrationLive,
1544 _PMigrationTargetNode,
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
1576
1585
1599
1609
1612 """Recreate an instance's disks."""
1613 _TDiskChanges = \
1614 ht.TAnd(ht.TIsLength(2),
1615 ht.TItems([ht.Comment("Disk index")(ht.TNonNegativeInt),
1616 ht.Comment("Parameters")(_TDiskParams)]))
1617
1618 OP_DSC_FIELD = "instance_name"
1619 OP_PARAMS = [
1620 _PInstanceName,
1621 ("disks", ht.EmptyList,
1622 ht.TOr(ht.TListOf(ht.TNonNegativeInt), ht.TListOf(_TDiskChanges)),
1623 "List of disk indexes (deprecated) or a list of tuples containing a disk"
1624 " index and a possibly empty dictionary with disk parameter changes"),
1625 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1626 "New instance nodes, if relocation is desired"),
1627 _PIAllocFromDesc("Iallocator for deciding new nodes"),
1628 ]
1629 OP_RESULT = ht.TNone
1630
1641
1644 """Compute the run-time status of instances."""
1645 OP_PARAMS = [
1646 _PUseLocking,
1647 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString),
1648 "Instance names"),
1649 ("static", False, ht.TBool,
1650 "Whether to only return configuration data without querying"
1651 " nodes"),
1652 ]
1653 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TDict)
1654
1657 """Generates a check for modification lists.
1658
1659 """
1660
1661
1662 old_mod_item_fn = \
1663 ht.TAnd(ht.TIsLength(2), ht.TItems([
1664 ht.TOr(ht.TElemOf(constants.DDMS_VALUES), ht.TNonNegativeInt),
1665 fn,
1666 ]))
1667
1668
1669 mod_item_fn = \
1670 ht.TAnd(ht.TIsLength(3), ht.TItems([
1671 ht.TElemOf(constants.DDMS_VALUES_WITH_MODIFY),
1672 ht.Comment("Device index, can be negative, e.g. -1 for last disk")
1673 (ht.TOr(ht.TInt, ht.TString)),
1674 fn,
1675 ]))
1676
1677 return ht.TOr(ht.Comment("Recommended")(ht.TListOf(mod_item_fn)),
1678 ht.Comment("Deprecated")(ht.TListOf(old_mod_item_fn)))
1679
1682 """Change the parameters of an instance.
1683
1684 """
1685 TestNicModifications = _TestInstSetParamsModList(_TestNicDef)
1686 TestDiskModifications = _TestInstSetParamsModList(_TDiskParams)
1687
1688 OP_DSC_FIELD = "instance_name"
1689 OP_PARAMS = [
1690 _PInstanceName,
1691 _PForce,
1692 _PForceVariant,
1693 _PIgnoreIpolicy,
1694 ("nics", ht.EmptyList, TestNicModifications,
1695 "List of NIC changes: each item is of the form"
1696 " ``(op, identifier, settings)``, ``op`` is one of ``%s``, ``%s`` or"
1697 " ``%s``, ``identifier`` can be a zero-based index number (or -1 to refer"
1698 " to the last position), the NIC's UUID of the NIC's name; a"
1699 " deprecated version of this parameter used the form ``(op, settings)``,"
1700 " where ``op`` can be ``%s`` to add a new NIC with the specified"
1701 " settings, ``%s`` to remove the last NIC or a number to modify the"
1702 " settings of the NIC with that index" %
1703 (constants.DDM_ADD, constants.DDM_MODIFY, constants.DDM_REMOVE,
1704 constants.DDM_ADD, constants.DDM_REMOVE)),
1705 ("disks", ht.EmptyList, TestDiskModifications,
1706 "List of disk changes; see ``nics``"),
1707 ("beparams", ht.EmptyDict, ht.TDict, "Per-instance backend parameters"),
1708 ("runtime_mem", None, ht.TMaybePositiveInt, "New runtime memory"),
1709 ("hvparams", ht.EmptyDict, ht.TDict,
1710 "Per-instance hypervisor parameters, hypervisor-dependent"),
1711 ("disk_template", None, ht.TMaybe(_BuildDiskTemplateCheck(False)),
1712 "Disk template for instance"),
1713 ("pnode", None, ht.TMaybeString, "New primary node"),
1714 ("remote_node", None, ht.TMaybeString,
1715 "Secondary node (used when changing disk template)"),
1716 ("os_name", None, ht.TMaybeString,
1717 "Change the instance's OS without reinstalling the instance"),
1718 ("osparams", None, ht.TMaybeDict, "Per-instance OS parameters"),
1719 ("wait_for_sync", True, ht.TBool,
1720 "Whether to wait for the disk to synchronize, when changing template"),
1721 ("offline", None, ht.TMaybeBool, "Whether to mark instance as offline"),
1722 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"),
1723 ]
1724 OP_RESULT = _TSetParamsResult
1725
1728 """Grow a disk of an instance."""
1729 OP_DSC_FIELD = "instance_name"
1730 OP_PARAMS = [
1731 _PInstanceName,
1732 _PWaitForSync,
1733 ("disk", ht.NoDefault, ht.TInt, "Disk index"),
1734 ("amount", ht.NoDefault, ht.TNonNegativeInt,
1735 "Amount of disk space to add (megabytes)"),
1736 ("absolute", False, ht.TBool,
1737 "Whether the amount parameter is an absolute target or a relative one"),
1738 ]
1739 OP_RESULT = ht.TNone
1740
1752
1757 """Add a node group to the cluster."""
1758 OP_DSC_FIELD = "group_name"
1759 OP_PARAMS = [
1760 _PGroupName,
1761 _PNodeGroupAllocPolicy,
1762 _PGroupNodeParams,
1763 _PDiskParams,
1764 _PHvState,
1765 _PDiskState,
1766 ("ipolicy", None, ht.TMaybeDict,
1767 "Group-wide :ref:`instance policy <rapi-ipolicy>` specs"),
1768 ]
1769 OP_RESULT = ht.TNone
1770
1782
1792
1795 """Change the parameters of a node group."""
1796 OP_DSC_FIELD = "group_name"
1797 OP_PARAMS = [
1798 _PGroupName,
1799 _PNodeGroupAllocPolicy,
1800 _PGroupNodeParams,
1801 _PDiskParams,
1802 _PHvState,
1803 _PDiskState,
1804 ("ipolicy", None, ht.TMaybeDict, "Group-wide instance policy specs"),
1805 ]
1806 OP_RESULT = _TSetParamsResult
1807
1816
1825
1837
1848
1859
1872
1888
1891 """Export an instance.
1892
1893 For local exports, the export destination is the node name. For
1894 remote exports, the export destination is a list of tuples, each
1895 consisting of hostname/IP address, port, magic, HMAC and HMAC
1896 salt. The HMAC is calculated using the cluster domain secret over
1897 the value "${index}:${hostname}:${port}". The destination X509 CA
1898 must be a signed certificate.
1899
1900 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1901 @ivar target_node: Export destination
1902 @ivar x509_key_name: X509 key to use (remote export only)
1903 @ivar destination_x509_ca: Destination X509 CA in PEM format (remote export
1904 only)
1905
1906 """
1907 OP_DSC_FIELD = "instance_name"
1908 OP_PARAMS = [
1909 _PInstanceName,
1910 _PShutdownTimeout,
1911
1912
1913 ("target_node", ht.NoDefault, ht.TOr(ht.TNonEmptyString, ht.TList),
1914 "Destination information, depends on export mode"),
1915 ("shutdown", True, ht.TBool, "Whether to shutdown instance before export"),
1916 ("remove_instance", False, ht.TBool,
1917 "Whether to remove instance after export"),
1918 ("ignore_remove_failures", False, ht.TBool,
1919 "Whether to ignore failures while removing instances"),
1920 ("mode", constants.EXPORT_MODE_LOCAL, ht.TElemOf(constants.EXPORT_MODES),
1921 "Export mode"),
1922 ("x509_key_name", None, ht.TMaybe(ht.TList),
1923 "Name of X509 key (remote export only)"),
1924 ("destination_x509_ca", None, ht.TMaybeString,
1925 "Destination X509 CA (remote export only)"),
1926 ]
1927 OP_RESULT = \
1928 ht.TAnd(ht.TIsLength(2), ht.TItems([
1929 ht.Comment("Finalizing status")(ht.TBool),
1930 ht.Comment("Status for every exported disk")(ht.TListOf(ht.TBool)),
1931 ]))
1932
1941
1956
1969
1981
1993
1997 """Sleeps for a configured amount of time.
1998
1999 This is used just for debugging and testing.
2000
2001 Parameters:
2002 - duration: the time to sleep, in seconds
2003 - on_master: if true, sleep on the master
2004 - on_nodes: list of nodes in which to sleep
2005
2006 If the on_master parameter is true, it will execute a sleep on the
2007 master (before any node sleep).
2008
2009 If the on_nodes list is not empty, it will sleep on those nodes
2010 (after the sleep on the master, if that is enabled).
2011
2012 As an additional feature, the case of duration < 0 will be reported
2013 as an execution error, so this opcode can be used as a failure
2014 generator. The case of duration == 0 will not be treated specially.
2015
2016 """
2017 OP_DSC_FIELD = "duration"
2018 OP_PARAMS = [
2019 ("duration", ht.NoDefault, ht.TNumber, None),
2020 ("on_master", True, ht.TBool, None),
2021 ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
2022 ("repeat", 0, ht.TNonNegativeInt, None),
2023 ]
2024
2026 """Custom formatter for duration.
2027
2028 """
2029 try:
2030 v = float(value)
2031 except TypeError:
2032 v = value
2033 return str(v)
2034
2037 """Allocator framework testing.
2038
2039 This opcode has two modes:
2040 - gather and return allocator input for a given mode (allocate new
2041 or replace secondary) and a given instance definition (direction
2042 'in')
2043 - run a selected allocator for a given operation (as above) and
2044 return the allocator output (direction 'out')
2045
2046 """
2047 OP_DSC_FIELD = "iallocator"
2048 OP_PARAMS = [
2049 ("direction", ht.NoDefault,
2050 ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS), None),
2051 ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES), None),
2052 ("name", ht.NoDefault, ht.TNonEmptyString, None),
2053 ("nics", ht.NoDefault,
2054 ht.TMaybeListOf(ht.TDictOf(ht.TElemOf([constants.INIC_MAC,
2055 constants.INIC_IP,
2056 "bridge"]),
2057 ht.TMaybeString)),
2058 None),
2059 ("disks", ht.NoDefault, ht.TMaybe(ht.TList), None),
2060 ("hypervisor", None, ht.TMaybeString, None),
2061 _PIAllocFromDesc(None),
2062 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None),
2063 ("memory", None, ht.TMaybe(ht.TNonNegativeInt), None),
2064 ("vcpus", None, ht.TMaybe(ht.TNonNegativeInt), None),
2065 ("os", None, ht.TMaybeString, None),
2066 ("disk_template", None, ht.TMaybeString, None),
2067 ("instances", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
2068 ("evac_mode", None,
2069 ht.TMaybe(ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)), None),
2070 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), None),
2071 ("spindle_use", 1, ht.TNonNegativeInt, None),
2072 ("count", 1, ht.TNonNegativeInt, None),
2073 ]
2074
2077 """Utility opcode to test some aspects of the job queue.
2078
2079 """
2080 OP_PARAMS = [
2081 ("notify_waitlock", False, ht.TBool, None),
2082 ("notify_exec", False, ht.TBool, None),
2083 ("log_messages", ht.EmptyList, ht.TListOf(ht.TString), None),
2084 ("fail", False, ht.TBool, None),
2085 ]
2086
2089 """Utility opcode used by unittests.
2090
2091 """
2092 OP_PARAMS = [
2093 ("result", ht.NoDefault, ht.NoType, None),
2094 ("messages", ht.NoDefault, ht.NoType, None),
2095 ("fail", ht.NoDefault, ht.NoType, None),
2096 ("submit_jobs", None, ht.NoType, None),
2097 ]
2098 WITH_LU = False
2099
2104 """Add an IP network to the cluster."""
2105 OP_DSC_FIELD = "network_name"
2106 OP_PARAMS = [
2107 _PNetworkName,
2108 ("network", ht.NoDefault, _TIpNetwork4, "IPv4 subnet"),
2109 ("gateway", None, ht.TMaybe(_TIpAddress4), "IPv4 gateway"),
2110 ("network6", None, ht.TMaybe(_TIpNetwork6), "IPv6 subnet"),
2111 ("gateway6", None, ht.TMaybe(_TIpAddress6), "IPv6 gateway"),
2112 ("mac_prefix", None, ht.TMaybeString,
2113 "MAC address prefix that overrides cluster one"),
2114 ("add_reserved_ips", None, _TMaybeAddr4List,
2115 "Which IP addresses to reserve"),
2116 ("conflicts_check", True, ht.TBool,
2117 "Whether to check for conflicting IP addresses"),
2118 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Network tags"),
2119 ]
2120 OP_RESULT = ht.TNone
2121
2134
2137 """Modify Network's parameters except for IPv4 subnet"""
2138 OP_DSC_FIELD = "network_name"
2139 OP_PARAMS = [
2140 _PNetworkName,
2141 ("gateway", None, ht.TMaybeValueNone(_TIpAddress4), "IPv4 gateway"),
2142 ("network6", None, ht.TMaybeValueNone(_TIpNetwork6), "IPv6 subnet"),
2143 ("gateway6", None, ht.TMaybeValueNone(_TIpAddress6), "IPv6 gateway"),
2144 ("mac_prefix", None, ht.TMaybeValueNone(ht.TString),
2145 "MAC address prefix that overrides cluster one"),
2146 ("add_reserved_ips", None, _TMaybeAddr4List,
2147 "Which external IP addresses to reserve"),
2148 ("remove_reserved_ips", None, _TMaybeAddr4List,
2149 "Which external IP addresses to release"),
2150 ]
2151 OP_RESULT = ht.TNone
2152
2155 """Connect a Network to a specific Nodegroup with the defined netparams
2156 (mode, link). Nics in this Network will inherit those params.
2157 Produce errors if a NIC (that its not already assigned to a network)
2158 has an IP that is contained in the Network this will produce error unless
2159 --no-conflicts-check is passed.
2160
2161 """
2162 OP_DSC_FIELD = "network_name"
2163 OP_PARAMS = [
2164 _PGroupName,
2165 _PNetworkName,
2166 ("network_mode", ht.NoDefault, ht.TElemOf(constants.NIC_VALID_MODES),
2167 "Connectivity mode"),
2168 ("network_link", ht.NoDefault, ht.TString, "Connectivity link"),
2169 ("conflicts_check", True, ht.TBool, "Whether to check for conflicting IPs"),
2170 ]
2171 OP_RESULT = ht.TNone
2172
2185
2196
2199 """Returns list of all defined opcodes.
2200
2201 Does not eliminate duplicates by C{OP_ID}.
2202
2203 """
2204 return [v for v in globals().values()
2205 if (isinstance(v, type) and issubclass(v, OpCode) and
2206 hasattr(v, "OP_ID") and v is not OpCode)]
2207
2208
2209 OP_MAPPING = dict((v.OP_ID, v) for v in _GetOpList())
2210