Revision ff0d18e6

b/lib/opcodes.py
34 34
# pylint: disable-msg=R0903
35 35

  
36 36
import logging
37
import re
37 38

  
38 39
from ganeti import constants
39 40
from ganeti import errors
......
77 78
#: List of tag strings
78 79
_PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
79 80

  
81
#: OP_ID conversion regular expression
82
_OPID_RE = re.compile("([a-z])([A-Z])")
83

  
84

  
85
def _NameToId(name):
86
  """Convert an opcode class name to an OP_ID.
87

  
88
  @type name: string
89
  @param name: the class name, as OpXxxYyy
90
  @rtype: string
91
  @return: the name in the OP_XXXX_YYYY format
92

  
93
  """
94
  if not name.startswith("Op"):
95
    return None
96
  # Note: (?<=[a-z])(?=[A-Z]) would be ideal, since it wouldn't
97
  # consume any input, and hence we would just have all the elements
98
  # in the list, one by one; but it seems that split doesn't work on
99
  # non-consuming input, hence we have to process the input string a
100
  # bit
101
  name = _OPID_RE.sub(r"\1,\2", name)
102
  elems = name.split(",")
103
  return "_".join(n.upper() for n in elems)
104

  
80 105

  
81 106
def RequireFileStorage():
82 107
  """Checks that file storage is enabled.
......
138 163
    """
139 164
    assert "__slots__" not in attrs, \
140 165
      "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
166

  
167
    op_id = _NameToId(name)
168
    if "OP_ID" in attrs:
169
      assert attrs["OP_ID"] == op_id, ("Class '%s' defining wrong OP_ID"
170
                                       " attribute %s, should be %s" %
171
                                       (name, attrs["OP_ID"], op_id))
172

  
173
    attrs["OP_ID"] = op_id
142 174

  
143 175
    # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams
144 176
    params = attrs.setdefault("OP_PARAMS", [])
......
296 328
  @ivar priority: Opcode priority for queue
297 329

  
298 330
  """
299
  OP_ID = "OP_ABSTRACT"
331
  OP_ID = "OP_CODE"
300 332
  WITH_LU = True
301 333
  OP_PARAMS = [
302 334
    ("dry_run", None, ht.TMaybeBool),
......
352 384
  def Summary(self):
353 385
    """Generates a summary description of this opcode.
354 386

  
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).
387
    The summary is the value of the OP_ID attribute (without the "OP_"
388
    prefix), plus the value of the OP_DSC_FIELD attribute, if one was
389
    defined; this field should allow to easily identify the operation
390
    (for an instance creation job, e.g., it would be the instance
391
    name).
