4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 This module implements the data structures which define the cluster
25 operations - the so-called opcodes.
27 Every operation which modifies the cluster state is expressed via
32 # this are practically structures, so disable the message about too
34 # pylint: disable-msg=R0903
38 from ganeti import constants
39 from ganeti import errors
43 # Common opcode attributes
45 #: output fields for a query operation
46 _POutputFields = ("output_fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
48 #: the shutdown timeout
49 _PShutdownTimeout = ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
52 #: the force parameter
53 _PForce = ("force", False, ht.TBool)
55 #: a required instance name (for single-instance LUs)
56 _PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString)
58 #: Whether to ignore offline nodes
59 _PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool)
61 #: a required node name (for single-node LUs)
62 _PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString)
64 #: a required node group name (for single-group LUs)
65 _PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString)
67 #: Migration type (live/non-live)
68 _PMigrationMode = ("mode", None,
69 ht.TOr(ht.TNone, ht.TElemOf(constants.HT_MIGRATION_MODES)))
71 #: Obsolete 'live' migration mode (boolean)
72 _PMigrationLive = ("live", None, ht.TMaybeBool)
75 _PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES))
77 #: List of tag strings
78 _PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
81 def RequireFileStorage():
82 """Checks that file storage is enabled.
84 While it doesn't really fit into this module, L{utils} was deemed too large
85 of a dependency to be imported for just one or two functions.
87 @raise errors.OpPrereqError: when file storage is disabled
90 if not constants.ENABLE_FILE_STORAGE:
91 raise errors.OpPrereqError("File storage disabled at configure time",
95 def _CheckDiskTemplate(template):
96 """Ensure a given disk template is valid.
99 if template not in constants.DISK_TEMPLATES:
100 # Using str.join directly to avoid importing utils for CommaJoin
101 msg = ("Invalid disk template name '%s', valid templates are: %s" %
102 (template, ", ".join(constants.DISK_TEMPLATES)))
103 raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
104 if template == constants.DT_FILE:
109 def _CheckStorageType(storage_type):
110 """Ensure a given storage type is valid.
113 if storage_type not in constants.VALID_STORAGE_TYPES:
114 raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
116 if storage_type == constants.ST_FILE:
121 #: Storage type parameter
122 _PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType)
125 class _AutoOpParamSlots(type):
126 """Meta class for opcode definitions.
129 def __new__(mcs, name, bases, attrs):
130 """Called when a class should be created.
132 @param mcs: The meta class
133 @param name: Name of created class
134 @param bases: Base classes
136 @param attrs: Class attributes
139 assert "__slots__" not in attrs, \
140 "Class '%s' defines __slots__ when it should use OP_PARAMS" % name
141 assert "OP_ID" in attrs, "Class '%s' is missing OP_ID attribute" % name
143 # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams
144 params = attrs.setdefault("OP_PARAMS", [])
146 # Use parameter names as slots
147 slots = [pname for (pname, _, _) in params]
149 assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
150 "Class '%s' uses unknown field in OP_DSC_FIELD" % name
152 attrs["__slots__"] = slots
154 return type.__new__(mcs, name, bases, attrs)
157 class BaseOpCode(object):
158 """A simple serializable object.
160 This object serves as a parent class for OpCode without any custom
164 __metaclass__ = _AutoOpParamSlots
168 def __init__(self, **kwargs):
169 """Constructor for BaseOpCode.
171 The constructor takes only keyword arguments and will set
172 attributes on this object based on the passed arguments. As such,
173 it means that you should not pass arguments which are not in the
174 __slots__ attribute for this class.
177 slots = self._all_slots()
180 raise TypeError("Object %s doesn't support the parameter '%s'" %
181 (self.__class__.__name__, key))
182 setattr(self, key, kwargs[key])
184 def __getstate__(self):
185 """Generic serializer.
187 This method just returns the contents of the instance as a
191 @return: the instance attributes and their values
195 for name in self._all_slots():
196 if hasattr(self, name):
197 state[name] = getattr(self, name)
200 def __setstate__(self, state):
201 """Generic unserializer.
203 This method just restores from the serialized state the attributes
204 of the current instance.
206 @param state: the serialized opcode data
210 if not isinstance(state, dict):
211 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
214 for name in self._all_slots():
215 if name not in state and hasattr(self, name):
219 setattr(self, name, state[name])
223 """Compute the list of all declared slots for a class.
227 for parent in cls.__mro__:
228 slots.extend(getattr(parent, "__slots__", []))
232 def GetAllParams(cls):
233 """Compute list of all parameters for an opcode.
237 for parent in cls.__mro__:
238 slots.extend(getattr(parent, "OP_PARAMS", []))
241 def Validate(self, set_defaults):
242 """Validate opcode parameters, optionally setting default values.
244 @type set_defaults: bool
245 @param set_defaults: Whether to set default values
246 @raise errors.OpPrereqError: When a parameter value doesn't match
250 for (attr_name, default, test) in self.GetAllParams():
251 assert test == ht.NoType or callable(test)
253 if not hasattr(self, attr_name):
254 if default == ht.NoDefault:
255 raise errors.OpPrereqError("Required parameter '%s.%s' missing" %
256 (self.OP_ID, attr_name),
259 if callable(default):
263 setattr(self, attr_name, dval)
265 if test == ht.NoType:
269 if set_defaults or hasattr(self, attr_name):
270 attr_val = getattr(self, attr_name)
271 if not test(attr_val):
272 logging.error("OpCode %s, parameter %s, has invalid type %s/value %s",
273 self.OP_ID, attr_name, type(attr_val), attr_val)
274 raise errors.OpPrereqError("Parameter '%s.%s' fails validation" %
275 (self.OP_ID, attr_name),
279 class OpCode(BaseOpCode):
282 This is the root of the actual OpCode hierarchy. All clases derived
283 from this class should override OP_ID.
285 @cvar OP_ID: The ID of this opcode. This should be unique amongst all
286 children of this class.
287 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
288 string returned by Summary(); see the docstring of that
290 @cvar OP_PARAMS: List of opcode attributes, the default values they should
291 get if not already defined, and types they must match.
292 @cvar WITH_LU: Boolean that specifies whether this should be included in
293 mcpu's dispatch table
294 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
296 @ivar priority: Opcode priority for queue
299 OP_ID = "OP_ABSTRACT"
302 ("dry_run", None, ht.TMaybeBool),
303 ("debug_level", None, ht.TOr(ht.TNone, ht.TPositiveInt)),
304 ("priority", constants.OP_PRIO_DEFAULT,
305 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID)),
308 def __getstate__(self):
309 """Specialized getstate for opcodes.
311 This method adds to the state dictionary the OP_ID of the class,
312 so that on unload we can identify the correct class for
313 instantiating the opcode.
316 @return: the state as a dictionary
319 data = BaseOpCode.__getstate__(self)
320 data["OP_ID"] = self.OP_ID
324 def LoadOpCode(cls, data):
325 """Generic load opcode method.
327 The method identifies the correct opcode class from the dict-form
328 by looking for a OP_ID key, if this is not found, or its value is
329 not available in this module as a child of this class, we fail.
332 @param data: the serialized opcode
335 if not isinstance(data, dict):
336 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
337 if "OP_ID" not in data:
338 raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
339 op_id = data["OP_ID"]
341 if op_id in OP_MAPPING:
342 op_class = OP_MAPPING[op_id]
344 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
347 new_data = data.copy()
348 del new_data["OP_ID"]
349 op.__setstate__(new_data)
353 """Generates a summary description of this opcode.
355 The summary is the value of the OP_ID attribute (without the "OP_" prefix),
356 plus the value of the OP_DSC_FIELD attribute, if one was defined; this field
357 should allow to easily identify the operation (for an instance creation job,
358 e.g., it would be the instance name).
361 # all OP_ID start with OP_, we remove that
363 field_name = getattr(self, "OP_DSC_FIELD", None)
365 field_value = getattr(self, field_name, None)
366 if isinstance(field_value, (list, tuple)):
367 field_value = ",".join(str(i) for i in field_value)
368 txt = "%s(%s)" % (txt, field_value)
374 class OpClusterPostInit(OpCode):
375 """Post cluster initialization.
377 This opcode does not touch the cluster at all. Its purpose is to run hooks
378 after the cluster has been initialized.
381 OP_ID = "OP_CLUSTER_POST_INIT"
384 class OpClusterDestroy(OpCode):
385 """Destroy the cluster.
387 This opcode has no other parameters. All the state is irreversibly
388 lost after the execution of this opcode.
391 OP_ID = "OP_CLUSTER_DESTROY"
394 class OpClusterQuery(OpCode):
395 """Query cluster information."""
396 OP_ID = "OP_CLUSTER_QUERY"
399 class OpClusterVerify(OpCode):
400 """Verify the cluster state.
402 @type skip_checks: C{list}
403 @ivar skip_checks: steps to be skipped from the verify process; this
404 needs to be a subset of
405 L{constants.VERIFY_OPTIONAL_CHECKS}; currently
406 only L{constants.VERIFY_NPLUSONE_MEM} can be passed
409 OP_ID = "OP_CLUSTER_VERIFY"
411 ("skip_checks", ht.EmptyList,
412 ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS))),
413 ("verbose", False, ht.TBool),
414 ("error_codes", False, ht.TBool),
415 ("debug_simulate_errors", False, ht.TBool),
419 class OpClusterVerifyDisks(OpCode):
420 """Verify the cluster disks.
424 Result: a tuple of four elements:
425 - list of node names with bad data returned (unreachable, etc.)
426 - dict of node names with broken volume groups (values: error msg)
427 - list of instances with degraded disks (that should be activated)
428 - dict of instances with missing logical volumes (values: (node, vol)
429 pairs with details about the missing volumes)
431 In normal operation, all lists should be empty. A non-empty instance
432 list (3rd element of the result) is still ok (errors were fixed) but
433 non-empty node list means some node is down, and probably there are
434 unfixable drbd errors.
436 Note that only instances that are drbd-based are taken into
437 consideration. This might need to be revisited in the future.
440 OP_ID = "OP_CLUSTER_VERIFY_DISKS"
443 class OpClusterRepairDiskSizes(OpCode):
444 """Verify the disk sizes of the instances and fixes configuration
447 Parameters: optional instances list, in case we want to restrict the
448 checks to only a subset of the instances.
450 Result: a list of tuples, (instance, disk, new-size) for changed
453 In normal operation, the list should be empty.
455 @type instances: list
456 @ivar instances: the list of instances to check, or empty for all instances
459 OP_ID = "OP_CLUSTER_REPAIR_DISK_SIZES"
461 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
465 class OpClusterConfigQuery(OpCode):
466 """Query cluster configuration values."""
467 OP_ID = "OP_CLUSTER_CONFIG_QUERY"
473 class OpClusterRename(OpCode):
474 """Rename the cluster.
477 @ivar name: The new name of the cluster. The name and/or the master IP
478 address will be changed to match the new name and its IP
482 OP_ID = "OP_CLUSTER_RENAME"
483 OP_DSC_FIELD = "name"
485 ("name", ht.NoDefault, ht.TNonEmptyString),
489 class OpClusterSetParams(OpCode):
490 """Change the parameters of the cluster.
492 @type vg_name: C{str} or C{None}
493 @ivar vg_name: The new volume group name or None to disable LVM usage.
496 OP_ID = "OP_CLUSTER_SET_PARAMS"
498 ("vg_name", None, ht.TMaybeString),
499 ("enabled_hypervisors", None,
500 ht.TOr(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)), ht.TTrue),
502 ("hvparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
504 ("beparams", None, ht.TOr(ht.TDict, ht.TNone)),
505 ("os_hvp", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
507 ("osparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
509 ("candidate_pool_size", None, ht.TOr(ht.TStrictPositiveInt, ht.TNone)),
510 ("uid_pool", None, ht.NoType),
511 ("add_uids", None, ht.NoType),
512 ("remove_uids", None, ht.NoType),
513 ("maintain_node_health", None, ht.TMaybeBool),
514 ("prealloc_wipe_disks", None, ht.TMaybeBool),
515 ("nicparams", None, ht.TOr(ht.TDict, ht.TNone)),
516 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
517 ("drbd_helper", None, ht.TOr(ht.TString, ht.TNone)),
518 ("default_iallocator", None, ht.TOr(ht.TString, ht.TNone)),
519 ("master_netdev", None, ht.TOr(ht.TString, ht.TNone)),
520 ("reserved_lvs", None, ht.TOr(ht.TListOf(ht.TNonEmptyString), ht.TNone)),
521 ("hidden_os", None, ht.TOr(ht.TListOf(
524 ht.TMap(lambda v: v[0], ht.TElemOf(constants.DDMS_VALUES)))),
526 ("blacklisted_os", None, ht.TOr(ht.TListOf(
529 ht.TMap(lambda v: v[0], ht.TElemOf(constants.DDMS_VALUES)))),
534 class OpClusterRedistConf(OpCode):
535 """Force a full push of the cluster configuration.
538 OP_ID = "OP_CLUSTER_REDIST_CONF"
541 class OpQuery(OpCode):
542 """Query for resources/items.
544 @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY}
545 @ivar fields: List of fields to retrieve
546 @ivar filter: Query filter
551 ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY)),
552 ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString)),
553 ("filter", None, ht.TOr(ht.TNone,
554 ht.TListOf(ht.TOr(ht.TNonEmptyString, ht.TList)))),
558 class OpQueryFields(OpCode):
559 """Query for available resource/item fields.
561 @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY}
562 @ivar fields: List of fields to retrieve
565 OP_ID = "OP_QUERY_FIELDS"
567 ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY)),
568 ("fields", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString))),
572 class OpOobCommand(OpCode):
573 """Interact with OOB."""
574 OP_ID = "OP_OOB_COMMAND"
577 ("command", None, ht.TElemOf(constants.OOB_COMMANDS)),
578 ("timeout", constants.OOB_TIMEOUT, ht.TInt),
584 class OpRemoveNode(OpCode):
587 @type node_name: C{str}
588 @ivar node_name: The name of the node to remove. If the node still has
589 instances on it, the operation will fail.
592 OP_ID = "OP_NODE_REMOVE"
593 OP_DSC_FIELD = "node_name"
599 class OpAddNode(OpCode):
600 """Add a node to the cluster.
602 @type node_name: C{str}
603 @ivar node_name: The name of the node to add. This can be a short name,
604 but it will be expanded to the FQDN.
605 @type primary_ip: IP address
606 @ivar primary_ip: The primary IP of the node. This will be ignored when the
607 opcode is submitted, but will be filled during the node
608 add (so it will be visible in the job query).
609 @type secondary_ip: IP address
610 @ivar secondary_ip: The secondary IP of the node. This needs to be passed
611 if the cluster has been initialized in 'dual-network'
612 mode, otherwise it must not be given.
614 @ivar readd: Whether to re-add an existing node to the cluster. If
615 this is not passed, then the operation will abort if the node
616 name is already in the cluster; use this parameter to 'repair'
617 a node that had its configuration broken, or was reinstalled
618 without removal from the cluster.
620 @ivar group: The node group to which this node will belong.
621 @type vm_capable: C{bool}
622 @ivar vm_capable: The vm_capable node attribute
623 @type master_capable: C{bool}
624 @ivar master_capable: The master_capable node attribute
627 OP_ID = "OP_NODE_ADD"
628 OP_DSC_FIELD = "node_name"
631 ("primary_ip", None, ht.NoType),
632 ("secondary_ip", None, ht.TMaybeString),
633 ("readd", False, ht.TBool),
634 ("group", None, ht.TMaybeString),
635 ("master_capable", None, ht.TMaybeBool),
636 ("vm_capable", None, ht.TMaybeBool),
637 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
641 class OpQueryNodes(OpCode):
642 """Compute the list of nodes."""
643 OP_ID = "OP_NODE_QUERY"
646 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
647 ("use_locking", False, ht.TBool),
651 class OpQueryNodeVolumes(OpCode):
652 """Get list of volumes on node."""
653 OP_ID = "OP_NODE_QUERYVOLS"
656 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
660 class OpQueryNodeStorage(OpCode):
661 """Get information on storage for node(s)."""
662 OP_ID = "OP_NODE_QUERY_STORAGE"
666 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
667 ("name", None, ht.TMaybeString),
671 class OpModifyNodeStorage(OpCode):
672 """Modifies the properies of a storage unit"""
673 OP_ID = "OP_NODE_MODIFY_STORAGE"
677 ("name", ht.NoDefault, ht.TNonEmptyString),
678 ("changes", ht.NoDefault, ht.TDict),
682 class OpRepairNodeStorage(OpCode):
683 """Repairs the volume group on a node."""
684 OP_ID = "OP_REPAIR_NODE_STORAGE"
685 OP_DSC_FIELD = "node_name"
689 ("name", ht.NoDefault, ht.TNonEmptyString),
690 ("ignore_consistency", False, ht.TBool),
694 class OpSetNodeParams(OpCode):
695 """Change the parameters of a node."""
696 OP_ID = "OP_NODE_SET_PARAMS"
697 OP_DSC_FIELD = "node_name"
701 ("master_candidate", None, ht.TMaybeBool),
702 ("offline", None, ht.TMaybeBool),
703 ("drained", None, ht.TMaybeBool),
704 ("auto_promote", False, ht.TBool),
705 ("master_capable", None, ht.TMaybeBool),
706 ("vm_capable", None, ht.TMaybeBool),
707 ("secondary_ip", None, ht.TMaybeString),
708 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
709 ("powered", None, ht.TMaybeBool),
713 class OpPowercycleNode(OpCode):
714 """Tries to powercycle a node."""
715 OP_ID = "OP_NODE_POWERCYCLE"
716 OP_DSC_FIELD = "node_name"
723 class OpMigrateNode(OpCode):
724 """Migrate all instances from a node."""
725 OP_ID = "OP_NODE_MIGRATE"
726 OP_DSC_FIELD = "node_name"
734 class OpNodeEvacuationStrategy(OpCode):
735 """Compute the evacuation strategy for a list of nodes."""
736 OP_ID = "OP_NODE_EVAC_STRATEGY"
737 OP_DSC_FIELD = "nodes"
739 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString)),
740 ("remote_node", None, ht.TMaybeString),
741 ("iallocator", None, ht.TMaybeString),
747 class OpCreateInstance(OpCode):
748 """Create an instance.
750 @ivar instance_name: Instance name
751 @ivar mode: Instance creation mode (one of L{constants.INSTANCE_CREATE_MODES})
752 @ivar source_handshake: Signed handshake from source (remote import only)
753 @ivar source_x509_ca: Source X509 CA in PEM format (remote import only)
754 @ivar source_instance_name: Previous name of instance (remote import only)
755 @ivar source_shutdown_timeout: Shutdown timeout used for source instance
759 OP_ID = "OP_INSTANCE_CREATE"
760 OP_DSC_FIELD = "instance_name"
763 ("beparams", ht.EmptyDict, ht.TDict),
764 ("disks", ht.NoDefault, ht.TListOf(ht.TDict)),
765 ("disk_template", ht.NoDefault, _CheckDiskTemplate),
766 ("file_driver", None, ht.TOr(ht.TNone, ht.TElemOf(constants.FILE_DRIVER))),
767 ("file_storage_dir", None, ht.TMaybeString),
768 ("force_variant", False, ht.TBool),
769 ("hvparams", ht.EmptyDict, ht.TDict),
770 ("hypervisor", None, ht.TMaybeString),
771 ("iallocator", None, ht.TMaybeString),
772 ("identify_defaults", False, ht.TBool),
773 ("ip_check", True, ht.TBool),
774 ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES)),
775 ("name_check", True, ht.TBool),
776 ("nics", ht.NoDefault, ht.TListOf(ht.TDict)),
777 ("no_install", None, ht.TMaybeBool),
778 ("osparams", ht.EmptyDict, ht.TDict),
779 ("os_type", None, ht.TMaybeString),
780 ("pnode", None, ht.TMaybeString),
781 ("snode", None, ht.TMaybeString),
782 ("source_handshake", None, ht.TOr(ht.TList, ht.TNone)),
783 ("source_instance_name", None, ht.TMaybeString),
784 ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
786 ("source_x509_ca", None, ht.TMaybeString),
787 ("src_node", None, ht.TMaybeString),
788 ("src_path", None, ht.TMaybeString),
789 ("start", True, ht.TBool),
790 ("wait_for_sync", True, ht.TBool),
794 class OpReinstallInstance(OpCode):
795 """Reinstall an instance's OS."""
796 OP_ID = "OP_INSTANCE_REINSTALL"
797 OP_DSC_FIELD = "instance_name"
800 ("os_type", None, ht.TMaybeString),
801 ("force_variant", False, ht.TBool),
802 ("osparams", None, ht.TOr(ht.TDict, ht.TNone)),
806 class OpRemoveInstance(OpCode):
807 """Remove an instance."""
808 OP_ID = "OP_INSTANCE_REMOVE"
809 OP_DSC_FIELD = "instance_name"
813 ("ignore_failures", False, ht.TBool),
817 class OpRenameInstance(OpCode):
818 """Rename an instance."""
819 OP_ID = "OP_INSTANCE_RENAME"
822 ("new_name", ht.NoDefault, ht.TNonEmptyString),
823 ("ip_check", False, ht.TBool),
824 ("name_check", True, ht.TBool),
828 class OpStartupInstance(OpCode):
829 """Startup an instance."""
830 OP_ID = "OP_INSTANCE_STARTUP"
831 OP_DSC_FIELD = "instance_name"
835 _PIgnoreOfflineNodes,
836 ("hvparams", ht.EmptyDict, ht.TDict),
837 ("beparams", ht.EmptyDict, ht.TDict),
841 class OpShutdownInstance(OpCode):
842 """Shutdown an instance."""
843 OP_ID = "OP_INSTANCE_SHUTDOWN"
844 OP_DSC_FIELD = "instance_name"
847 _PIgnoreOfflineNodes,
848 ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TPositiveInt),
852 class OpRebootInstance(OpCode):
853 """Reboot an instance."""
854 OP_ID = "OP_INSTANCE_REBOOT"
855 OP_DSC_FIELD = "instance_name"
859 ("ignore_secondaries", False, ht.TBool),
860 ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES)),
864 class OpReplaceDisks(OpCode):
865 """Replace the disks of an instance."""
866 OP_ID = "OP_INSTANCE_REPLACE_DISKS"
867 OP_DSC_FIELD = "instance_name"
870 ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES)),
871 ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt)),
872 ("remote_node", None, ht.TMaybeString),
873 ("iallocator", None, ht.TMaybeString),
874 ("early_release", False, ht.TBool),
878 class OpFailoverInstance(OpCode):
879 """Failover an instance."""
880 OP_ID = "OP_INSTANCE_FAILOVER"
881 OP_DSC_FIELD = "instance_name"
885 ("ignore_consistency", False, ht.TBool),
889 class OpMigrateInstance(OpCode):
890 """Migrate an instance.
892 This migrates (without shutting down an instance) to its secondary
895 @ivar instance_name: the name of the instance
896 @ivar mode: the migration mode (live, non-live or None for auto)
899 OP_ID = "OP_INSTANCE_MIGRATE"
900 OP_DSC_FIELD = "instance_name"
905 ("cleanup", False, ht.TBool),
909 class OpMoveInstance(OpCode):
912 This move (with shutting down an instance and data copying) to an
915 @ivar instance_name: the name of the instance
916 @ivar target_node: the destination node
919 OP_ID = "OP_INSTANCE_MOVE"
920 OP_DSC_FIELD = "instance_name"
924 ("target_node", ht.NoDefault, ht.TNonEmptyString),
928 class OpConnectConsole(OpCode):
929 """Connect to an instance's console."""
930 OP_ID = "OP_INSTANCE_CONSOLE"
931 OP_DSC_FIELD = "instance_name"
937 class OpActivateInstanceDisks(OpCode):
938 """Activate an instance's disks."""
939 OP_ID = "OP_INSTANCE_ACTIVATE_DISKS"
940 OP_DSC_FIELD = "instance_name"
943 ("ignore_size", False, ht.TBool),
947 class OpDeactivateInstanceDisks(OpCode):
948 """Deactivate an instance's disks."""
949 OP_ID = "OP_INSTANCE_DEACTIVATE_DISKS"
950 OP_DSC_FIELD = "instance_name"
956 class OpRecreateInstanceDisks(OpCode):
957 """Deactivate an instance's disks."""
958 OP_ID = "OP_INSTANCE_RECREATE_DISKS"
959 OP_DSC_FIELD = "instance_name"
962 ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt)),
966 class OpQueryInstances(OpCode):
967 """Compute the list of instances."""
968 OP_ID = "OP_INSTANCE_QUERY"
971 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
972 ("use_locking", False, ht.TBool),
976 class OpQueryInstanceData(OpCode):
977 """Compute the run-time status of instances."""
978 OP_ID = "OP_INSTANCE_QUERY_DATA"
980 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
981 ("static", False, ht.TBool),
985 class OpSetInstanceParams(OpCode):
986 """Change the parameters of an instance."""
987 OP_ID = "OP_INSTANCE_SET_PARAMS"
988 OP_DSC_FIELD = "instance_name"
992 ("nics", ht.EmptyList, ht.TList),
993 ("disks", ht.EmptyList, ht.TList),
994 ("beparams", ht.EmptyDict, ht.TDict),
995 ("hvparams", ht.EmptyDict, ht.TDict),
996 ("disk_template", None, ht.TOr(ht.TNone, _CheckDiskTemplate)),
997 ("remote_node", None, ht.TMaybeString),
998 ("os_name", None, ht.TMaybeString),
999 ("force_variant", False, ht.TBool),
1000 ("osparams", None, ht.TOr(ht.TDict, ht.TNone)),
1004 class OpGrowDisk(OpCode):
1005 """Grow a disk of an instance."""
1006 OP_ID = "OP_INSTANCE_GROW_DISK"
1007 OP_DSC_FIELD = "instance_name"
1010 ("disk", ht.NoDefault, ht.TInt),
1011 ("amount", ht.NoDefault, ht.TInt),
1012 ("wait_for_sync", True, ht.TBool),
1016 # Node group opcodes
1018 class OpAddGroup(OpCode):
1019 """Add a node group to the cluster."""
1020 OP_ID = "OP_GROUP_ADD"
1021 OP_DSC_FIELD = "group_name"
1024 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
1025 ("alloc_policy", None,
1026 ht.TOr(ht.TNone, ht.TElemOf(constants.VALID_ALLOC_POLICIES))),
1030 class OpAssignGroupNodes(OpCode):
1031 """Assign nodes to a node group."""
1032 OP_ID = "OP_GROUP_ASSIGN_NODES"
1033 OP_DSC_FIELD = "group_name"
1037 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString)),
1041 class OpQueryGroups(OpCode):
1042 """Compute the list of node groups."""
1043 OP_ID = "OP_GROUP_QUERY"
1046 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1050 class OpSetGroupParams(OpCode):
1051 """Change the parameters of a node group."""
1052 OP_ID = "OP_GROUP_SET_PARAMS"
1053 OP_DSC_FIELD = "group_name"
1056 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
1057 ("alloc_policy", None, ht.TOr(ht.TNone,
1058 ht.TElemOf(constants.VALID_ALLOC_POLICIES))),
1062 class OpRemoveGroup(OpCode):
1063 """Remove a node group from the cluster."""
1064 OP_ID = "OP_GROUP_REMOVE"
1065 OP_DSC_FIELD = "group_name"
1071 class OpRenameGroup(OpCode):
1072 """Rename a node group in the cluster."""
1073 OP_ID = "OP_GROUP_RENAME"
1074 OP_DSC_FIELD = "old_name"
1076 ("old_name", ht.NoDefault, ht.TNonEmptyString),
1077 ("new_name", ht.NoDefault, ht.TNonEmptyString),
1082 class OpDiagnoseOS(OpCode):
1083 """Compute the list of guest operating systems."""
1084 OP_ID = "OP_OS_DIAGNOSE"
1087 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1092 class OpBackupQuery(OpCode):
1093 """Compute the list of exported images."""
1094 OP_ID = "OP_BACKUP_QUERY"
1096 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1097 ("use_locking", False, ht.TBool),
1101 class OpBackupPrepare(OpCode):
1102 """Prepares an instance export.
1104 @ivar instance_name: Instance name
1105 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1108 OP_ID = "OP_BACKUP_PREPARE"
1109 OP_DSC_FIELD = "instance_name"
1112 ("mode", ht.NoDefault, ht.TElemOf(constants.EXPORT_MODES)),
1116 class OpBackupExport(OpCode):
1117 """Export an instance.
1119 For local exports, the export destination is the node name. For remote
1120 exports, the export destination is a list of tuples, each consisting of
1121 hostname/IP address, port, HMAC and HMAC salt. The HMAC is calculated using
1122 the cluster domain secret over the value "${index}:${hostname}:${port}". The
1123 destination X509 CA must be a signed certificate.
1125 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1126 @ivar target_node: Export destination
1127 @ivar x509_key_name: X509 key to use (remote export only)
1128 @ivar destination_x509_ca: Destination X509 CA in PEM format (remote export
1132 OP_ID = "OP_BACKUP_EXPORT"
1133 OP_DSC_FIELD = "instance_name"
1137 # TODO: Rename target_node as it changes meaning for different export modes
1138 # (e.g. "destination")
1139 ("target_node", ht.NoDefault, ht.TOr(ht.TNonEmptyString, ht.TList)),
1140 ("shutdown", True, ht.TBool),
1141 ("remove_instance", False, ht.TBool),
1142 ("ignore_remove_failures", False, ht.TBool),
1143 ("mode", constants.EXPORT_MODE_LOCAL, ht.TElemOf(constants.EXPORT_MODES)),
1144 ("x509_key_name", None, ht.TOr(ht.TList, ht.TNone)),
1145 ("destination_x509_ca", None, ht.TMaybeString),
1149 class OpBackupRemove(OpCode):
1150 """Remove an instance's export."""
1151 OP_ID = "OP_BACKUP_REMOVE"
1152 OP_DSC_FIELD = "instance_name"
1159 class OpGetTags(OpCode):
1160 """Returns the tags of the given object."""
1161 OP_ID = "OP_TAGS_GET"
1162 OP_DSC_FIELD = "name"
1165 # Name is only meaningful for nodes and instances
1166 ("name", ht.NoDefault, ht.TMaybeString),
1170 class OpSearchTags(OpCode):
1171 """Searches the tags in the cluster for a given pattern."""
1172 OP_ID = "OP_TAGS_SEARCH"
1173 OP_DSC_FIELD = "pattern"
1175 ("pattern", ht.NoDefault, ht.TNonEmptyString),
1179 class OpAddTags(OpCode):
1180 """Add a list of tags on a given object."""
1181 OP_ID = "OP_TAGS_SET"
1185 # Name is only meaningful for nodes and instances
1186 ("name", ht.NoDefault, ht.TMaybeString),
1190 class OpDelTags(OpCode):
1191 """Remove a list of tags from a given object."""
1192 OP_ID = "OP_TAGS_DEL"
1196 # Name is only meaningful for nodes and instances
1197 ("name", ht.NoDefault, ht.TMaybeString),
1201 class OpTestDelay(OpCode):
1202 """Sleeps for a configured amount of time.
1204 This is used just for debugging and testing.
1207 - duration: the time to sleep
1208 - on_master: if true, sleep on the master
1209 - on_nodes: list of nodes in which to sleep
1211 If the on_master parameter is true, it will execute a sleep on the
1212 master (before any node sleep).
1214 If the on_nodes list is not empty, it will sleep on those nodes
1215 (after the sleep on the master, if that is enabled).
1217 As an additional feature, the case of duration < 0 will be reported
1218 as an execution error, so this opcode can be used as a failure
1219 generator. The case of duration == 0 will not be treated specially.
1222 OP_ID = "OP_TEST_DELAY"
1223 OP_DSC_FIELD = "duration"
1225 ("duration", ht.NoDefault, ht.TFloat),
1226 ("on_master", True, ht.TBool),
1227 ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1228 ("repeat", 0, ht.TPositiveInt)
1232 class OpTestAllocator(OpCode):
1233 """Allocator framework testing.
1235 This opcode has two modes:
1236 - gather and return allocator input for a given mode (allocate new
1237 or replace secondary) and a given instance definition (direction
1239 - run a selected allocator for a given operation (as above) and
1240 return the allocator output (direction 'out')
1243 OP_ID = "OP_TEST_ALLOCATOR"
1244 OP_DSC_FIELD = "allocator"
1246 ("direction", ht.NoDefault,
1247 ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)),
1248 ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES)),
1249 ("name", ht.NoDefault, ht.TNonEmptyString),
1250 ("nics", ht.NoDefault, ht.TOr(ht.TNone, ht.TListOf(
1251 ht.TDictOf(ht.TElemOf(["mac", "ip", "bridge"]),
1252 ht.TOr(ht.TNone, ht.TNonEmptyString))))),
1253 ("disks", ht.NoDefault, ht.TOr(ht.TNone, ht.TList)),
1254 ("hypervisor", None, ht.TMaybeString),
1255 ("allocator", None, ht.TMaybeString),
1256 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1257 ("mem_size", None, ht.TOr(ht.TNone, ht.TPositiveInt)),
1258 ("vcpus", None, ht.TOr(ht.TNone, ht.TPositiveInt)),
1259 ("os", None, ht.TMaybeString),
1260 ("disk_template", None, ht.TMaybeString),
1261 ("evac_nodes", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString))),
1265 class OpTestJobqueue(OpCode):
1266 """Utility opcode to test some aspects of the job queue.
1269 OP_ID = "OP_TEST_JQUEUE"
1271 ("notify_waitlock", False, ht.TBool),
1272 ("notify_exec", False, ht.TBool),
1273 ("log_messages", ht.EmptyList, ht.TListOf(ht.TString)),
1274 ("fail", False, ht.TBool),
1278 class OpTestDummy(OpCode):
1279 """Utility opcode used by unittests.
1282 OP_ID = "OP_TEST_DUMMY"
1284 ("result", ht.NoDefault, ht.NoType),
1285 ("messages", ht.NoDefault, ht.NoType),
1286 ("fail", ht.NoDefault, ht.NoType),
1292 """Returns list of all defined opcodes.
1294 Does not eliminate duplicates by C{OP_ID}.
1297 return [v for v in globals().values()
1298 if (isinstance(v, type) and issubclass(v, OpCode) and
1299 hasattr(v, "OP_ID") and v is not OpCode)]
1302 OP_MAPPING = dict((v.OP_ID, v) for v in _GetOpList())