Commit 286c0df2 authored by Hrvoje Ribicic's avatar Hrvoje Ribicic
Browse files

Add support for value aliases to RAPI

This patch extends the metaclass used to generate RAPI handlers to
allow creating aliases of certain values returned by GET methods.
Signed-off-by: default avatarHrvoje Ribicic <>
Reviewed-by: default avatarThomas Thrainer <>
parent 33b9e4b2
......@@ -473,7 +473,7 @@ def _GetHandlerMethods(handler):
return sorted(method
for (method, op_attr, _, _) in rapi.baserlib.OPCODE_ATTRS
for (method, op_attr, _, _, _) in rapi.baserlib.OPCODE_ATTRS
# Only if handler supports method
if hasattr(handler, method) or hasattr(handler, op_attr))
......@@ -56,7 +56,7 @@ def _BuildOpcodeAttributes():
return [(method, "%s_OPCODE" % method, "%s_RENAME" % method,
"Get%sOpInput" % method.capitalize())
"%s_ALIASES" % method, "Get%sOpInput" % method.capitalize())
for method in _SUPPORTED_METHODS]
......@@ -406,7 +406,7 @@ def GetResourceOpcodes(cls):
return frozenset(filter(None, (getattr(cls, op_attr, None)
for (_, op_attr, _, _) in OPCODE_ATTRS)))
for (_, op_attr, _, _, _) in OPCODE_ATTRS)))
def GetHandlerAccess(handler, method):
......@@ -420,6 +420,22 @@ def GetHandlerAccess(handler, method):
return getattr(handler, "%s_ACCESS" % method, None)
def GetHandler(get_fn, aliases):
result = get_fn()
if not isinstance(result, dict) or aliases is None:
return result
for (param, alias) in aliases.items():
if param in result:
if alias in result:
raise http.HttpBadRequest("Parameter '%s' has an alias of '%s', but"
" both values are present in response" %
(param, alias))
result[alias] = result[param]
return result
class _MetaOpcodeResource(type):
"""Meta class for RAPI resources.
......@@ -431,13 +447,23 @@ class _MetaOpcodeResource(type):
# Access to private attributes of a client class, pylint: disable=W0212
obj = type.__call__(mcs, *args, **kwargs)
for (method, op_attr, rename_attr, fn_attr) in OPCODE_ATTRS:
for (method, op_attr, rename_attr, aliases_attr, fn_attr) in OPCODE_ATTRS:
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)
# 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)
# The aliases are allowed only on GET calls
assert not hasattr(obj, aliases_attr) or method == http.HTTP_GET
# GET methods can add aliases of values they return under a different
# name
if method == http.HTTP_GET and hasattr(obj, aliases_attr):
setattr(obj, method,
compat.partial(GetHandler, getattr(obj, method),
getattr(obj, aliases_attr)))
# Try to generate handler method on handler instance
......@@ -473,6 +499,8 @@ class OpcodeResource(ResourceBase):
automatically generate a GET handler submitting the opcode
@cvar GET_RENAME: Set this to rename parameters in the GET handler (see
@cvar GET_ALIASES: Set this to duplicate return values in GET results (see
@ivar GetGetOpInput: Define this to override the default method for
getting opcode parameters (see L{baserlib.OpcodeResource._GetDefaultData})
......@@ -107,7 +107,7 @@ class TestOpcodeResource(unittest.TestCase):
def _GetMethodAttributes(method):
attrs = ["%s_OPCODE" % method, "%s_RENAME" % method,
"Get%sOpInput" % method.capitalize()]
"%s_ALIASES" % method, "Get%sOpInput" % method.capitalize()]
assert attrs == dict((opattrs[0], list(opattrs[1:]))
for opattrs in baserlib.OPCODE_ATTRS)[method]
return attrs
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment