Adam Litke has uploaded a new change for review. Change subject: api: Move DynamicBridge to vdsmapi schema processing ......................................................................
api: Move DynamicBridge to vdsmapi schema processing Signed-off-by: Adam Litke <a...@us.ibm.com> Change-Id: I0bbcc2475a40749c959eade157f6030b2c2f5e71 --- M tests/apiTests.py M vdsm/clientIF.py M vdsm_api/Bridge.py M vdsm_api/jsonrpc/__init__.py 4 files changed, 29 insertions(+), 59 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/12107/1 diff --git a/tests/apiTests.py b/tests/apiTests.py index 7ad8a1f..5275391 100644 --- a/tests/apiTests.py +++ b/tests/apiTests.py @@ -27,7 +27,6 @@ from contextlib import closing from testrunner import VdsmTestCase as TestCaseBase -from vdsm import constants import BindingJsonRpc import jsonrpc import apiData @@ -110,21 +109,6 @@ sys.modules['API'] = _newAPI -def findSchema(): - """ - Find the API schema file whether we are running tests from the source dir - or from the tests install location - """ - scriptdir = os.path.dirname(__file__) - localpath = os.path.join(scriptdir, '../vdsm_api/vdsmapi-schema.json') - installedpath = os.path.join(constants.P_VDSM, 'vdsmapi-schema.json') - for f in localpath, installedpath: - if os.access(f, os.R_OK): - return f - raise Exception("Unable to find schema in %s or %s", - localpath, installedpath) - - def setUpModule(): """ Set up the environment for all tests: @@ -140,12 +124,11 @@ handler.setLevel(logging.INFO) log.addHandler(handler) - schema = findSchema() createFakeAPI() # Bridge imports the API module so we must set up the fake API first import Bridge - bridge = Bridge.DynamicBridge(schema) + bridge = Bridge.DynamicBridge() # Support parallel testing. Try hard to find an open port to use port = getFreePort() diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py index 841e962..ef9a19b 100644 --- a/vdsm/clientIF.py +++ b/vdsm/clientIF.py @@ -153,11 +153,10 @@ def _loadBindingJsonRpc(self): from BindingJsonRpc import BindingJsonRpc from Bridge import DynamicBridge - schema = os.path.join(constants.P_VDSM, 'vdsmapi-schema.json') ip = self._getServerIP(config.get('addresses', 'management_ip')) port = config.getint('addresses', 'json_port') conf = [('tcp', {"ip": ip, "port": port})] - self.bindings['json'] = BindingJsonRpc(DynamicBridge(schema), conf) + self.bindings['json'] = BindingJsonRpc(DynamicBridge(), conf) def _prepareBindings(self): self.bindings = {} diff --git a/vdsm_api/Bridge.py b/vdsm_api/Bridge.py index 8fade0f..cc3f227 100644 --- a/vdsm_api/Bridge.py +++ b/vdsm_api/Bridge.py @@ -29,8 +29,8 @@ class DynamicBridge(object): - def __init__(self, schema): - self._parseSchema(schema) + def __init__(self): + self.api = vdsmapi.get_api() def dispatch(self, name, argobj): methodName = name.replace('.', '_') @@ -60,30 +60,13 @@ except KeyError: raise VdsmError(5, "Response is missing '%s' member" % member) - def _parseSchema(self, schema): - self.commands = {} - self.classes = {} - self.types = {} - with open(schema) as f: - symbols = vdsmapi.parse_schema(f) - for s in symbols: - if 'command' in s: - key = "%s_%s" % (s['command']['class'], - s['command']['name']) - self.commands[key] = s - elif 'class' in s: - cls = s['class'] - self.classes[cls] = s - elif 'type' in s: - t = s['type'] - self.types[t] = s - def __getattr__(self, attr): - if attr in self.commands: + try: className, methodName = attr.split('_') - return partial(self._dynamicMethod, className, methodName) - else: + self.api['commands'][className][methodName] + except (KeyError, ValueError): raise AttributeError("Attribute not found '%s'" % attr) + return partial(self._dynamicMethod, className, methodName) def _convertClassName(self, name): """ @@ -97,7 +80,7 @@ except KeyError: return name - def _getMethodArgs(self, className, cmd, argObj): + def _getMethodArgs(self, className, methodName, argObj): """ An internal API call currently looks like: @@ -109,10 +92,11 @@ them from here. For any given method, the method_args are obtained by chopping off the ctor_args from the beginning of argObj. """ - className = self._convertClassName(className) # Get the full argument list - allArgs = self.commands[cmd].get('data', {}).keys() + sym = self.api['commands'][className][methodName] + allArgs = sym.get('data', {}).keys() + className = self._convertClassName(className) # Get the list of ctor_args ctorArgs = getattr(API, className).ctorArgs @@ -149,7 +133,7 @@ symName = self._symNameFilter(symName) try: - symbol = self.types[symTypeName] + symbol = self.api['types'][symTypeName] except KeyError: return @@ -167,16 +151,17 @@ if k in item: self._typeFixup(k, v, item[k]) - def _fixupArgs(self, cmd, args): - argInfo = zip(self.commands[cmd].get('data', {}).items(), args) + def _fixupArgs(self, className, methodName, args): + argDef = self.api['commands'][className][methodName].get('data', {}) + argInfo = zip(argDef.items(), args) for typeInfo, val in argInfo: argName, argType = typeInfo - if argType not in self.types: + if argType not in self.api['types']: continue self._typeFixup(argName, argType, val) - def _fixupRet(self, cmd, result): - retType = self.commands[cmd].get('returns', None) + def _fixupRet(self, className, methodName, result): + retType = self.api['commands'][className][methodName].get('returns') if retType is not None: self._typeFixup('return', retType, result) return result @@ -189,17 +174,19 @@ return kwargs - def _getArgList(self, cmd): - return self.commands[cmd].get('data', {}).keys() + def _getArgList(self, className, methodName): + sym = self.api['commands'][className][methodName] + return sym.get('data', {}).keys() def _dynamicMethod(self, className, methodName, *args, **kwargs): - cmd = '%s_%s' % (className, methodName) - argobj = self._nameArgs(args, kwargs, self._getArgList(cmd)) + argobj = self._nameArgs(args, kwargs, + self._getArgList(className, methodName)) api = self._getApiInstance(className, argobj) - methodArgs = self._getMethodArgs(className, cmd, argobj) - self._fixupArgs(cmd, methodArgs) + methodArgs = self._getMethodArgs(className, methodName, argobj) + self._fixupArgs(className, methodName, methodArgs) # Call the override function (if given). Otherwise, just call directly + cmd = '%s_%s' % (className, methodName) fn = command_info.get(cmd, {}).get('call') if fn: result = fn(api, argobj) @@ -217,7 +204,7 @@ ret = retfield(result) else: ret = self._getResult(result, retfield) - return self._fixupRet(cmd, ret) + return self._fixupRet(className, methodName, ret) def Host_getStorageRepoStats_Ret(ret): diff --git a/vdsm_api/jsonrpc/__init__.py b/vdsm_api/jsonrpc/__init__.py index 49e8788..03cbf2e 100644 --- a/vdsm_api/jsonrpc/__init__.py +++ b/vdsm_api/jsonrpc/__init__.py @@ -226,6 +226,7 @@ except JsonRpcError as e: ctx.sendReply(None, e) except Exception as e: + self.log.error("Unexpected exception", exc_info=True) ctx.sendReply(None, JsonRpcInternalError(str(e))) else: return ctx.sendReply(res, None) -- To view, visit http://gerrit.ovirt.org/12107 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I0bbcc2475a40749c959eade157f6030b2c2f5e71 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Adam Litke <a...@us.ibm.com> _______________________________________________ vdsm-patches mailing list vdsm-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches