obj = type.__call__(mcs, *args, **kwargs)
for (method, op_attr, rename_attr, fn_attr) in _OPCODE_ATTRS:
- try:
- opcode = getattr(obj, op_attr)
- except AttributeError:
- # If the "*_OPCODE" attribute isn't set, "*_RENAME" or "Get*OpInput"
- # shouldn't either
+ if hasattr(obj, method):
+ # If the method handler is already defined, "*_RENAME" or "Get*OpInput"
+ # shouldn't be (they're only used by the automatically generated
+ # handler)
assert not hasattr(obj, rename_attr)
assert not hasattr(obj, fn_attr)
- continue
-
- assert not hasattr(obj, method)
-
- # Generate handler method on handler instance
- setattr(obj, method,
- compat.partial(obj._GenericHandler, opcode,
- getattr(obj, rename_attr, None),
- getattr(obj, fn_attr, obj._GetDefaultData)))
+ else:
+ # Try to generate handler method on handler instance
+ try:
+ opcode = getattr(obj, op_attr)
+ except AttributeError:
+ pass
+ else:
+ setattr(obj, method,
+ compat.partial(obj._GenericHandler, opcode,
+ getattr(obj, rename_attr, None),
+ getattr(obj, fn_attr, obj._GetDefaultData)))
return obj
return constants.RAPI_VERSION
-class R_2_info(baserlib.ResourceBase):
+class R_2_info(baserlib.OpcodeResource):
"""/2/info resource.
"""
+ GET_OPCODE = opcodes.OpClusterQuery
+
def GET(self):
"""Returns cluster information.
return list(ALL_FEATURES)
-class R_2_os(baserlib.ResourceBase):
+class R_2_os(baserlib.OpcodeResource):
"""/2/os resource.
"""
+ GET_OPCODE = opcodes.OpOsDiagnose
+
def GET(self):
"""Return a list of all OSes.
}
-class R_2_nodes(baserlib.ResourceBase):
+class R_2_nodes(baserlib.OpcodeResource):
"""/2/nodes resource.
"""
+ GET_OPCODE = opcodes.OpNodeQuery
+
def GET(self):
"""Returns a list of all nodes.
uri_fields=("id", "uri"))
-class R_2_nodes_name(baserlib.ResourceBase):
+class R_2_nodes_name(baserlib.OpcodeResource):
"""/2/nodes/[node_name] resource.
"""
+ GET_OPCODE = opcodes.OpNodeQuery
+
def GET(self):
"""Send information about a node.
"""/2/groups resource.
"""
+ GET_OPCODE = opcodes.OpGroupQuery
POST_OPCODE = opcodes.OpGroupAdd
POST_RENAME = {
"name": "group_name",
"""/2/instances resource.
"""
+ GET_OPCODE = opcodes.OpInstanceQuery
POST_OPCODE = opcodes.OpInstanceCreate
POST_RENAME = {
"os": "os_type",
"""/2/instances/[instance_name] resource.
"""
+ GET_OPCODE = opcodes.OpInstanceQuery
DELETE_OPCODE = opcodes.OpInstanceRemove
def GET(self):
return ops
-class R_2_instances_name_reinstall(baserlib.ResourceBase):
+class R_2_instances_name_reinstall(baserlib.OpcodeResource):
"""/2/instances/[instance_name]/reinstall resource.
Implements an instance reinstall.
"""
+ POST_OPCODE = opcodes.OpInstanceReinstall
+
def POST(self):
"""Reinstall an instance.
"""
GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
+ GET_OPCODE = opcodes.OpInstanceConsole
def GET(self):
"""Request information for connecting to instance's console.
"""
# Results might contain sensitive information
GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
+ GET_OPCODE = opcodes.OpQuery
+ PUT_OPCODE = opcodes.OpQuery
def _Query(self, fields, filter_):
return self.GetClient().Query(self.items[0], fields, filter_).ToDict()
"""/2/query/[resource]/fields resource.
"""
+ GET_OPCODE = opcodes.OpQueryFields
+
def GET(self):
"""Retrieves list of available fields for a resource.
"""
TAG_LEVEL = None
+ GET_OPCODE = opcodes.OpTagsGet
PUT_OPCODE = opcodes.OpTagsSet
DELETE_OPCODE = opcodes.OpTagsDel
"""Script for testing ganeti.rapi.baserlib"""
import unittest
+import itertools
from ganeti import errors
from ganeti import opcodes
from ganeti import ht
from ganeti import http
+from ganeti import compat
from ganeti.rapi import baserlib
import testutils
class TestOpcodeResource(unittest.TestCase):
- def testDoubleDefinition(self):
- class _TClass(baserlib.OpcodeResource):
- GET_OPCODE = opcodes.OpTestDelay
- def GET(self): pass
-
- self.assertRaises(AssertionError, _TClass, None, None, None)
-
- def testNoOpCode(self):
- class _TClass(baserlib.OpcodeResource):
- POST_OPCODE = None
- def POST(self): pass
+ @staticmethod
+ def _MakeClass(method, attrs):
+ return type("Test%s" % method, (baserlib.OpcodeResource, ), attrs)
+
+ @staticmethod
+ def _GetMethodAttributes(method):
+ attrs = ["%s_OPCODE" % method, "%s_RENAME" % method,
+ "Get%sOpInput" % method.capitalize()]
+ assert attrs == dict((opattrs[0], list(opattrs[1:]))
+ for opattrs in baserlib._OPCODE_ATTRS)[method]
+ return attrs
- self.assertRaises(AssertionError, _TClass, None, None, None)
+ def test(self):
+ for method in baserlib._SUPPORTED_METHODS:
+ # Empty handler
+ obj = self._MakeClass(method, {})(None, None, None)
+ for attr in itertools.chain(*baserlib._OPCODE_ATTRS):
+ self.assertFalse(hasattr(obj, attr))
+
+ # Direct handler function
+ obj = self._MakeClass(method, {
+ method: lambda _: None,
+ })(None, None, None)
+ self.assertFalse(compat.all(hasattr(obj, attr)
+ for i in baserlib._SUPPORTED_METHODS
+ for attr in self._GetMethodAttributes(i)))
+
+ # Let metaclass define handler function
+ for opcls in [None, object()]:
+ obj = self._MakeClass(method, {
+ "%s_OPCODE" % method: opcls,
+ })(None, None, None)
+ self.assertTrue(callable(getattr(obj, method)))
+ self.assertEqual(getattr(obj, "%s_OPCODE" % method), opcls)
+ self.assertFalse(hasattr(obj, "%s_RENAME" % method))
+ self.assertFalse(compat.any(hasattr(obj, attr)
+ for i in baserlib._SUPPORTED_METHODS
+ if i != method
+ for attr in self._GetMethodAttributes(i)))
def testIllegalRename(self):
class _TClass(baserlib.OpcodeResource):
pass
obj = _Empty(None, None, None)
- for attr in ["GetPostOpInput", "GetPutOpInput", "GetGetOpInput",
- "GetDeleteOpInput"]:
+
+ for attr in itertools.chain(*baserlib._OPCODE_ATTRS):
self.assertFalse(hasattr(obj, attr))