359 392

  
360 393
    """
394
    assert self.OP_ID is not None and len(self.OP_ID) > 3
361 395
    # all OP_ID start with OP_, we remove that
362 396
    txt = self.OP_ID[3:]
363 397
    field_name = getattr(self, "OP_DSC_FIELD", None)
b/test/ganeti.cmdlib_unittest.py
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2008 Google Inc.
4
# Copyright (C) 2008, 2011 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
85 85
        self.cfg = mocks.FakeConfig()
86 86
        self.op = opcode
87 87

  
88
    class TestOpcode(opcodes.OpCode):
89
      OP_ID = "OP_TEST"
90
      OP_PARAMS = [
88
    class OpTest(opcodes.OpCode):
89
       OP_PARAMS = [
91 90
        ("iallocator", None, ht.NoType),
92 91
        ("node", None, ht.NoType),
93 92
        ]
......
95 94
    default_iallocator = mocks.FakeConfig().GetDefaultIAllocator()
96 95
    other_iallocator = default_iallocator + "_not"
97 96

  
98
    op = TestOpcode()
97
    op = OpTest()
99 98
    lu = TestLU(op)
100 99

  
101 100
    c_i = lambda: cmdlib._CheckIAllocatorOrNode(lu, "iallocator", "node")
b/test/ganeti.opcodes_unittest.py
45 45
      self.assert_(cls.OP_ID.startswith("OP_"))
46 46
      self.assert_(len(cls.OP_ID) > 3)
47 47
      self.assertEqual(cls.OP_ID, cls.OP_ID.upper())
48
      self.assertEqual(cls.OP_ID, opcodes._NameToId(cls.__name__))
48 49

  
49 50
      self.assertRaises(TypeError, cls, unsupported_parameter="some value")
50 51

  
......
88 89
      self.assertEqual("OP_%s" % summary, op.OP_ID)
89 90

  
90 91
  def testSummary(self):
91
    class _TestOp(opcodes.OpCode):
92
      OP_ID = "OP_TEST"
92
    class OpTest(opcodes.OpCode):
93 93
      OP_DSC_FIELD = "data"
94 94
      OP_PARAMS = [
95 95
        ("data", ht.NoDefault, ht.TString),
96 96
        ]
97 97

  
98
    self.assertEqual(_TestOp(data="").Summary(), "TEST()")
99
    self.assertEqual(_TestOp(data="Hello World").Summary(),
98
    self.assertEqual(OpTest(data="").Summary(), "TEST()")
99
    self.assertEqual(OpTest(data="Hello World").Summary(),
100 100
                     "TEST(Hello World)")
101
    self.assertEqual(_TestOp(data="node1.example.com").Summary(),
101
    self.assertEqual(OpTest(data="node1.example.com").Summary(),
102 102
                     "TEST(node1.example.com)")
103 103

  
104 104
  def testListSummary(self):
105
    class _TestOp(opcodes.OpCode):
106
      OP_ID = "OP_TEST"
105
    class OpTest(opcodes.OpCode):
107 106
      OP_DSC_FIELD = "data"
108 107
      OP_PARAMS = [
109 108
        ("data", ht.NoDefault, ht.TList),
110 109
        ]
111 110

  
112
    self.assertEqual(_TestOp(data=["a", "b", "c"]).Summary(),
111
    self.assertEqual(OpTest(data=["a", "b", "c"]).Summary(),
113 112
                     "TEST(a,b,c)")
114
    self.assertEqual(_TestOp(data=["a", None, "c"]).Summary(),
113
    self.assertEqual(OpTest(data=["a", None, "c"]).Summary(),
115 114
                     "TEST(a,None,c)")
116
    self.assertEqual(_TestOp(data=[1, 2, 3, 4]).Summary(), "TEST(1,2,3,4)")
115
    self.assertEqual(OpTest(data=[1, 2, 3, 4]).Summary(), "TEST(1,2,3,4)")
117 116

  
118 117
  def testOpId(self):
119 118
    self.assertFalse(utils.FindDuplicates(cls.OP_ID
......
162 161
                           msg="Default value returned by function is callable")
163 162

  
164 163
  def testValidateNoModification(self):
165
    class _TestOp(opcodes.OpCode):
166
      OP_ID = "OP_TEST"
164
    class OpTest(opcodes.OpCode):
167 165
      OP_PARAMS = [
168 166
        ("nodef", ht.NoDefault, ht.TMaybeString),
169 167
        ("wdef", "default", ht.TMaybeString),
......
172 170
        ]
173 171

  
174 172
    # Missing required parameter "nodef"
175
    op = _TestOp()
173
    op = OpTest()
176 174
    before = op.__getstate__()
177 175
    self.assertRaises(errors.OpPrereqError, op.Validate, False)
178 176
    self.assertFalse(hasattr(op, "nodef"))
......
182 180
    self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
183 181

  
184 182
    # Required parameter "nodef" is provided
185
    op = _TestOp(nodef="foo")
183
    op = OpTest(nodef="foo")
186 184
    before = op.__getstate__()
187 185
    op.Validate(False)
188 186
    self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
......
192 190
    self.assertFalse(hasattr(op, "notype"))
193 191

  
194 192
    # Missing required parameter "nodef"
195
    op = _TestOp(wdef="hello", number=999)
193
    op = OpTest(wdef="hello", number=999)
196 194
    before = op.__getstate__()
197 195
    self.assertRaises(errors.OpPrereqError, op.Validate, False)
198 196
    self.assertFalse(hasattr(op, "nodef"))
......
200 198
    self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
201 199

  
202 200
    # Wrong type for "nodef"
203
    op = _TestOp(nodef=987)
201
    op = OpTest(nodef=987)
204 202
    before = op.__getstate__()
205 203
    self.assertRaises(errors.OpPrereqError, op.Validate, False)
206 204
    self.assertEqual(op.nodef, 987)
......
208 206
    self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
209 207

  
210 208
    # Testing different types for "notype"
211
    op = _TestOp(nodef="foo", notype=[1, 2, 3])
209
    op = OpTest(nodef="foo", notype=[1, 2, 3])
212 210
    before = op.__getstate__()
213 211
    op.Validate(False)
214 212
    self.assertEqual(op.nodef, "foo")
215 213
    self.assertEqual(op.notype, [1, 2, 3])
216 214
    self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
217 215

  
218
    op = _TestOp(nodef="foo", notype="Hello World")
216
    op = OpTest(nodef="foo", notype="Hello World")
219 217
    before = op.__getstate__()
220 218
    op.Validate(False)
221 219
    self.assertEqual(op.nodef, "foo")
......
223 221
    self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
224 222

  
225 223
  def testValidateSetDefaults(self):
226
    class _TestOp(opcodes.OpCode):
227
      OP_ID = "OP_TEST"
224
    class OpTest(opcodes.OpCode):
228 225
      OP_PARAMS = [
229 226
        # Static default value
230 227
        ("value1", "default", ht.TMaybeString),
......
233 230
        ("value2", lambda: "result", ht.TMaybeString),
234 231
        ]
235 232

  
236
    op = _TestOp()
233
    op = OpTest()
237 234
    before = op.__getstate__()
238 235
    op.Validate(True)
239 236
    self.assertNotEqual(op.__getstate__(), before,
......
244 241
    self.assert_(op.debug_level is None)
245 242
    self.assertEqual(op.priority, constants.OP_PRIO_DEFAULT)
246 243

  
247
    op = _TestOp(value1="hello", value2="world", debug_level=123)
244
    op = OpTest(value1="hello", value2="world", debug_level=123)
248 245
    before = op.__getstate__()
249 246
    op.Validate(True)
250 247
    self.assertNotEqual(op.__getstate__(), before,
b/test/ganeti.rapi.baserlib_unittest.py
33 33

  
34 34

  
35 35
class TestFillOpcode(unittest.TestCase):
36
  class _TestOp(opcodes.OpCode):
37
    OP_ID = "RAPI_TEST_OP"
36
  class OpTest(opcodes.OpCode):
38 37
    OP_PARAMS = [
39 38
      ("test", None, ht.TMaybeString),
40 39
      ]
41 40

  
42 41
  def test(self):
43 42
    for static in [None, {}]:
44
      op = baserlib.FillOpcode(self._TestOp, {}, static)
45
      self.assertTrue(isinstance(op, self._TestOp))
43
      op = baserlib.FillOpcode(self.OpTest, {}, static)
44
      self.assertTrue(isinstance(op, self.OpTest))
46 45
      self.assertFalse(hasattr(op, "test"))
47 46

  
48 47
  def testStatic(self):
49
    op = baserlib.FillOpcode(self._TestOp, {}, {"test": "abc"})
50
    self.assertTrue(isinstance(op, self._TestOp))
48
    op = baserlib.FillOpcode(self.OpTest, {}, {"test": "abc"})
49
    self.assertTrue(isinstance(op, self.OpTest))
51 50
    self.assertEqual(op.test, "abc")
52 51

  
53 52
    # Overwrite static parameter
54 53
    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
55
                      self._TestOp, {"test": 123}, {"test": "abc"})
54
                      self.OpTest, {"test": 123}, {"test": "abc"})
56 55

  
57 56
  def testType(self):
58 57
    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
59
                      self._TestOp, {"test": [1, 2, 3]}, {})
58
                      self.OpTest, {"test": [1, 2, 3]}, {})
60 59

  
61 60
  def testStaticType(self):
62 61
    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
63
                      self._TestOp, {}, {"test": [1, 2, 3]})
62
                      self.OpTest, {}, {"test": [1, 2, 3]})
64 63

  
65 64
  def testUnicode(self):
66
    op = baserlib.FillOpcode(self._TestOp, {u"test": "abc"}, {})
67
    self.assertTrue(isinstance(op, self._TestOp))
65
    op = baserlib.FillOpcode(self.OpTest, {u"test": "abc"}, {})
66
    self.assertTrue(isinstance(op, self.OpTest))
68 67
    self.assertEqual(op.test, "abc")
69 68

  
70
    op = baserlib.FillOpcode(self._TestOp, {}, {u"test": "abc"})
71
    self.assertTrue(isinstance(op, self._TestOp))
69
    op = baserlib.FillOpcode(self.OpTest, {}, {u"test": "abc"})
70
    self.assertTrue(isinstance(op, self.OpTest))
72 71
    self.assertEqual(op.test, "abc")
73 72

  
74 73
  def testUnknownParameter(self):
75 74
    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
76
                      self._TestOp, {"othervalue": 123}, None)
75
                      self.OpTest, {"othervalue": 123}, None)
77 76

  
78 77
  def testInvalidBody(self):
79 78
    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
80
                      self._TestOp, "", None)
79
                      self.OpTest, "", None)
81 80
    self.assertRaises(http.HttpBadRequest, baserlib.FillOpcode,
82
                      self._TestOp, range(10), None)
81
                      self.OpTest, range(10), None)
83 82

  
84 83

  
85 84
if __name__ == "__main__":

Also available in: Unified diff