## root / lib / opcodes.py.in_before @ 84ad6b78

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 | 580b1fdd | Jose A. Lopes | (constants.OPCODE_REASON, None, 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) |