4 # Copyright (C) 2006, 2007, 2008, 2009, 2010 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
36 from ganeti import constants
37 from ganeti import errors
41 # Common opcode attributes
43 #: output fields for a query operation
44 _POutputFields = ("output_fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
46 #: the shutdown timeout
47 _PShutdownTimeout = ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
50 #: the force parameter
51 _PForce = ("force", False, ht.TBool)
53 #: a required instance name (for single-instance LUs)
54 _PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString)
56 #: Whether to ignore offline nodes
57 _PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool)
59 #: a required node name (for single-node LUs)
60 _PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString)
62 #: a required node group name (for single-group LUs)
63 _PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString)
65 #: Migration type (live/non-live)
66 _PMigrationMode = ("mode", None,
67 ht.TOr(ht.TNone, ht.TElemOf(constants.HT_MIGRATION_MODES)))
69 #: Obsolete 'live' migration mode (boolean)
70 _PMigrationLive = ("live", None, ht.TMaybeBool)
73 _PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES))
75 #: List of tag strings
76 _PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
79 def RequireFileStorage():
80 """Checks that file storage is enabled.
82 While it doesn't really fit into this module, L{utils} was deemed too large
83 of a dependency to be imported for just one or two functions.
85 @raise errors.OpPrereqError: when file storage is disabled
88 if not constants.ENABLE_FILE_STORAGE:
89 raise errors.OpPrereqError("File storage disabled at configure time",
93 def _CheckDiskTemplate(template):
94 """Ensure a given disk template is valid.
97 if template not in constants.DISK_TEMPLATES:
98 # Using str.join directly to avoid importing utils for CommaJoin
99 msg = ("Invalid disk template name '%s', valid templates are: %s" %
100 (template, ", ".join(constants.DISK_TEMPLATES)))
101 raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
102 if template == constants.DT_FILE:
107 def _CheckStorageType(storage_type):
108 """Ensure a given storage type is valid.
111 if storage_type not in constants.VALID_STORAGE_TYPES:
112 raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
114 if storage_type == constants.ST_FILE:
119 #: Storage type parameter
120 _PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType)
123 class _AutoOpParamSlots(type):
124 """Meta class for opcode definitions.
127 def __new__(mcs, name, bases, attrs):
128 """Called when a class should be created.
130 @param mcs: The meta class
131 @param name: Name of created class
132 @param bases: Base classes
134 @param attrs: Class attributes
137 assert "__slots__" not in attrs, \
138 "Class '%s' defines __slots__ when it should use OP_PARAMS" % name
139 assert "OP_ID" in attrs, "Class '%s' is missing OP_ID attribute" % name
141 # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams
142 params = attrs.setdefault("OP_PARAMS", [])
144 # Use parameter names as slots
145 slots = [pname for (pname, _, _) in params]
147 assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
148 "Class '%s' uses unknown field in OP_DSC_FIELD" % name
150 attrs["__slots__"] = slots
152 return type.__new__(mcs, name, bases, attrs)
155 class BaseOpCode(object):
156 """A simple serializable object.
158 This object serves as a parent class for OpCode without any custom
162 __metaclass__ = _AutoOpParamSlots
166 def __init__(self, **kwargs):
167 """Constructor for BaseOpCode.
169 The constructor takes only keyword arguments and will set
170 attributes on this object based on the passed arguments. As such,
171 it means that you should not pass arguments which are not in the
172 __slots__ attribute for this class.
175 slots = self._all_slots()
178 raise TypeError("Object %s doesn't support the parameter '%s'" %
179 (self.__class__.__name__, key))
180 setattr(self, key, kwargs[key])
182 def __getstate__(self):
183 """Generic serializer.
185 This method just returns the contents of the instance as a
189 @return: the instance attributes and their values
193 for name in self._all_slots():
194 if hasattr(self, name):
195 state[name] = getattr(self, name)
198 def __setstate__(self, state):
199 """Generic unserializer.
201 This method just restores from the serialized state the attributes
202 of the current instance.
204 @param state: the serialized opcode data
208 if not isinstance(state, dict):
209 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
212 for name in self._all_slots():
213 if name not in state and hasattr(self, name):
217 setattr(self, name, state[name])
221 """Compute the list of all declared slots for a class.
225 for parent in cls.__mro__:
226 slots.extend(getattr(parent, "__slots__", []))
230 def GetAllParams(cls):
231 """Compute list of all parameters for an opcode.
235 for parent in cls.__mro__:
236 slots.extend(getattr(parent, "OP_PARAMS", []))
240 class OpCode(BaseOpCode):
243 This is the root of the actual OpCode hierarchy. All clases derived
244 from this class should override OP_ID.
246 @cvar OP_ID: The ID of this opcode. This should be unique amongst all
247 children of this class.
248 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
249 string returned by Summary(); see the docstring of that
251 @cvar OP_PARAMS: List of opcode attributes, the default values they should
252 get if not already defined, and types they must match.
253 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
255 @ivar priority: Opcode priority for queue
258 OP_ID = "OP_ABSTRACT"
260 ("dry_run", None, ht.TMaybeBool),
261 ("debug_level", None, ht.TOr(ht.TNone, ht.TPositiveInt)),
262 ("priority", constants.OP_PRIO_DEFAULT,
263 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID)),
266 def __getstate__(self):
267 """Specialized getstate for opcodes.
269 This method adds to the state dictionary the OP_ID of the class,
270 so that on unload we can identify the correct class for
271 instantiating the opcode.
274 @return: the state as a dictionary
277 data = BaseOpCode.__getstate__(self)
278 data["OP_ID"] = self.OP_ID
282 def LoadOpCode(cls, data):
283 """Generic load opcode method.
285 The method identifies the correct opcode class from the dict-form
286 by looking for a OP_ID key, if this is not found, or its value is
287 not available in this module as a child of this class, we fail.
290 @param data: the serialized opcode
293 if not isinstance(data, dict):
294 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
295 if "OP_ID" not in data:
296 raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
297 op_id = data["OP_ID"]
299 if op_id in OP_MAPPING:
300 op_class = OP_MAPPING[op_id]
302 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
305 new_data = data.copy()
306 del new_data["OP_ID"]
307 op.__setstate__(new_data)
311 """Generates a summary description of this opcode.
313 The summary is the value of the OP_ID attribute (without the "OP_" prefix),
314 plus the value of the OP_DSC_FIELD attribute, if one was defined; this field
315 should allow to easily identify the operation (for an instance creation job,
316 e.g., it would be the instance name).
319 # all OP_ID start with OP_, we remove that
321 field_name = getattr(self, "OP_DSC_FIELD", None)
323 field_value = getattr(self, field_name, None)
324 if isinstance(field_value, (list, tuple)):
325 field_value = ",".join(str(i) for i in field_value)
326 txt = "%s(%s)" % (txt, field_value)
332 class OpPostInitCluster(OpCode):
333 """Post cluster initialization.
335 This opcode does not touch the cluster at all. Its purpose is to run hooks
336 after the cluster has been initialized.
339 OP_ID = "OP_CLUSTER_POST_INIT"
342 class OpDestroyCluster(OpCode):
343 """Destroy the cluster.
345 This opcode has no other parameters. All the state is irreversibly
346 lost after the execution of this opcode.
349 OP_ID = "OP_CLUSTER_DESTROY"
352 class OpQueryClusterInfo(OpCode):
353 """Query cluster information."""
354 OP_ID = "OP_CLUSTER_QUERY"
357 class OpVerifyCluster(OpCode):
358 """Verify the cluster state.
360 @type skip_checks: C{list}
361 @ivar skip_checks: steps to be skipped from the verify process; this
362 needs to be a subset of
363 L{constants.VERIFY_OPTIONAL_CHECKS}; currently
364 only L{constants.VERIFY_NPLUSONE_MEM} can be passed
367 OP_ID = "OP_CLUSTER_VERIFY"
369 ("skip_checks", ht.EmptyList,
370 ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS))),
371 ("verbose", False, ht.TBool),
372 ("error_codes", False, ht.TBool),
373 ("debug_simulate_errors", False, ht.TBool),
377 class OpVerifyDisks(OpCode):
378 """Verify the cluster disks.
382 Result: a tuple of four elements:
383 - list of node names with bad data returned (unreachable, etc.)
384 - dict of node names with broken volume groups (values: error msg)
385 - list of instances with degraded disks (that should be activated)
386 - dict of instances with missing logical volumes (values: (node, vol)
387 pairs with details about the missing volumes)
389 In normal operation, all lists should be empty. A non-empty instance
390 list (3rd element of the result) is still ok (errors were fixed) but
391 non-empty node list means some node is down, and probably there are
392 unfixable drbd errors.
394 Note that only instances that are drbd-based are taken into
395 consideration. This might need to be revisited in the future.
398 OP_ID = "OP_CLUSTER_VERIFY_DISKS"
401 class OpRepairDiskSizes(OpCode):
402 """Verify the disk sizes of the instances and fixes configuration
405 Parameters: optional instances list, in case we want to restrict the
406 checks to only a subset of the instances.
408 Result: a list of tuples, (instance, disk, new-size) for changed
411 In normal operation, the list should be empty.
413 @type instances: list
414 @ivar instances: the list of instances to check, or empty for all instances
417 OP_ID = "OP_CLUSTER_REPAIR_DISK_SIZES"
419 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
423 class OpQueryConfigValues(OpCode):
424 """Query cluster configuration values."""
425 OP_ID = "OP_CLUSTER_CONFIG_QUERY"
431 class OpRenameCluster(OpCode):
432 """Rename the cluster.
435 @ivar name: The new name of the cluster. The name and/or the master IP
436 address will be changed to match the new name and its IP
440 OP_ID = "OP_CLUSTER_RENAME"
441 OP_DSC_FIELD = "name"
443 ("name", ht.NoDefault, ht.TNonEmptyString),
447 class OpSetClusterParams(OpCode):
448 """Change the parameters of the cluster.
450 @type vg_name: C{str} or C{None}
451 @ivar vg_name: The new volume group name or None to disable LVM usage.
454 OP_ID = "OP_CLUSTER_SET_PARAMS"
456 ("vg_name", None, ht.TMaybeString),
457 ("enabled_hypervisors", None,
458 ht.TOr(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)), ht.TTrue),
460 ("hvparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
462 ("beparams", None, ht.TOr(ht.TDict, ht.TNone)),
463 ("os_hvp", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
465 ("osparams", None, ht.TOr(ht.TDictOf(ht.TNonEmptyString, ht.TDict),
467 ("candidate_pool_size", None, ht.TOr(ht.TStrictPositiveInt, ht.TNone)),
468 ("uid_pool", None, ht.NoType),
469 ("add_uids", None, ht.NoType),
470 ("remove_uids", None, ht.NoType),
471 ("maintain_node_health", None, ht.TMaybeBool),
472 ("prealloc_wipe_disks", None, ht.TMaybeBool),
473 ("nicparams", None, ht.TOr(ht.TDict, ht.TNone)),
474 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
475 ("drbd_helper", None, ht.TOr(ht.TString, ht.TNone)),
476 ("default_iallocator", None, ht.TOr(ht.TString, ht.TNone)),
477 ("master_netdev", None, ht.TOr(ht.TString, ht.TNone)),
478 ("reserved_lvs", None, ht.TOr(ht.TListOf(ht.TNonEmptyString), ht.TNone)),
479 ("hidden_os", None, ht.TOr(ht.TListOf(
482 ht.TMap(lambda v: v[0], ht.TElemOf(constants.DDMS_VALUES)))),
484 ("blacklisted_os", None, ht.TOr(ht.TListOf(
487 ht.TMap(lambda v: v[0], ht.TElemOf(constants.DDMS_VALUES)))),
492 class OpRedistributeConfig(OpCode):
493 """Force a full push of the cluster configuration.
496 OP_ID = "OP_CLUSTER_REDIST_CONF"
499 class OpQuery(OpCode):
500 """Query for resources/items.
502 @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY}
503 @ivar fields: List of fields to retrieve
504 @ivar filter: Query filter
509 ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY)),
510 ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString)),
511 ("filter", None, ht.TOr(ht.TNone,
512 ht.TListOf(ht.TOr(ht.TNonEmptyString, ht.TList)))),
516 class OpQueryFields(OpCode):
517 """Query for available resource/item fields.
519 @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY}
520 @ivar fields: List of fields to retrieve
523 OP_ID = "OP_QUERY_FIELDS"
525 ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY)),
526 ("fields", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString))),
530 class OpOobCommand(OpCode):
531 """Interact with OOB."""
532 OP_ID = "OP_OOB_COMMAND"
535 ("command", None, ht.TElemOf(constants.OOB_COMMANDS)),
536 ("timeout", constants.OOB_TIMEOUT, ht.TInt),
542 class OpRemoveNode(OpCode):
545 @type node_name: C{str}
546 @ivar node_name: The name of the node to remove. If the node still has
547 instances on it, the operation will fail.
550 OP_ID = "OP_NODE_REMOVE"
551 OP_DSC_FIELD = "node_name"
557 class OpAddNode(OpCode):
558 """Add a node to the cluster.
560 @type node_name: C{str}
561 @ivar node_name: The name of the node to add. This can be a short name,
562 but it will be expanded to the FQDN.
563 @type primary_ip: IP address
564 @ivar primary_ip: The primary IP of the node. This will be ignored when the
565 opcode is submitted, but will be filled during the node
566 add (so it will be visible in the job query).
567 @type secondary_ip: IP address
568 @ivar secondary_ip: The secondary IP of the node. This needs to be passed
569 if the cluster has been initialized in 'dual-network'
570 mode, otherwise it must not be given.
572 @ivar readd: Whether to re-add an existing node to the cluster. If
573 this is not passed, then the operation will abort if the node
574 name is already in the cluster; use this parameter to 'repair'
575 a node that had its configuration broken, or was reinstalled
576 without removal from the cluster.
578 @ivar group: The node group to which this node will belong.
579 @type vm_capable: C{bool}
580 @ivar vm_capable: The vm_capable node attribute
581 @type master_capable: C{bool}
582 @ivar master_capable: The master_capable node attribute
585 OP_ID = "OP_NODE_ADD"
586 OP_DSC_FIELD = "node_name"
589 ("primary_ip", None, ht.NoType),
590 ("secondary_ip", None, ht.TMaybeString),
591 ("readd", False, ht.TBool),
592 ("group", None, ht.TMaybeString),
593 ("master_capable", None, ht.TMaybeBool),
594 ("vm_capable", None, ht.TMaybeBool),
595 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
599 class OpQueryNodes(OpCode):
600 """Compute the list of nodes."""
601 OP_ID = "OP_NODE_QUERY"
604 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
605 ("use_locking", False, ht.TBool),
609 class OpQueryNodeVolumes(OpCode):
610 """Get list of volumes on node."""
611 OP_ID = "OP_NODE_QUERYVOLS"
614 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
618 class OpQueryNodeStorage(OpCode):
619 """Get information on storage for node(s)."""
620 OP_ID = "OP_NODE_QUERY_STORAGE"
624 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
625 ("name", None, ht.TMaybeString),
629 class OpModifyNodeStorage(OpCode):
630 """Modifies the properies of a storage unit"""
631 OP_ID = "OP_NODE_MODIFY_STORAGE"
635 ("name", ht.NoDefault, ht.TNonEmptyString),
636 ("changes", ht.NoDefault, ht.TDict),
640 class OpRepairNodeStorage(OpCode):
641 """Repairs the volume group on a node."""
642 OP_ID = "OP_REPAIR_NODE_STORAGE"
643 OP_DSC_FIELD = "node_name"
647 ("name", ht.NoDefault, ht.TNonEmptyString),
648 ("ignore_consistency", False, ht.TBool),
652 class OpSetNodeParams(OpCode):
653 """Change the parameters of a node."""
654 OP_ID = "OP_NODE_SET_PARAMS"
655 OP_DSC_FIELD = "node_name"
659 ("master_candidate", None, ht.TMaybeBool),
660 ("offline", None, ht.TMaybeBool),
661 ("drained", None, ht.TMaybeBool),
662 ("auto_promote", False, ht.TBool),
663 ("master_capable", None, ht.TMaybeBool),
664 ("vm_capable", None, ht.TMaybeBool),
665 ("secondary_ip", None, ht.TMaybeString),
666 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
667 ("powered", None, ht.TMaybeBool),
671 class OpPowercycleNode(OpCode):
672 """Tries to powercycle a node."""
673 OP_ID = "OP_NODE_POWERCYCLE"
674 OP_DSC_FIELD = "node_name"
681 class OpMigrateNode(OpCode):
682 """Migrate all instances from a node."""
683 OP_ID = "OP_NODE_MIGRATE"
684 OP_DSC_FIELD = "node_name"
692 class OpNodeEvacuationStrategy(OpCode):
693 """Compute the evacuation strategy for a list of nodes."""
694 OP_ID = "OP_NODE_EVAC_STRATEGY"
695 OP_DSC_FIELD = "nodes"
697 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString)),
698 ("remote_node", None, ht.TMaybeString),
699 ("iallocator", None, ht.TMaybeString),
705 class OpCreateInstance(OpCode):
706 """Create an instance.
708 @ivar instance_name: Instance name
709 @ivar mode: Instance creation mode (one of L{constants.INSTANCE_CREATE_MODES})
710 @ivar source_handshake: Signed handshake from source (remote import only)
711 @ivar source_x509_ca: Source X509 CA in PEM format (remote import only)
712 @ivar source_instance_name: Previous name of instance (remote import only)
713 @ivar source_shutdown_timeout: Shutdown timeout used for source instance
717 OP_ID = "OP_INSTANCE_CREATE"
718 OP_DSC_FIELD = "instance_name"
721 ("beparams", ht.EmptyDict, ht.TDict),
722 ("disks", ht.NoDefault, ht.TListOf(ht.TDict)),
723 ("disk_template", ht.NoDefault, _CheckDiskTemplate),
724 ("file_driver", None, ht.TOr(ht.TNone, ht.TElemOf(constants.FILE_DRIVER))),
725 ("file_storage_dir", None, ht.TMaybeString),
726 ("force_variant", False, ht.TBool),
727 ("hvparams", ht.EmptyDict, ht.TDict),
728 ("hypervisor", None, ht.TMaybeString),
729 ("iallocator", None, ht.TMaybeString),
730 ("identify_defaults", False, ht.TBool),
731 ("ip_check", True, ht.TBool),
732 ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES)),
733 ("name_check", True, ht.TBool),
734 ("nics", ht.NoDefault, ht.TListOf(ht.TDict)),
735 ("no_install", None, ht.TMaybeBool),
736 ("osparams", ht.EmptyDict, ht.TDict),
737 ("os_type", None, ht.TMaybeString),
738 ("pnode", None, ht.TMaybeString),
739 ("snode", None, ht.TMaybeString),
740 ("source_handshake", None, ht.TOr(ht.TList, ht.TNone)),
741 ("source_instance_name", None, ht.TMaybeString),
742 ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
744 ("source_x509_ca", None, ht.TMaybeString),
745 ("src_node", None, ht.TMaybeString),
746 ("src_path", None, ht.TMaybeString),
747 ("start", True, ht.TBool),
748 ("wait_for_sync", True, ht.TBool),
752 class OpReinstallInstance(OpCode):
753 """Reinstall an instance's OS."""
754 OP_ID = "OP_INSTANCE_REINSTALL"
755 OP_DSC_FIELD = "instance_name"
758 ("os_type", None, ht.TMaybeString),
759 ("force_variant", False, ht.TBool),
760 ("osparams", None, ht.TOr(ht.TDict, ht.TNone)),
764 class OpRemoveInstance(OpCode):
765 """Remove an instance."""
766 OP_ID = "OP_INSTANCE_REMOVE"
767 OP_DSC_FIELD = "instance_name"
771 ("ignore_failures", False, ht.TBool),
775 class OpRenameInstance(OpCode):
776 """Rename an instance."""
777 OP_ID = "OP_INSTANCE_RENAME"
780 ("new_name", ht.NoDefault, ht.TNonEmptyString),
781 ("ip_check", False, ht.TBool),
782 ("name_check", True, ht.TBool),
786 class OpStartupInstance(OpCode):
787 """Startup an instance."""
788 OP_ID = "OP_INSTANCE_STARTUP"
789 OP_DSC_FIELD = "instance_name"
793 _PIgnoreOfflineNodes,
794 ("hvparams", ht.EmptyDict, ht.TDict),
795 ("beparams", ht.EmptyDict, ht.TDict),
799 class OpShutdownInstance(OpCode):
800 """Shutdown an instance."""
801 OP_ID = "OP_INSTANCE_SHUTDOWN"
802 OP_DSC_FIELD = "instance_name"
805 _PIgnoreOfflineNodes,
806 ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TPositiveInt),
810 class OpRebootInstance(OpCode):
811 """Reboot an instance."""
812 OP_ID = "OP_INSTANCE_REBOOT"
813 OP_DSC_FIELD = "instance_name"
817 ("ignore_secondaries", False, ht.TBool),
818 ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES)),
822 class OpReplaceDisks(OpCode):
823 """Replace the disks of an instance."""
824 OP_ID = "OP_INSTANCE_REPLACE_DISKS"
825 OP_DSC_FIELD = "instance_name"
828 ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES)),
829 ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt)),
830 ("remote_node", None, ht.TMaybeString),
831 ("iallocator", None, ht.TMaybeString),
832 ("early_release", False, ht.TBool),
836 class OpFailoverInstance(OpCode):
837 """Failover an instance."""
838 OP_ID = "OP_INSTANCE_FAILOVER"
839 OP_DSC_FIELD = "instance_name"
843 ("ignore_consistency", False, ht.TBool),
847 class OpMigrateInstance(OpCode):
848 """Migrate an instance.
850 This migrates (without shutting down an instance) to its secondary
853 @ivar instance_name: the name of the instance
854 @ivar mode: the migration mode (live, non-live or None for auto)
857 OP_ID = "OP_INSTANCE_MIGRATE"
858 OP_DSC_FIELD = "instance_name"
863 ("cleanup", False, ht.TBool),
867 class OpMoveInstance(OpCode):
870 This move (with shutting down an instance and data copying) to an
873 @ivar instance_name: the name of the instance
874 @ivar target_node: the destination node
877 OP_ID = "OP_INSTANCE_MOVE"
878 OP_DSC_FIELD = "instance_name"
882 ("target_node", ht.NoDefault, ht.TNonEmptyString),
886 class OpConnectConsole(OpCode):
887 """Connect to an instance's console."""
888 OP_ID = "OP_INSTANCE_CONSOLE"
889 OP_DSC_FIELD = "instance_name"
895 class OpActivateInstanceDisks(OpCode):
896 """Activate an instance's disks."""
897 OP_ID = "OP_INSTANCE_ACTIVATE_DISKS"
898 OP_DSC_FIELD = "instance_name"
901 ("ignore_size", False, ht.TBool),
905 class OpDeactivateInstanceDisks(OpCode):
906 """Deactivate an instance's disks."""
907 OP_ID = "OP_INSTANCE_DEACTIVATE_DISKS"
908 OP_DSC_FIELD = "instance_name"
914 class OpRecreateInstanceDisks(OpCode):
915 """Deactivate an instance's disks."""
916 OP_ID = "OP_INSTANCE_RECREATE_DISKS"
917 OP_DSC_FIELD = "instance_name"
920 ("disks", ht.EmptyList, ht.TListOf(ht.TPositiveInt)),
924 class OpQueryInstances(OpCode):
925 """Compute the list of instances."""
926 OP_ID = "OP_INSTANCE_QUERY"
929 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
930 ("use_locking", False, ht.TBool),
934 class OpQueryInstanceData(OpCode):
935 """Compute the run-time status of instances."""
936 OP_ID = "OP_INSTANCE_QUERY_DATA"
938 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
939 ("static", False, ht.TBool),
943 class OpSetInstanceParams(OpCode):
944 """Change the parameters of an instance."""
945 OP_ID = "OP_INSTANCE_SET_PARAMS"
946 OP_DSC_FIELD = "instance_name"
950 ("nics", ht.EmptyList, ht.TList),
951 ("disks", ht.EmptyList, ht.TList),
952 ("beparams", ht.EmptyDict, ht.TDict),
953 ("hvparams", ht.EmptyDict, ht.TDict),
954 ("disk_template", None, _CheckDiskTemplate),
955 ("remote_node", None, ht.TMaybeString),
956 ("os_name", None, ht.TMaybeString),
957 ("force_variant", False, ht.TBool),
958 ("osparams", None, ht.TOr(ht.TDict, ht.TNone)),
962 class OpGrowDisk(OpCode):
963 """Grow a disk of an instance."""
964 OP_ID = "OP_INSTANCE_GROW_DISK"
965 OP_DSC_FIELD = "instance_name"
968 ("disk", ht.NoDefault, ht.TInt),
969 ("amount", ht.NoDefault, ht.TInt),
970 ("wait_for_sync", True, ht.TBool),
976 class OpAddGroup(OpCode):
977 """Add a node group to the cluster."""
978 OP_ID = "OP_GROUP_ADD"
979 OP_DSC_FIELD = "group_name"
982 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
983 ("alloc_policy", None,
984 ht.TOr(ht.TNone, ht.TElemOf(constants.VALID_ALLOC_POLICIES))),
988 class OpQueryGroups(OpCode):
989 """Compute the list of node groups."""
990 OP_ID = "OP_GROUP_QUERY"
993 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
997 class OpSetGroupParams(OpCode):
998 """Change the parameters of a node group."""
999 OP_ID = "OP_GROUP_SET_PARAMS"
1000 OP_DSC_FIELD = "group_name"
1003 ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)),
1004 ("alloc_policy", None, ht.TOr(ht.TNone,
1005 ht.TElemOf(constants.VALID_ALLOC_POLICIES))),
1009 class OpRemoveGroup(OpCode):
1010 """Remove a node group from the cluster."""
1011 OP_ID = "OP_GROUP_REMOVE"
1012 OP_DSC_FIELD = "group_name"
1018 class OpRenameGroup(OpCode):
1019 """Rename a node group in the cluster."""
1020 OP_ID = "OP_GROUP_RENAME"
1021 OP_DSC_FIELD = "old_name"
1023 ("old_name", ht.NoDefault, ht.TNonEmptyString),
1024 ("new_name", ht.NoDefault, ht.TNonEmptyString),
1029 class OpDiagnoseOS(OpCode):
1030 """Compute the list of guest operating systems."""
1031 OP_ID = "OP_OS_DIAGNOSE"
1034 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1039 class OpQueryExports(OpCode):
1040 """Compute the list of exported images."""
1041 OP_ID = "OP_BACKUP_QUERY"
1043 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1044 ("use_locking", False, ht.TBool),
1048 class OpPrepareExport(OpCode):
1049 """Prepares an instance export.
1051 @ivar instance_name: Instance name
1052 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1055 OP_ID = "OP_BACKUP_PREPARE"
1056 OP_DSC_FIELD = "instance_name"
1059 ("mode", ht.NoDefault, ht.TElemOf(constants.EXPORT_MODES)),
1063 class OpExportInstance(OpCode):
1064 """Export an instance.
1066 For local exports, the export destination is the node name. For remote
1067 exports, the export destination is a list of tuples, each consisting of
1068 hostname/IP address, port, HMAC and HMAC salt. The HMAC is calculated using
1069 the cluster domain secret over the value "${index}:${hostname}:${port}". The
1070 destination X509 CA must be a signed certificate.
1072 @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
1073 @ivar target_node: Export destination
1074 @ivar x509_key_name: X509 key to use (remote export only)
1075 @ivar destination_x509_ca: Destination X509 CA in PEM format (remote export
1079 OP_ID = "OP_BACKUP_EXPORT"
1080 OP_DSC_FIELD = "instance_name"
1084 # TODO: Rename target_node as it changes meaning for different export modes
1085 # (e.g. "destination")
1086 ("target_node", ht.NoDefault, ht.TOr(ht.TNonEmptyString, ht.TList)),
1087 ("shutdown", True, ht.TBool),
1088 ("remove_instance", False, ht.TBool),
1089 ("ignore_remove_failures", False, ht.TBool),
1090 ("mode", constants.EXPORT_MODE_LOCAL, ht.TElemOf(constants.EXPORT_MODES)),
1091 ("x509_key_name", None, ht.TOr(ht.TList, ht.TNone)),
1092 ("destination_x509_ca", None, ht.TMaybeString),
1096 class OpRemoveExport(OpCode):
1097 """Remove an instance's export."""
1098 OP_ID = "OP_BACKUP_REMOVE"
1099 OP_DSC_FIELD = "instance_name"
1106 class OpGetTags(OpCode):
1107 """Returns the tags of the given object."""
1108 OP_ID = "OP_TAGS_GET"
1109 OP_DSC_FIELD = "name"
1112 # Name is only meaningful for nodes and instances
1113 ("name", ht.NoDefault, ht.TMaybeString),
1117 class OpSearchTags(OpCode):
1118 """Searches the tags in the cluster for a given pattern."""
1119 OP_ID = "OP_TAGS_SEARCH"
1120 OP_DSC_FIELD = "pattern"
1122 ("pattern", ht.NoDefault, ht.TNonEmptyString),
1126 class OpAddTags(OpCode):
1127 """Add a list of tags on a given object."""
1128 OP_ID = "OP_TAGS_SET"
1132 # Name is only meaningful for nodes and instances
1133 ("name", ht.NoDefault, ht.TMaybeString),
1137 class OpDelTags(OpCode):
1138 """Remove a list of tags from a given object."""
1139 OP_ID = "OP_TAGS_DEL"
1143 # Name is only meaningful for nodes and instances
1144 ("name", ht.NoDefault, ht.TMaybeString),
1148 class OpTestDelay(OpCode):
1149 """Sleeps for a configured amount of time.
1151 This is used just for debugging and testing.
1154 - duration: the time to sleep
1155 - on_master: if true, sleep on the master
1156 - on_nodes: list of nodes in which to sleep
1158 If the on_master parameter is true, it will execute a sleep on the
1159 master (before any node sleep).
1161 If the on_nodes list is not empty, it will sleep on those nodes
1162 (after the sleep on the master, if that is enabled).
1164 As an additional feature, the case of duration < 0 will be reported
1165 as an execution error, so this opcode can be used as a failure
1166 generator. The case of duration == 0 will not be treated specially.
1169 OP_ID = "OP_TEST_DELAY"
1170 OP_DSC_FIELD = "duration"
1172 ("duration", ht.NoDefault, ht.TFloat),
1173 ("on_master", True, ht.TBool),
1174 ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1175 ("repeat", 0, ht.TPositiveInt)
1179 class OpTestAllocator(OpCode):
1180 """Allocator framework testing.
1182 This opcode has two modes:
1183 - gather and return allocator input for a given mode (allocate new
1184 or replace secondary) and a given instance definition (direction
1186 - run a selected allocator for a given operation (as above) and
1187 return the allocator output (direction 'out')
1190 OP_ID = "OP_TEST_ALLOCATOR"
1191 OP_DSC_FIELD = "allocator"
1193 ("direction", ht.NoDefault,
1194 ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)),
1195 ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES)),
1196 ("name", ht.NoDefault, ht.TNonEmptyString),
1197 ("nics", ht.NoDefault, ht.TOr(ht.TNone, ht.TListOf(
1198 ht.TDictOf(ht.TElemOf(["mac", "ip", "bridge"]),
1199 ht.TOr(ht.TNone, ht.TNonEmptyString))))),
1200 ("disks", ht.NoDefault, ht.TOr(ht.TNone, ht.TList)),
1201 ("hypervisor", None, ht.TMaybeString),
1202 ("allocator", None, ht.TMaybeString),
1203 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString)),
1204 ("mem_size", None, ht.TOr(ht.TNone, ht.TPositiveInt)),
1205 ("vcpus", None, ht.TOr(ht.TNone, ht.TPositiveInt)),
1206 ("os", None, ht.TMaybeString),
1207 ("disk_template", None, ht.TMaybeString),
1208 ("evac_nodes", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString))),
1212 class OpTestJobqueue(OpCode):
1213 """Utility opcode to test some aspects of the job queue.
1216 OP_ID = "OP_TEST_JQUEUE"
1218 ("notify_waitlock", False, ht.TBool),
1219 ("notify_exec", False, ht.TBool),
1220 ("log_messages", ht.EmptyList, ht.TListOf(ht.TString)),
1221 ("fail", False, ht.TBool),
1225 class OpTestDummy(OpCode):
1226 """Utility opcode used by unittests.
1229 OP_ID = "OP_TEST_DUMMY"
1231 ("result", ht.NoDefault, ht.NoType),
1232 ("messages", ht.NoDefault, ht.NoType),
1233 ("fail", ht.NoDefault, ht.NoType),
1237 OP_MAPPING = dict([(v.OP_ID, v) for v in globals().values()
1238 if (isinstance(v, type) and issubclass(v, OpCode) and
1239 hasattr(v, "OP_ID"))])