4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 Note that this file is autogenerated using @src/hs2py@ with a header
25 from @lib/opcodes.py.in_before@ and a footer from @lib/opcodes.py.in_after@.
27 This module implements part of the data structures which define the
28 cluster operations - the so-called opcodes.
30 Every operation which modifies the cluster state is expressed via
35 # this are practically structures, so disable the message about too
37 # pylint: disable=R0903
38 # pylint: disable=C0301
40 from ganeti import constants
43 from ganeti import opcodes_base
46 class OpCode(opcodes_base.BaseOpCode):
49 This is the root of the actual OpCode hierarchy. All clases derived
50 from this class should override OP_ID.
52 @cvar OP_ID: The ID of this opcode. This should be unique amongst all
53 children of this class.
54 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
55 string returned by Summary(); see the docstring of that
57 @cvar OP_DSC_FORMATTER: A callable that should format the OP_DSC_FIELD; if
58 not present, then the field will be simply converted
60 @cvar OP_PARAMS: List of opcode attributes, the default values they should
61 get if not already defined, and types they must match.
62 @cvar OP_RESULT: Callable to verify opcode result
63 @cvar WITH_LU: Boolean that specifies whether this should be included in
65 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
67 @ivar priority: Opcode priority for queue
70 # pylint: disable=E1101
71 # as OP_ID is dynamically defined
74 ("dry_run", None, ht.TMaybe(ht.TBool), "Run checks only, don't execute"),
75 ("debug_level", None, ht.TMaybe(ht.TNonNegative(ht.TInt)), "Debug level"),
76 ("priority", constants.OP_PRIO_DEFAULT,
77 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"),
78 (opcodes_base.DEPEND_ATTR, None, opcodes_base.BuildJobDepCheck(True),
79 "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)"
80 " job IDs can be used; see :doc:`design document <design-chained-jobs>`"
82 (opcodes_base.COMMENT_ATTR, None, ht.TMaybe(ht.TString),
83 "Comment describing the purpose of the opcode"),
84 (constants.OPCODE_REASON, None, ht.TMaybe(ht.TListOf(ht.TAny)),
85 "The reason trail, describing why the OpCode is executed"),
89 def __getstate__(self):
90 """Specialized getstate for opcodes.
92 This method adds to the state dictionary the OP_ID of the class,
93 so that on unload we can identify the correct class for
94 instantiating the opcode.
97 @return: the state as a dictionary
100 data = opcodes_base.BaseOpCode.__getstate__(self)
101 data["OP_ID"] = self.OP_ID
105 def LoadOpCode(cls, data):
106 """Generic load opcode method.
108 The method identifies the correct opcode class from the dict-form
109 by looking for a OP_ID key, if this is not found, or its value is
110 not available in this module as a child of this class, we fail.
113 @param data: the serialized opcode
116 if not isinstance(data, dict):
117 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
118 if "OP_ID" not in data:
119 raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
120 op_id = data["OP_ID"]
122 if op_id in OP_MAPPING:
123 op_class = OP_MAPPING[op_id]
125 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
128 new_data = data.copy()
129 del new_data["OP_ID"]
130 op.__setstate__(new_data)
134 """Generates a summary description of this opcode.
136 The summary is the value of the OP_ID attribute (without the "OP_"
137 prefix), plus the value of the OP_DSC_FIELD attribute, if one was
138 defined; this field should allow to easily identify the operation
139 (for an instance creation job, e.g., it would be the instance
143 assert self.OP_ID is not None and len(self.OP_ID) > 3
144 # all OP_ID start with OP_, we remove that
146 field_name = getattr(self, "OP_DSC_FIELD", None)
148 field_value = getattr(self, field_name, None)
149 field_formatter = getattr(self, "OP_DSC_FORMATTER", None)
150 if callable(field_formatter):
151 field_value = field_formatter(field_value)
152 elif isinstance(field_value, (list, tuple)):
153 field_value = ",".join(str(i) for i in field_value)
154 txt = "%s(%s)" % (txt, field_value)
157 def TinySummary(self):
158 """Generates a compact summary description of the opcode.
161 assert self.OP_ID.startswith("OP_")
163 text = self.OP_ID[3:]
165 for (prefix, supplement) in opcodes_base.SUMMARY_PREFIX.items():
166 if text.startswith(prefix):
167 return supplement + text[len(prefix):]
172 class OpInstanceMultiAllocBase(OpCode):
173 """Allocates multiple instances.
176 def __getstate__(self):
177 """Generic serializer.
180 state = OpCode.__getstate__(self)
181 if hasattr(self, "instances"):
182 # pylint: disable=E1101
183 state["instances"] = [inst.__getstate__() for inst in self.instances]
186 def __setstate__(self, state):
187 """Generic unserializer.
189 This method just restores from the serialized state the attributes
190 of the current instance.
192 @param state: the serialized opcode data
196 if not isinstance(state, dict):
197 raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
200 if "instances" in state:
201 state["instances"] = map(OpCode.LoadOpCode, state["instances"])
203 return OpCode.__setstate__(self, state)
205 def Validate(self, set_defaults):
206 """Validates this opcode.
208 We do this recursively.
211 OpCode.Validate(self, set_defaults)
213 for inst in self.instances: # pylint: disable=E1101
214 inst.Validate(set_defaults)