root / lib / opcodes.py.in_before @ 9808764a
History | View | Annotate | Download (6.9 kB)
1 | 580b1fdd | Jose A. Lopes | # |
---|---|---|---|
2 | 580b1fdd | Jose A. Lopes | # |
3 | 580b1fdd | Jose A. Lopes | |
4 | 580b1fdd | Jose A. Lopes | # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc. |
5 | 580b1fdd | Jose A. Lopes | # |
6 | 580b1fdd | Jose A. Lopes | # This program is free software; you can redistribute it and/or modify |
7 | 580b1fdd | Jose A. Lopes | # it under the terms of the GNU General Public License as published by |
8 | 580b1fdd | Jose A. Lopes | # the Free Software Foundation; either version 2 of the License, or |
9 | 580b1fdd | Jose A. Lopes | # (at your option) any later version. |
10 | 580b1fdd | Jose A. Lopes | # |
11 | 580b1fdd | Jose A. Lopes | # This program is distributed in the hope that it will be useful, but |
12 | 580b1fdd | Jose A. Lopes | # WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | 580b1fdd | Jose A. Lopes | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | 580b1fdd | Jose A. Lopes | # General Public License for more details. |
15 | 580b1fdd | Jose A. Lopes | # |
16 | 580b1fdd | Jose A. Lopes | # You should have received a copy of the GNU General Public License |
17 | 580b1fdd | Jose A. Lopes | # along with this program; if not, write to the Free Software |
18 | 580b1fdd | Jose A. Lopes | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
19 | 580b1fdd | Jose A. Lopes | # 02110-1301, USA. |
20 | 580b1fdd | Jose A. Lopes | |
21 | 580b1fdd | Jose A. Lopes | |
22 | 580b1fdd | Jose A. Lopes | """OpCodes module |
23 | 580b1fdd | Jose A. Lopes | |
24 | 580b1fdd | Jose A. Lopes | Note that this file is autogenerated using @src/hs2py@ with a header |
25 | 580b1fdd | Jose A. Lopes | from @lib/opcodes.py.in_before@ and a footer from @lib/opcodes.py.in_after@. |
26 | 580b1fdd | Jose A. Lopes | |
27 | 580b1fdd | Jose A. Lopes | This module implements part of the data structures which define the |
28 | 580b1fdd | Jose A. Lopes | cluster operations - the so-called opcodes. |
29 | 580b1fdd | Jose A. Lopes | |
30 | 580b1fdd | Jose A. Lopes | Every operation which modifies the cluster state is expressed via |
31 | 580b1fdd | Jose A. Lopes | opcodes. |
32 | 580b1fdd | Jose A. Lopes | |
33 | 580b1fdd | Jose A. Lopes | """ |
34 | 580b1fdd | Jose A. Lopes | |
35 | 580b1fdd | Jose A. Lopes | # this are practically structures, so disable the message about too |
36 | 580b1fdd | Jose A. Lopes | # few public methods: |
37 | 580b1fdd | Jose A. Lopes | # pylint: disable=R0903 |
38 | 580b1fdd | Jose A. Lopes | # pylint: disable=C0301 |
39 | 580b1fdd | Jose A. Lopes | |
40 | 580b1fdd | Jose A. Lopes | from ganeti import constants |
41 | 580b1fdd | Jose A. Lopes | from ganeti import ht |
42 | 580b1fdd | Jose A. Lopes | |
43 | 580b1fdd | Jose A. Lopes | from ganeti import opcodes_base |
44 | 580b1fdd | Jose A. Lopes | |
45 | 580b1fdd | Jose A. Lopes | |
46 | 580b1fdd | Jose A. Lopes | class OpCode(opcodes_base.BaseOpCode): |
47 | 580b1fdd | Jose A. Lopes | """Abstract OpCode. |
48 | 580b1fdd | Jose A. Lopes | |
49 | 580b1fdd | Jose A. Lopes | This is the root of the actual OpCode hierarchy. All clases derived |
50 | 580b1fdd | Jose A. Lopes | from this class should override OP_ID. |
51 | 580b1fdd | Jose A. Lopes | |
52 | 580b1fdd | Jose A. Lopes | @cvar OP_ID: The ID of this opcode. This should be unique amongst all |
53 | 580b1fdd | Jose A. Lopes | children of this class. |
54 | 580b1fdd | Jose A. Lopes | @cvar OP_DSC_FIELD: The name of a field whose value will be included in the |
55 | 580b1fdd | Jose A. Lopes | string returned by Summary(); see the docstring of that |
56 | 580b1fdd | Jose A. Lopes | method for details). |
57 | 580b1fdd | Jose A. Lopes | @cvar OP_DSC_FORMATTER: A callable that should format the OP_DSC_FIELD; if |
58 | 580b1fdd | Jose A. Lopes | not present, then the field will be simply converted |
59 | 580b1fdd | Jose A. Lopes | to string |
60 | 580b1fdd | Jose A. Lopes | @cvar OP_PARAMS: List of opcode attributes, the default values they should |
61 | 580b1fdd | Jose A. Lopes | get if not already defined, and types they must match. |
62 | 580b1fdd | Jose A. Lopes | @cvar OP_RESULT: Callable to verify opcode result |
63 | 580b1fdd | Jose A. Lopes | @cvar WITH_LU: Boolean that specifies whether this should be included in |
64 | 580b1fdd | Jose A. Lopes | mcpu's dispatch table |
65 | 580b1fdd | Jose A. Lopes | @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just |
66 | 580b1fdd | Jose A. Lopes | the check steps |
67 | 580b1fdd | Jose A. Lopes | @ivar priority: Opcode priority for queue |
68 | 580b1fdd | Jose A. Lopes | |
69 | 580b1fdd | Jose A. Lopes | """ |
70 | 580b1fdd | Jose A. Lopes | # pylint: disable=E1101 |
71 | 580b1fdd | Jose A. Lopes | # as OP_ID is dynamically defined |
72 | 580b1fdd | Jose A. Lopes | WITH_LU = True |
73 | 580b1fdd | Jose A. Lopes | OP_PARAMS = [ |
74 | 580b1fdd | Jose A. Lopes | ("dry_run", None, ht.TMaybe(ht.TBool), "Run checks only, don't execute"), |
75 | 580b1fdd | Jose A. Lopes | ("debug_level", None, ht.TMaybe(ht.TNonNegative(ht.TInt)), "Debug level"), |
76 | 580b1fdd | Jose A. Lopes | ("priority", constants.OP_PRIO_DEFAULT, |
77 | 580b1fdd | Jose A. Lopes | ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"), |
78 | 580b1fdd | Jose A. Lopes | (opcodes_base.DEPEND_ATTR, None, opcodes_base.BuildJobDepCheck(True), |
79 | 580b1fdd | Jose A. Lopes | "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)" |
80 | 580b1fdd | Jose A. Lopes | " job IDs can be used; see :doc:`design document <design-chained-jobs>`" |
81 | 580b1fdd | Jose A. Lopes | " for details"), |
82 | 580b1fdd | Jose A. Lopes | (opcodes_base.COMMENT_ATTR, None, ht.TMaybe(ht.TString), |
83 | 580b1fdd | Jose A. Lopes | "Comment describing the purpose of the opcode"), |
84 | 9749f90b | Thomas Thrainer | (constants.OPCODE_REASON, [], ht.TMaybe(ht.TListOf(ht.TAny)), |
85 | 580b1fdd | Jose A. Lopes | "The reason trail, describing why the OpCode is executed"), |
86 | 580b1fdd | Jose A. Lopes | ] |
87 | 580b1fdd | Jose A. Lopes | OP_RESULT = None |
88 | 580b1fdd | Jose A. Lopes | |
89 | 580b1fdd | Jose A. Lopes | def __getstate__(self): |
90 | 580b1fdd | Jose A. Lopes | """Specialized getstate for opcodes. |
91 | 580b1fdd | Jose A. Lopes | |
92 | 580b1fdd | Jose A. Lopes | This method adds to the state dictionary the OP_ID of the class, |
93 | 580b1fdd | Jose A. Lopes | so that on unload we can identify the correct class for |
94 | 580b1fdd | Jose A. Lopes | instantiating the opcode. |
95 | 580b1fdd | Jose A. Lopes | |
96 | 580b1fdd | Jose A. Lopes | @rtype: C{dict} |
97 | 580b1fdd | Jose A. Lopes | @return: the state as a dictionary |
98 | 580b1fdd | Jose A. Lopes | |
99 | 580b1fdd | Jose A. Lopes | """ |
100 | 580b1fdd | Jose A. Lopes | data = opcodes_base.BaseOpCode.__getstate__(self) |
101 | 580b1fdd | Jose A. Lopes | data["OP_ID"] = self.OP_ID |
102 | 580b1fdd | Jose A. Lopes | return data |
103 | 580b1fdd | Jose A. Lopes | |
104 | 580b1fdd | Jose A. Lopes | @classmethod |
105 | 580b1fdd | Jose A. Lopes | def LoadOpCode(cls, data): |
106 | 580b1fdd | Jose A. Lopes | """Generic load opcode method. |
107 | 580b1fdd | Jose A. Lopes | |
108 | 580b1fdd | Jose A. Lopes | The method identifies the correct opcode class from the dict-form |
109 | 580b1fdd | Jose A. Lopes | by looking for a OP_ID key, if this is not found, or its value is |
110 | 580b1fdd | Jose A. Lopes | not available in this module as a child of this class, we fail. |
111 | 580b1fdd | Jose A. Lopes | |
112 | 580b1fdd | Jose A. Lopes | @type data: C{dict} |
113 | 580b1fdd | Jose A. Lopes | @param data: the serialized opcode |
114 | 580b1fdd | Jose A. Lopes | |
115 | 580b1fdd | Jose A. Lopes | """ |
116 | 580b1fdd | Jose A. Lopes | if not isinstance(data, dict): |
117 | 580b1fdd | Jose A. Lopes | raise ValueError("Invalid data to LoadOpCode (%s)" % type(data)) |
118 | 580b1fdd | Jose A. Lopes | if "OP_ID" not in data: |
119 | 580b1fdd | Jose A. Lopes | raise ValueError("Invalid data to LoadOpcode, missing OP_ID") |
120 | 580b1fdd | Jose A. Lopes | op_id = data["OP_ID"] |
121 | 580b1fdd | Jose A. Lopes | op_class = None |
122 | 580b1fdd | Jose A. Lopes | if op_id in OP_MAPPING: |
123 | 580b1fdd | Jose A. Lopes | op_class = OP_MAPPING[op_id] |
124 | 580b1fdd | Jose A. Lopes | else: |
125 | 580b1fdd | Jose A. Lopes | raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" % |
126 | 580b1fdd | Jose A. Lopes | op_id) |
127 | 580b1fdd | Jose A. Lopes | op = op_class() |
128 | 580b1fdd | Jose A. Lopes | new_data = data.copy() |
129 | 580b1fdd | Jose A. Lopes | del new_data["OP_ID"] |
130 | 580b1fdd | Jose A. Lopes | op.__setstate__(new_data) |
131 | 580b1fdd | Jose A. Lopes | return op |
132 | 580b1fdd | Jose A. Lopes | |
133 | 580b1fdd | Jose A. Lopes | def Summary(self): |
134 | 580b1fdd | Jose A. Lopes | """Generates a summary description of this opcode. |
135 | 580b1fdd | Jose A. Lopes | |
136 | 580b1fdd | Jose A. Lopes | The summary is the value of the OP_ID attribute (without the "OP_" |
137 | 580b1fdd | Jose A. Lopes | prefix), plus the value of the OP_DSC_FIELD attribute, if one was |
138 | 580b1fdd | Jose A. Lopes | defined; this field should allow to easily identify the operation |
139 | 580b1fdd | Jose A. Lopes | (for an instance creation job, e.g., it would be the instance |
140 | 580b1fdd | Jose A. Lopes | name). |
141 | 580b1fdd | Jose A. Lopes | |
142 | 580b1fdd | Jose A. Lopes | """ |
143 | 580b1fdd | Jose A. Lopes | assert self.OP_ID is not None and len(self.OP_ID) > 3 |
144 | 580b1fdd | Jose A. Lopes | # all OP_ID start with OP_, we remove that |
145 | 580b1fdd | Jose A. Lopes | txt = self.OP_ID[3:] |
146 | 580b1fdd | Jose A. Lopes | field_name = getattr(self, "OP_DSC_FIELD", None) |
147 | 580b1fdd | Jose A. Lopes | if field_name: |
148 | 580b1fdd | Jose A. Lopes | field_value = getattr(self, field_name, None) |
149 | 580b1fdd | Jose A. Lopes | field_formatter = getattr(self, "OP_DSC_FORMATTER", None) |
150 | 580b1fdd | Jose A. Lopes | if callable(field_formatter): |
151 | 580b1fdd | Jose A. Lopes | field_value = field_formatter(field_value) |
152 | 580b1fdd | Jose A. Lopes | elif isinstance(field_value, (list, tuple)): |
153 | 580b1fdd | Jose A. Lopes | field_value = ",".join(str(i) for i in field_value) |
154 | 580b1fdd | Jose A. Lopes | txt = "%s(%s)" % (txt, field_value) |
155 | 580b1fdd | Jose A. Lopes | return txt |
156 | 580b1fdd | Jose A. Lopes | |
157 | 580b1fdd | Jose A. Lopes | def TinySummary(self): |
158 | 580b1fdd | Jose A. Lopes | """Generates a compact summary description of the opcode. |
159 | 580b1fdd | Jose A. Lopes | |
160 | 580b1fdd | Jose A. Lopes | """ |
161 | 580b1fdd | Jose A. Lopes | assert self.OP_ID.startswith("OP_") |
162 | 580b1fdd | Jose A. Lopes | |
163 | 580b1fdd | Jose A. Lopes | text = self.OP_ID[3:] |
164 | 580b1fdd | Jose A. Lopes | |
165 | 580b1fdd | Jose A. Lopes | for (prefix, supplement) in opcodes_base.SUMMARY_PREFIX.items(): |
166 | 580b1fdd | Jose A. Lopes | if text.startswith(prefix): |
167 | 580b1fdd | Jose A. Lopes | return supplement + text[len(prefix):] |
168 | 580b1fdd | Jose A. Lopes | |
169 | 580b1fdd | Jose A. Lopes | return text |
170 | 580b1fdd | Jose A. Lopes | |
171 | 580b1fdd | Jose A. Lopes | |
172 | 580b1fdd | Jose A. Lopes | class OpInstanceMultiAllocBase(OpCode): |
173 | 580b1fdd | Jose A. Lopes | """Allocates multiple instances. |
174 | 580b1fdd | Jose A. Lopes | |
175 | 580b1fdd | Jose A. Lopes | """ |
176 | 580b1fdd | Jose A. Lopes | def __getstate__(self): |
177 | 580b1fdd | Jose A. Lopes | """Generic serializer. |
178 | 580b1fdd | Jose A. Lopes | |
179 | 580b1fdd | Jose A. Lopes | """ |
180 | 580b1fdd | Jose A. Lopes | state = OpCode.__getstate__(self) |
181 | 580b1fdd | Jose A. Lopes | if hasattr(self, "instances"): |
182 | 580b1fdd | Jose A. Lopes | # pylint: disable=E1101 |
183 | 580b1fdd | Jose A. Lopes | state["instances"] = [inst.__getstate__() for inst in self.instances] |
184 | 580b1fdd | Jose A. Lopes | return state |
185 | 580b1fdd | Jose A. Lopes | |
186 | 580b1fdd | Jose A. Lopes | def __setstate__(self, state): |
187 | 580b1fdd | Jose A. Lopes | """Generic unserializer. |
188 | 580b1fdd | Jose A. Lopes | |
189 | 580b1fdd | Jose A. Lopes | This method just restores from the serialized state the attributes |
190 | 580b1fdd | Jose A. Lopes | of the current instance. |
191 | 580b1fdd | Jose A. Lopes | |
192 | 580b1fdd | Jose A. Lopes | @param state: the serialized opcode data |
193 | 580b1fdd | Jose A. Lopes | @type state: C{dict} |
194 | 580b1fdd | Jose A. Lopes | |
195 | 580b1fdd | Jose A. Lopes | """ |
196 | 580b1fdd | Jose A. Lopes | if not isinstance(state, dict): |
197 | 580b1fdd | Jose A. Lopes | raise ValueError("Invalid data to __setstate__: expected dict, got %s" % |
198 | 580b1fdd | Jose A. Lopes | type(state)) |
199 | 580b1fdd | Jose A. Lopes | |
200 | 580b1fdd | Jose A. Lopes | if "instances" in state: |
201 | 580b1fdd | Jose A. Lopes | state["instances"] = map(OpCode.LoadOpCode, state["instances"]) |
202 | 580b1fdd | Jose A. Lopes | |
203 | 580b1fdd | Jose A. Lopes | return OpCode.__setstate__(self, state) |
204 | 580b1fdd | Jose A. Lopes | |
205 | 580b1fdd | Jose A. Lopes | def Validate(self, set_defaults): |
206 | 580b1fdd | Jose A. Lopes | """Validates this opcode. |
207 | 580b1fdd | Jose A. Lopes | |
208 | 580b1fdd | Jose A. Lopes | We do this recursively. |
209 | 580b1fdd | Jose A. Lopes | |
210 | 580b1fdd | Jose A. Lopes | """ |
211 | 580b1fdd | Jose A. Lopes | OpCode.Validate(self, set_defaults) |
212 | 580b1fdd | Jose A. Lopes | |
213 | 580b1fdd | Jose A. Lopes | for inst in self.instances: # pylint: disable=E1101 |
214 | 580b1fdd | Jose A. Lopes | inst.Validate(set_defaults) |