From 87b63c1e9939a158fc8a654295f822d64ea35e1d Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Fri, 18 Mar 2016 14:47:51 -0400 Subject: Run through pep8 This is all whitespace changes flagged by pep8. --- obmc-rest | 1417 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 718 insertions(+), 699 deletions(-) diff --git a/obmc-rest b/obmc-rest index c6d2949..f2e268b 100644 --- a/obmc-rest +++ b/obmc-rest @@ -23,764 +23,783 @@ DELETE_IFACE = 'org.openbmc.Object.Delete' _4034_msg = "The specified %s cannot be %s: '%s'" + def valid_user(session, *a, **kw): - ''' Authorization plugin callback that checks that the user is logged in. ''' - if session is None: - abort(403, 'Login required') + ''' Authorization plugin callback that checks + that the user is logged in. ''' + if session is None: + abort(403, 'Login required') + class UserInGroup: - ''' Authorization plugin callback that checks that the user is logged in - and a member of a group. ''' - def __init__(self, group): - self.group = group + ''' Authorization plugin callback that checks that the user is logged in + and a member of a group. ''' + def __init__(self, group): + self.group = group + + def __call__(self, session, *a, **kw): + valid_user(session, *a, **kw) + res = False - def __call__(self, session, *a, **kw): - valid_user(session, *a, **kw) - res = False + try: + res = session['user'] in grp.getgrnam(self.group)[3] + except KeyError: + pass - try: - res = session['user'] in grp.getgrnam(self.group)[3] - except KeyError: - pass + if not res: + abort(403, 'Insufficient access') - if not res: - abort(403, 'Insufficient access') def find_case_insensitive(value, lst): - return next((x for x in lst if x.lower() == value.lower()), None) + return next((x for x in lst if x.lower() == value.lower()), None) + def makelist(data): - if isinstance(data, list): - return data - elif data: - return [data] - else: - return [] + if isinstance(data, list): + return data + elif data: + return [data] + else: + return [] + class RouteHandler(object): - _require_auth = makelist(valid_user) - def __init__(self, app, bus, verbs, rules): - self.app = app - self.bus = bus - self.mapper = Mapper(bus) - self._verbs = makelist(verbs) - self._rules = rules - - def _setup(self, **kw): - request.route_data = {} - if request.method in self._verbs: - return self.setup(**kw) - else: - self.find(**kw) - raise HTTPError(405, "Method not allowed.", - Allow=','.join(self._verbs)) - - def __call__(self, **kw): - return getattr(self, 'do_' + request.method.lower())(**kw) - - def install(self): - self.app.route(self._rules, callback = self, - method = ['GET', 'PUT', 'PATCH', 'POST', 'DELETE']) - - @staticmethod - def try_mapper_call(f, callback = None, **kw): - try: - return f(**kw) - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() != OpenBMCMapper.MAPPER_NOT_FOUND: - raise - if callback is None: - def callback(e, **kw): - abort(404, str(e)) - - callback(e, **kw) - - @staticmethod - def try_properties_interface(f, *a): - try: - return f(*a) - except dbus.exceptions.DBusException, e: - if DBUS_UNKNOWN_INTERFACE in e.get_dbus_message(): - # interface doesn't have any properties - return None - if DBUS_UNKNOWN_METHOD == e.get_dbus_name(): - # properties interface not implemented at all - return None - raise + _require_auth = makelist(valid_user) + + def __init__(self, app, bus, verbs, rules): + self.app = app + self.bus = bus + self.mapper = Mapper(bus) + self._verbs = makelist(verbs) + self._rules = rules + + def _setup(self, **kw): + request.route_data = {} + if request.method in self._verbs: + return self.setup(**kw) + else: + self.find(**kw) + raise HTTPError( + 405, "Method not allowed.", Allow=','.join(self._verbs)) + + def __call__(self, **kw): + return getattr(self, 'do_' + request.method.lower())(**kw) + + def install(self): + self.app.route( + self._rules, callback=self, + method=['GET', 'PUT', 'PATCH', 'POST', 'DELETE']) + + @staticmethod + def try_mapper_call(f, callback=None, **kw): + try: + return f(**kw) + except dbus.exceptions.DBusException, e: + if e.get_dbus_name() != OpenBMCMapper.MAPPER_NOT_FOUND: + raise + if callback is None: + def callback(e, **kw): + abort(404, str(e)) + + callback(e, **kw) + + @staticmethod + def try_properties_interface(f, *a): + try: + return f(*a) + except dbus.exceptions.DBusException, e: + if DBUS_UNKNOWN_INTERFACE in e.get_dbus_message(): + # interface doesn't have any properties + return None + if DBUS_UNKNOWN_METHOD == e.get_dbus_name(): + # properties interface not implemented at all + return None + raise + class DirectoryHandler(RouteHandler): - verbs = 'GET' - rules = '/' + verbs = 'GET' + rules = '/' + + def __init__(self, app, bus): + super(DirectoryHandler, self).__init__( + app, bus, self.verbs, self.rules) - def __init__(self, app, bus): - super(DirectoryHandler, self).__init__( - app, bus, self.verbs, self.rules) + def find(self, path='/'): + return self.try_mapper_call( + self.mapper.get_subtree_paths, path=path, depth=1) - def find(self, path = '/'): - return self.try_mapper_call( - self.mapper.get_subtree_paths, - path = path, depth = 1) + def setup(self, path='/'): + request.route_data['map'] = self.find(path) - def setup(self, path = '/'): - request.route_data['map'] = self.find(path) + def do_get(self, path='/'): + return request.route_data['map'] - def do_get(self, path = '/'): - return request.route_data['map'] class ListNamesHandler(RouteHandler): - verbs = 'GET' - rules = ['/list', '/list'] + verbs = 'GET' + rules = ['/list', '/list'] - def __init__(self, app, bus): - super(ListNamesHandler, self).__init__( - app, bus, self.verbs, self.rules) + def __init__(self, app, bus): + super(ListNamesHandler, self).__init__( + app, bus, self.verbs, self.rules) - def find(self, path = '/'): - return self.try_mapper_call( - self.mapper.get_subtree, path = path).keys() + def find(self, path='/'): + return self.try_mapper_call( + self.mapper.get_subtree, path=path).keys() - def setup(self, path = '/'): - request.route_data['map'] = self.find(path) + def setup(self, path='/'): + request.route_data['map'] = self.find(path) + + def do_get(self, path='/'): + return request.route_data['map'] - def do_get(self, path = '/'): - return request.route_data['map'] class ListHandler(RouteHandler): - verbs = 'GET' - rules = ['/enumerate', '/enumerate'] - - def __init__(self, app, bus): - super(ListHandler, self).__init__( - app, bus, self.verbs, self.rules) - - def find(self, path = '/'): - return self.try_mapper_call( - self.mapper.get_subtree, path = path) - - def setup(self, path = '/'): - request.route_data['map'] = self.find(path) - - def do_get(self, path = '/'): - objs = {} - mapper_data = request.route_data['map'] - tree = PathTree() - for x,y in mapper_data.iteritems(): - tree[x] = y - - try: - # Check to see if the root path implements - # enumerate in addition to any sub tree - # objects. - root = self.try_mapper_call(self.mapper.get_object, - path = path) - mapper_data[path] = root - except: - pass - - have_enumerate = [ (x[0], self.enumerate_capable(*x)) \ - for x in mapper_data.iteritems() \ - if self.enumerate_capable(*x) ] - - for x,y in have_enumerate: - objs.update(self.call_enumerate(x, y)) - tmp = tree[x] - # remove the subtree - del tree[x] - # add the new leaf back since enumerate results don't - # include the object enumerate is being invoked on - tree[x] = tmp - - # make dbus calls for any remaining objects - for x,y in tree.dataitems(): - objs[x] = self.app.instance_handler.do_get(x) - - return objs - - @staticmethod - def enumerate_capable(path, bus_data): - busses = [] - for name, ifaces in bus_data.iteritems(): - if OpenBMCMapper.ENUMERATE_IFACE in ifaces: - busses.append(name) - return busses - - def call_enumerate(self, path, busses): - objs = {} - for b in busses: - obj = self.bus.get_object(b, path, introspect = False) - iface = dbus.Interface(obj, OpenBMCMapper.ENUMERATE_IFACE) - objs.update(iface.enumerate()) - return objs + verbs = 'GET' + rules = ['/enumerate', '/enumerate'] + + def __init__(self, app, bus): + super(ListHandler, self).__init__( + app, bus, self.verbs, self.rules) + + def find(self, path='/'): + return self.try_mapper_call( + self.mapper.get_subtree, path=path) + + def setup(self, path='/'): + request.route_data['map'] = self.find(path) + + def do_get(self, path='/'): + objs = {} + mapper_data = request.route_data['map'] + tree = PathTree() + for x, y in mapper_data.iteritems(): + tree[x] = y + + try: + # Check to see if the root path implements + # enumerate in addition to any sub tree + # objects. + root = self.try_mapper_call( + self.mapper.get_object, path=path) + mapper_data[path] = root + except: + pass + + have_enumerate = [ + (x[0], self.enumerate_capable(*x)) + for x in mapper_data.iteritems() if self.enumerate_capable(*x)] + + for x, y in have_enumerate: + objs.update(self.call_enumerate(x, y)) + tmp = tree[x] + # remove the subtree + del tree[x] + # add the new leaf back since enumerate results don't + # include the object enumerate is being invoked on + tree[x] = tmp + + # make dbus calls for any remaining objects + for x, y in tree.dataitems(): + objs[x] = self.app.instance_handler.do_get(x) + + return objs + + @staticmethod + def enumerate_capable(path, bus_data): + busses = [] + for name, ifaces in bus_data.iteritems(): + if OpenBMCMapper.ENUMERATE_IFACE in ifaces: + busses.append(name) + return busses + + def call_enumerate(self, path, busses): + objs = {} + for b in busses: + obj = self.bus.get_object(b, path, introspect=False) + iface = dbus.Interface(obj, OpenBMCMapper.ENUMERATE_IFACE) + objs.update(iface.enumerate()) + return objs + class MethodHandler(RouteHandler): - verbs = 'POST' - rules = '/action/' - request_type = list - - def __init__(self, app, bus): - super(MethodHandler, self).__init__( - app, bus, self.verbs, self.rules) - - def find(self, path, method): - busses = self.try_mapper_call(self.mapper.get_object, - path = path) - for items in busses.iteritems(): - m = self.find_method_on_bus(path, method, *items) - if m: - return m - - abort(404, _4034_msg %('method', 'found', method)) - - def setup(self, path, method): - request.route_data['method'] = self.find(path, method) - - def do_post(self, path, method): - try: - if request.parameter_list: - return request.route_data['method'](*request.parameter_list) - else: - return request.route_data['method']() - - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() == DBUS_INVALID_ARGS: - abort(400, str(e)) - if e.get_dbus_name() == DBUS_TYPE_ERROR: - abort(400, str(e)) - raise - - @staticmethod - def find_method_in_interface(method, obj, interface, methods): - if methods is None: - return None - - method = find_case_insensitive(method, methods.keys()) - if method is not None: - iface = dbus.Interface(obj, interface) - return iface.get_dbus_method(method) - - def find_method_on_bus(self, path, method, bus, interfaces): - obj = self.bus.get_object(bus, path, introspect = False) - iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE) - data = iface.Introspect() - parser = IntrospectionNodeParser( - ElementTree.fromstring(data), - intf_match = ListMatch(interfaces)) - for x,y in parser.get_interfaces().iteritems(): - m = self.find_method_in_interface(method, obj, x, - y.get('method')) - if m: - return m + verbs = 'POST' + rules = '/action/' + request_type = list + + def __init__(self, app, bus): + super(MethodHandler, self).__init__( + app, bus, self.verbs, self.rules) + + def find(self, path, method): + busses = self.try_mapper_call( + self.mapper.get_object, path=path) + for items in busses.iteritems(): + m = self.find_method_on_bus(path, method, *items) + if m: + return m + + abort(404, _4034_msg % ('method', 'found', method)) + + def setup(self, path, method): + request.route_data['method'] = self.find(path, method) + + def do_post(self, path, method): + try: + if request.parameter_list: + return request.route_data['method'](*request.parameter_list) + else: + return request.route_data['method']() + + except dbus.exceptions.DBusException, e: + if e.get_dbus_name() == DBUS_INVALID_ARGS: + abort(400, str(e)) + if e.get_dbus_name() == DBUS_TYPE_ERROR: + abort(400, str(e)) + raise + + @staticmethod + def find_method_in_interface(method, obj, interface, methods): + if methods is None: + return None + + method = find_case_insensitive(method, methods.keys()) + if method is not None: + iface = dbus.Interface(obj, interface) + return iface.get_dbus_method(method) + + def find_method_on_bus(self, path, method, bus, interfaces): + obj = self.bus.get_object(bus, path, introspect=False) + iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE) + data = iface.Introspect() + parser = IntrospectionNodeParser( + ElementTree.fromstring(data), + intf_match=ListMatch(interfaces)) + for x, y in parser.get_interfaces().iteritems(): + m = self.find_method_in_interface( + method, obj, x, y.get('method')) + if m: + return m + class PropertyHandler(RouteHandler): - verbs = ['PUT', 'GET'] - rules = '/attr/' - - def __init__(self, app, bus): - super(PropertyHandler, self).__init__( - app, bus, self.verbs, self.rules) - - def find(self, path, prop): - self.app.instance_handler.setup(path) - obj = self.app.instance_handler.do_get(path) - try: - obj[prop] - except KeyError, e: - if request.method == 'PUT': - abort(403, _4034_msg %('property', 'created', str(e))) - else: - abort(404, _4034_msg %('property', 'found', str(e))) - - return { path: obj } - - def setup(self, path, prop): - request.route_data['obj'] = self.find(path, prop) - - def do_get(self, path, prop): - return request.route_data['obj'][path][prop] - - def do_put(self, path, prop, value = None): - if value is None: - value = request.parameter_list - - prop, iface, properties_iface = self.get_host_interface( - path, prop, request.route_data['map'][path]) - try: - properties_iface.Set(iface, prop, value) - except ValueError, e: - abort(400, str(e)) - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() == DBUS_INVALID_ARGS: - abort(403, str(e)) - raise - - def get_host_interface(self, path, prop, bus_info): - for bus, interfaces in bus_info.iteritems(): - obj = self.bus.get_object(bus, path, introspect = True) - properties_iface = dbus.Interface( - obj, dbus_interface=dbus.PROPERTIES_IFACE) - - info = self.get_host_interface_on_bus( - path, prop, properties_iface, - bus, interfaces) - if info is not None: - prop, iface = info - return prop, iface, properties_iface - - def get_host_interface_on_bus(self, path, prop, iface, bus, interfaces): - for i in interfaces: - properties = self.try_properties_interface(iface.GetAll, i) - if properties is None: - continue - prop = find_case_insensitive(prop, properties.keys()) - if prop is None: - continue - return prop, i + verbs = ['PUT', 'GET'] + rules = '/attr/' + + def __init__(self, app, bus): + super(PropertyHandler, self).__init__( + app, bus, self.verbs, self.rules) + + def find(self, path, prop): + self.app.instance_handler.setup(path) + obj = self.app.instance_handler.do_get(path) + try: + obj[prop] + except KeyError, e: + if request.method == 'PUT': + abort(403, _4034_msg % ('property', 'created', str(e))) + else: + abort(404, _4034_msg % ('property', 'found', str(e))) + + return {path: obj} + + def setup(self, path, prop): + request.route_data['obj'] = self.find(path, prop) + + def do_get(self, path, prop): + return request.route_data['obj'][path][prop] + + def do_put(self, path, prop, value=None): + if value is None: + value = request.parameter_list + + prop, iface, properties_iface = self.get_host_interface( + path, prop, request.route_data['map'][path]) + try: + properties_iface.Set(iface, prop, value) + except ValueError, e: + abort(400, str(e)) + except dbus.exceptions.DBusException, e: + if e.get_dbus_name() == DBUS_INVALID_ARGS: + abort(403, str(e)) + raise + + def get_host_interface(self, path, prop, bus_info): + for bus, interfaces in bus_info.iteritems(): + obj = self.bus.get_object(bus, path, introspect=True) + properties_iface = dbus.Interface( + obj, dbus_interface=dbus.PROPERTIES_IFACE) + + info = self.get_host_interface_on_bus( + path, prop, properties_iface, bus, interfaces) + if info is not None: + prop, iface = info + return prop, iface, properties_iface + + def get_host_interface_on_bus(self, path, prop, iface, bus, interfaces): + for i in interfaces: + properties = self.try_properties_interface(iface.GetAll, i) + if properties is None: + continue + prop = find_case_insensitive(prop, properties.keys()) + if prop is None: + continue + return prop, i + class SchemaHandler(RouteHandler): - verbs = ['GET'] - rules = '/schema' - - def __init__(self, app, bus): - super(SchemaHandler, self).__init__( - app, bus, self.verbs, self.rules) - - def find(self, path): - return self.try_mapper_call( - self.mapper.get_object, - path = path) - - def setup(self, path): - request.route_data['map'] = self.find(path) - - def do_get(self, path): - schema = {} - for x in request.route_data['map'].iterkeys(): - obj = self.bus.get_object( - x, path, introspect = False) - iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE) - data = iface.Introspect() - parser = IntrospectionNodeParser( - ElementTree.fromstring(data)) - for x,y in parser.get_interfaces().iteritems(): - schema[x] = y - - return schema + verbs = ['GET'] + rules = '/schema' + + def __init__(self, app, bus): + super(SchemaHandler, self).__init__( + app, bus, self.verbs, self.rules) + + def find(self, path): + return self.try_mapper_call( + self.mapper.get_object, + path=path) + + def setup(self, path): + request.route_data['map'] = self.find(path) + + def do_get(self, path): + schema = {} + for x in request.route_data['map'].iterkeys(): + obj = self.bus.get_object(x, path, introspect=False) + iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE) + data = iface.Introspect() + parser = IntrospectionNodeParser( + ElementTree.fromstring(data)) + for x, y in parser.get_interfaces().iteritems(): + schema[x] = y + + return schema + class InstanceHandler(RouteHandler): - verbs = ['GET', 'PUT', 'DELETE'] - rules = '' - request_type = dict - - def __init__(self, app, bus): - super(InstanceHandler, self).__init__( - app, bus, self.verbs, self.rules) - - def find(self, path, callback = None): - return { path: self.try_mapper_call( - self.mapper.get_object, - callback, - path = path) } - - def setup(self, path): - callback = None - if request.method == 'PUT': - def callback(e, **kw): - abort(403, _4034_msg %('resource', - 'created', path)) - - if request.route_data.get('map') is None: - request.route_data['map'] = self.find(path, callback) - - def do_get(self, path): - properties = {} - for item in request.route_data['map'][path].iteritems(): - properties.update(self.get_properties_on_bus( - path, *item)) - - return properties - - @staticmethod - def get_properties_on_iface(properties_iface, iface): - properties = InstanceHandler.try_properties_interface( - properties_iface.GetAll, iface) - if properties is None: - return {} - return properties - - def get_properties_on_bus(self, path, bus, interfaces): - properties = {} - obj = self.bus.get_object(bus, path, introspect = False) - properties_iface = dbus.Interface( - obj, dbus_interface=dbus.PROPERTIES_IFACE) - for i in interfaces: - properties.update(self.get_properties_on_iface( - properties_iface, i)) - - return properties - - def do_put(self, path): - # make sure all properties exist in the request - obj = set(self.do_get(path).keys()) - req = set(request.parameter_list.keys()) - - diff = list(obj.difference(req)) - if diff: - abort(403, _4034_msg %('resource', 'removed', - '%s/attr/%s' %(path, diff[0]))) - - diff = list(req.difference(obj)) - if diff: - abort(403, _4034_msg %('resource', 'created', - '%s/attr/%s' %(path, diff[0]))) - - for p,v in request.parameter_list.iteritems(): - self.app.property_handler.do_put( - path, p, v) - - def do_delete(self, path): - for bus_info in request.route_data['map'][path].iteritems(): - if self.bus_missing_delete(path, *bus_info): - abort(403, _4034_msg %('resource', 'removed', - path)) - - for bus in request.route_data['map'][path].iterkeys(): - self.delete_on_bus(path, bus) - - def bus_missing_delete(self, path, bus, interfaces): - return DELETE_IFACE not in interfaces - - def delete_on_bus(self, path, bus): - obj = self.bus.get_object(bus, path, introspect = False) - delete_iface = dbus.Interface( - obj, dbus_interface = DELETE_IFACE) - delete_iface.Delete() + verbs = ['GET', 'PUT', 'DELETE'] + rules = '' + request_type = dict + + def __init__(self, app, bus): + super(InstanceHandler, self).__init__( + app, bus, self.verbs, self.rules) + + def find(self, path, callback=None): + return {path: self.try_mapper_call( + self.mapper.get_object, + callback, + path=path)} + + def setup(self, path): + callback = None + if request.method == 'PUT': + def callback(e, **kw): + abort(403, _4034_msg % ('resource', 'created', path)) + + if request.route_data.get('map') is None: + request.route_data['map'] = self.find(path, callback) + + def do_get(self, path): + properties = {} + for item in request.route_data['map'][path].iteritems(): + properties.update(self.get_properties_on_bus( + path, *item)) + + return properties + + @staticmethod + def get_properties_on_iface(properties_iface, iface): + properties = InstanceHandler.try_properties_interface( + properties_iface.GetAll, iface) + if properties is None: + return {} + return properties + + def get_properties_on_bus(self, path, bus, interfaces): + properties = {} + obj = self.bus.get_object(bus, path, introspect=False) + properties_iface = dbus.Interface( + obj, dbus_interface=dbus.PROPERTIES_IFACE) + for i in interfaces: + properties.update(self.get_properties_on_iface( + properties_iface, i)) + + return properties + + def do_put(self, path): + # make sure all properties exist in the request + obj = set(self.do_get(path).keys()) + req = set(request.parameter_list.keys()) + + diff = list(obj.difference(req)) + if diff: + abort(403, _4034_msg % ( + 'resource', 'removed', '%s/attr/%s' % (path, diff[0]))) + + diff = list(req.difference(obj)) + if diff: + abort(403, _4034_msg % ( + 'resource', 'created', '%s/attr/%s' % (path, diff[0]))) + + for p, v in request.parameter_list.iteritems(): + self.app.property_handler.do_put( + path, p, v) + + def do_delete(self, path): + for bus_info in request.route_data['map'][path].iteritems(): + if self.bus_missing_delete(path, *bus_info): + abort(403, _4034_msg % ('resource', 'removed', path)) + + for bus in request.route_data['map'][path].iterkeys(): + self.delete_on_bus(path, bus) + + def bus_missing_delete(self, path, bus, interfaces): + return DELETE_IFACE not in interfaces + + def delete_on_bus(self, path, bus): + obj = self.bus.get_object(bus, path, introspect=False) + delete_iface = dbus.Interface( + obj, dbus_interface=DELETE_IFACE) + delete_iface.Delete() + class SessionHandler(MethodHandler): - ''' Handles the /login and /logout routes, manages server side session store and - session cookies. ''' - - rules = ['/login', '/logout'] - login_str = "User '%s' logged %s" - bad_passwd_str = "Invalid username or password" - no_user_str = "No user logged in" - bad_json_str = "Expecting request format { 'data': [, ] }, got '%s'" - _require_auth = None - MAX_SESSIONS = 16 - - def __init__(self, app, bus): - super(SessionHandler, self).__init__( - app, bus) - self.hmac_key = os.urandom(128) - self.session_store = [] - - @staticmethod - def authenticate(username, clear): - try: - encoded = spwd.getspnam(username)[1] - return encoded == crypt.crypt(clear, encoded) - except KeyError: - return False - - def invalidate_session(self, session): - try: - self.session_store.remove(session) - except ValueError: - pass - - def new_session(self): - sid = os.urandom(32) - if self.MAX_SESSIONS <= len(self.session_store): - self.session_store.pop() - self.session_store.insert(0, {'sid': sid}) - - return self.session_store[0] - - def get_session(self, sid): - sids = [ x['sid'] for x in self.session_store ] - try: - return self.session_store[sids.index(sid)] - except ValueError: - return None - - def get_session_from_cookie(self): - return self.get_session( - request.get_cookie('sid', - secret = self.hmac_key)) - - def do_post(self, **kw): - if request.path == '/login': - return self.do_login(**kw) - else: - return self.do_logout(**kw) - - def do_logout(self, **kw): - session = self.get_session_from_cookie() - if session is not None: - user = session['user'] - self.invalidate_session(session) - response.delete_cookie('sid') - return self.login_str %(user, 'out') - - return self.no_user_str - - def do_login(self, **kw): - session = self.get_session_from_cookie() - if session is not None: - return self.login_str %(session['user'], 'in') - - if len(request.parameter_list) != 2: - abort(400, self.bad_json_str %(request.json)) - - if not self.authenticate(*request.parameter_list): - return self.bad_passwd_str - - user = request.parameter_list[0] - session = self.new_session() - session['user'] = user - response.set_cookie('sid', session['sid'], secret = self.hmac_key, - secure = True, - httponly = True) - return self.login_str %(user, 'in') - - def find(self, **kw): - pass - - def setup(self, **kw): - pass + ''' Handles the /login and /logout routes, manages + server side session store and session cookies. ''' + + rules = ['/login', '/logout'] + login_str = "User '%s' logged %s" + bad_passwd_str = "Invalid username or password" + no_user_str = "No user logged in" + bad_json_str = "Expecting request format { 'data': " \ + "[, ] }, got '%s'" + _require_auth = None + MAX_SESSIONS = 16 + + def __init__(self, app, bus): + super(SessionHandler, self).__init__( + app, bus) + self.hmac_key = os.urandom(128) + self.session_store = [] + + @staticmethod + def authenticate(username, clear): + try: + encoded = spwd.getspnam(username)[1] + return encoded == crypt.crypt(clear, encoded) + except KeyError: + return False + + def invalidate_session(self, session): + try: + self.session_store.remove(session) + except ValueError: + pass + + def new_session(self): + sid = os.urandom(32) + if self.MAX_SESSIONS <= len(self.session_store): + self.session_store.pop() + self.session_store.insert(0, {'sid': sid}) + + return self.session_store[0] + + def get_session(self, sid): + sids = [x['sid'] for x in self.session_store] + try: + return self.session_store[sids.index(sid)] + except ValueError: + return None + + def get_session_from_cookie(self): + return self.get_session( + request.get_cookie( + 'sid', secret=self.hmac_key)) + + def do_post(self, **kw): + if request.path == '/login': + return self.do_login(**kw) + else: + return self.do_logout(**kw) + + def do_logout(self, **kw): + session = self.get_session_from_cookie() + if session is not None: + user = session['user'] + self.invalidate_session(session) + response.delete_cookie('sid') + return self.login_str % (user, 'out') + + return self.no_user_str + + def do_login(self, **kw): + session = self.get_session_from_cookie() + if session is not None: + return self.login_str % (session['user'], 'in') + + if len(request.parameter_list) != 2: + abort(400, self.bad_json_str % (request.json)) + + if not self.authenticate(*request.parameter_list): + return self.bad_passwd_str + + user = request.parameter_list[0] + session = self.new_session() + session['user'] = user + response.set_cookie( + 'sid', session['sid'], secret=self.hmac_key, + secure=True, + httponly=True) + return self.login_str % (user, 'in') + + def find(self, **kw): + pass + + def setup(self, **kw): + pass + class AuthorizationPlugin(object): - ''' Invokes an optional list of authorization callbacks. ''' + ''' Invokes an optional list of authorization callbacks. ''' - name = 'authorization' - api = 2 + name = 'authorization' + api = 2 - class Compose: - def __init__(self, validators, callback, session_mgr): - self.validators = validators - self.callback = callback - self.session_mgr = session_mgr + class Compose: + def __init__(self, validators, callback, session_mgr): + self.validators = validators + self.callback = callback + self.session_mgr = session_mgr - def __call__(self, *a, **kw): - sid = request.get_cookie('sid', secret = self.session_mgr.hmac_key) - session = self.session_mgr.get_session(sid) - for x in self.validators: - x(session, *a, **kw) + def __call__(self, *a, **kw): + sid = request.get_cookie('sid', secret=self.session_mgr.hmac_key) + session = self.session_mgr.get_session(sid) + for x in self.validators: + x(session, *a, **kw) - return self.callback(*a, **kw) + return self.callback(*a, **kw) - def apply(self, callback, route): - undecorated = route.get_undecorated_callback() - if not isinstance(undecorated, RouteHandler): - return callback + def apply(self, callback, route): + undecorated = route.get_undecorated_callback() + if not isinstance(undecorated, RouteHandler): + return callback - auth_types = getattr(undecorated, - '_require_auth', None) - if not auth_types: - return callback + auth_types = getattr( + undecorated, '_require_auth', None) + if not auth_types: + return callback + + return self.Compose( + auth_types, callback, undecorated.app.session_handler) - return self.Compose(auth_types, callback, - undecorated.app.session_handler) class JsonApiRequestPlugin(object): - ''' Ensures request content satisfies the OpenBMC json api format. ''' - name = 'json_api_request' - api = 2 - - error_str = "Expecting request format { 'data': }, got '%s'" - type_error_str = "Unsupported Content-Type: '%s'" - json_type = "application/json" - request_methods = ['PUT', 'POST', 'PATCH'] - - @staticmethod - def content_expected(): - return request.method in JsonApiRequestPlugin.request_methods - - def validate_request(self): - if request.content_length > 0 and \ - request.content_type != self.json_type: - abort(415, self.type_error_str %(request.content_type)) - - try: - request.parameter_list = request.json.get('data') - except ValueError, e: - abort(400, str(e)) - except (AttributeError, KeyError, TypeError): - abort(400, self.error_str %(request.json)) - - def apply(self, callback, route): - verbs = getattr(route.get_undecorated_callback(), - '_verbs', None) - if verbs is None: - return callback - - if not set(self.request_methods).intersection(verbs): - return callback - - def wrap(*a, **kw): - if self.content_expected(): - self.validate_request() - return callback(*a, **kw) - - return wrap + ''' Ensures request content satisfies the OpenBMC json api format. ''' + name = 'json_api_request' + api = 2 + + error_str = "Expecting request format { 'data': }, got '%s'" + type_error_str = "Unsupported Content-Type: '%s'" + json_type = "application/json" + request_methods = ['PUT', 'POST', 'PATCH'] + + @staticmethod + def content_expected(): + return request.method in JsonApiRequestPlugin.request_methods + + def validate_request(self): + if request.content_length > 0 and \ + request.content_type != self.json_type: + abort(415, self.type_error_str % request.content_type) + + try: + request.parameter_list = request.json.get('data') + except ValueError, e: + abort(400, str(e)) + except (AttributeError, KeyError, TypeError): + abort(400, self.error_str % request.json) + + def apply(self, callback, route): + verbs = getattr( + route.get_undecorated_callback(), '_verbs', None) + if verbs is None: + return callback + + if not set(self.request_methods).intersection(verbs): + return callback + + def wrap(*a, **kw): + if self.content_expected(): + self.validate_request() + return callback(*a, **kw) + + return wrap + class JsonApiRequestTypePlugin(object): - ''' Ensures request content type satisfies the OpenBMC json api format. ''' - name = 'json_api_method_request' - api = 2 + ''' Ensures request content type satisfies the OpenBMC json api format. ''' + name = 'json_api_method_request' + api = 2 - error_str = "Expecting request format { 'data': %s }, got '%s'" + error_str = "Expecting request format { 'data': %s }, got '%s'" - def apply(self, callback, route): - request_type = getattr(route.get_undecorated_callback(), - 'request_type', None) - if request_type is None: - return callback + def apply(self, callback, route): + request_type = getattr( + route.get_undecorated_callback(), 'request_type', None) + if request_type is None: + return callback - def validate_request(): - if not isinstance(request.parameter_list, request_type): - abort(400, self.error_str %(str(request_type), request.json)) + def validate_request(): + if not isinstance(request.parameter_list, request_type): + abort(400, self.error_str % (str(request_type), request.json)) - def wrap(*a, **kw): - if JsonApiRequestPlugin.content_expected(): - validate_request() - return callback(*a, **kw) + def wrap(*a, **kw): + if JsonApiRequestPlugin.content_expected(): + validate_request() + return callback(*a, **kw) + + return wrap - return wrap class JsonApiResponsePlugin(object): - ''' Emits normal responses in the OpenBMC json api format. ''' - name = 'json_api_response' - api = 2 - - def apply(self, callback, route): - def wrap(*a, **kw): - resp = { 'data': callback(*a, **kw) } - resp['status'] = 'ok' - resp['message'] = response.status_line - return resp - return wrap + ''' Emits normal responses in the OpenBMC json api format. ''' + name = 'json_api_response' + api = 2 + + def apply(self, callback, route): + def wrap(*a, **kw): + resp = {'data': callback(*a, **kw)} + resp['status'] = 'ok' + resp['message'] = response.status_line + return resp + return wrap + class JsonApiErrorsPlugin(object): - ''' Emits error responses in the OpenBMC json api format. ''' - name = 'json_api_errors' - api = 2 - - def __init__(self, **kw): - self.app = None - self.function_type = None - self.original = None - self.json_opts = { x:y for x,y in kw.iteritems() \ - if x in ['indent','sort_keys'] } - - def setup(self, app): - self.app = app - self.function_type = type(app.default_error_handler) - self.original = app.default_error_handler - self.app.default_error_handler = self.function_type( - self.json_errors, app, Bottle) - - def apply(self, callback, route): - return callback - - def close(self): - self.app.default_error_handler = self.function_type( - self.original, self.app, Bottle) - - def json_errors(self, res, error): - response_object = {'status': 'error', 'data': {} } - response_object['message'] = error.status_line - response_object['data']['description'] = str(error.body) - if error.status_code == 500: - response_object['data']['exception'] = repr(error.exception) - response_object['data']['traceback'] = error.traceback.splitlines() - - json_response = json.dumps(response_object, **self.json_opts) - response.content_type = 'application/json' - return json_response + ''' Emits error responses in the OpenBMC json api format. ''' + name = 'json_api_errors' + api = 2 + + def __init__(self, **kw): + self.app = None + self.function_type = None + self.original = None + self.json_opts = { + x: y for x, y in kw.iteritems() + if x in ['indent', 'sort_keys']} + + def setup(self, app): + self.app = app + self.function_type = type(app.default_error_handler) + self.original = app.default_error_handler + self.app.default_error_handler = self.function_type( + self.json_errors, app, Bottle) + + def apply(self, callback, route): + return callback + + def close(self): + self.app.default_error_handler = self.function_type( + self.original, self.app, Bottle) + + def json_errors(self, res, error): + response_object = {'status': 'error', 'data': {}} + response_object['message'] = error.status_line + response_object['data']['description'] = str(error.body) + if error.status_code == 500: + response_object['data']['exception'] = repr(error.exception) + response_object['data']['traceback'] = error.traceback.splitlines() + + json_response = json.dumps(response_object, **self.json_opts) + response.content_type = 'application/json' + return json_response + class RestApp(Bottle): - def __init__(self, bus): - super(RestApp, self).__init__(autojson = False) - self.bus = bus - self.mapper = Mapper(bus) - - self.install_hooks() - self.install_plugins() - self.create_handlers() - self.install_handlers() - - def install_plugins(self): - # install json api plugins - json_kw = {'indent': 2, 'sort_keys': True} - self.install(JSONPlugin(**json_kw)) - self.install(JsonApiErrorsPlugin(**json_kw)) - self.install(AuthorizationPlugin()) - self.install(JsonApiResponsePlugin()) - self.install(JsonApiRequestPlugin()) - self.install(JsonApiRequestTypePlugin()) - - def install_hooks(self): - self.real_router_match = self.router.match - self.router.match = self.custom_router_match - self.add_hook('before_request', self.strip_extra_slashes) - - def create_handlers(self): - # create route handlers - self.session_handler = SessionHandler(self, self.bus) - self.directory_handler = DirectoryHandler(self, self.bus) - self.list_names_handler = ListNamesHandler(self, self.bus) - self.list_handler = ListHandler(self, self.bus) - self.method_handler = MethodHandler(self, self.bus) - self.property_handler = PropertyHandler(self, self.bus) - self.schema_handler = SchemaHandler(self, self.bus) - self.instance_handler = InstanceHandler(self, self.bus) - - def install_handlers(self): - self.session_handler.install() - self.directory_handler.install() - self.list_names_handler.install() - self.list_handler.install() - self.method_handler.install() - self.property_handler.install() - self.schema_handler.install() - # this has to come last, since it matches everything - self.instance_handler.install() - - def custom_router_match(self, environ): - ''' The built-in Bottle algorithm for figuring out if a 404 or 405 is - needed doesn't work for us since the instance rules match everything. - This monkey-patch lets the route handler figure out which response is - needed. This could be accomplished with a hook but that would require - calling the router match function twice. - ''' - route, args = self.real_router_match(environ) - if isinstance(route.callback, RouteHandler): - route.callback._setup(**args) - - return route, args - - @staticmethod - def strip_extra_slashes(): - path = request.environ['PATH_INFO'] - trailing = ("","/")[path[-1] == '/'] - parts = filter(bool, path.split('/')) - request.environ['PATH_INFO'] = '/' + '/'.join(parts) + trailing + def __init__(self, bus): + super(RestApp, self).__init__(autojson=False) + self.bus = bus + self.mapper = Mapper(bus) + + self.install_hooks() + self.install_plugins() + self.create_handlers() + self.install_handlers() + + def install_plugins(self): + # install json api plugins + json_kw = {'indent': 2, 'sort_keys': True} + self.install(JSONPlugin(**json_kw)) + self.install(JsonApiErrorsPlugin(**json_kw)) + self.install(AuthorizationPlugin()) + self.install(JsonApiResponsePlugin()) + self.install(JsonApiRequestPlugin()) + self.install(JsonApiRequestTypePlugin()) + + def install_hooks(self): + self.real_router_match = self.router.match + self.router.match = self.custom_router_match + self.add_hook('before_request', self.strip_extra_slashes) + + def create_handlers(self): + # create route handlers + self.session_handler = SessionHandler(self, self.bus) + self.directory_handler = DirectoryHandler(self, self.bus) + self.list_names_handler = ListNamesHandler(self, self.bus) + self.list_handler = ListHandler(self, self.bus) + self.method_handler = MethodHandler(self, self.bus) + self.property_handler = PropertyHandler(self, self.bus) + self.schema_handler = SchemaHandler(self, self.bus) + self.instance_handler = InstanceHandler(self, self.bus) + + def install_handlers(self): + self.session_handler.install() + self.directory_handler.install() + self.list_names_handler.install() + self.list_handler.install() + self.method_handler.install() + self.property_handler.install() + self.schema_handler.install() + # this has to come last, since it matches everything + self.instance_handler.install() + + def custom_router_match(self, environ): + ''' The built-in Bottle algorithm for figuring out if a 404 or 405 is + needed doesn't work for us since the instance rules match + everything. This monkey-patch lets the route handler figure + out which response is needed. This could be accomplished + with a hook but that would require calling the router match + function twice. + ''' + route, args = self.real_router_match(environ) + if isinstance(route.callback, RouteHandler): + route.callback._setup(**args) + + return route, args + + @staticmethod + def strip_extra_slashes(): + path = request.environ['PATH_INFO'] + trailing = ("", "/")[path[-1] == '/'] + parts = filter(bool, path.split('/')) + request.environ['PATH_INFO'] = '/' + '/'.join(parts) + trailing if __name__ == '__main__': - log = logging.getLogger('Rocket.Errors') - log.setLevel(logging.INFO) - log.addHandler(logging.StreamHandler(sys.stdout)) - - bus = dbus.SystemBus() - app = RestApp(bus) - default_cert = os.path.join(sys.prefix, 'share', - os.path.basename(__file__), 'cert.pem') - - server = Rocket(('0.0.0.0', - 443, - default_cert, - default_cert), - 'wsgi', {'wsgi_app': app}, - min_threads = 1, - max_threads = 1) - server.start() + log = logging.getLogger('Rocket.Errors') + log.setLevel(logging.INFO) + log.addHandler(logging.StreamHandler(sys.stdout)) + + bus = dbus.SystemBus() + app = RestApp(bus) + default_cert = os.path.join( + sys.prefix, 'share', os.path.basename(__file__), 'cert.pem') + + server = Rocket( + ('0.0.0.0', 443, default_cert, default_cert), + 'wsgi', {'wsgi_app': app}, + min_threads=1, + max_threads=1) + server.start() -- cgit v1.2.1 From b103d2d225af95eb0256bdf13b659af5d2a61c98 Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Fri, 4 Mar 2016 16:19:14 -0500 Subject: Use pyobmc package No functional changes here. Just module/package namespace updates to use the pyobmc library. --- obmc-rest | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/obmc-rest b/obmc-rest index f2e268b..7c4ddfd 100644 --- a/obmc-rest +++ b/obmc-rest @@ -9,8 +9,10 @@ import logging from xml.etree import ElementTree from rocket import Rocket from bottle import Bottle, abort, request, response, JSONPlugin, HTTPError -import OpenBMCMapper -from OpenBMCMapper import Mapper, PathTree, IntrospectionNodeParser, ListMatch +import obmc.utils.misc +import obmc.utils.pathtree +from obmc.dbuslib.introspection import IntrospectionNodeParser +import obmc.mapper import spwd import grp import crypt @@ -69,7 +71,7 @@ class RouteHandler(object): def __init__(self, app, bus, verbs, rules): self.app = app self.bus = bus - self.mapper = Mapper(bus) + self.mapper = obmc.mapper.Mapper(bus) self._verbs = makelist(verbs) self._rules = rules @@ -95,7 +97,7 @@ class RouteHandler(object): try: return f(**kw) except dbus.exceptions.DBusException, e: - if e.get_dbus_name() != OpenBMCMapper.MAPPER_NOT_FOUND: + if e.get_dbus_name() != obmc.mapper.MAPPER_NOT_FOUND: raise if callback is None: def callback(e, **kw): @@ -173,7 +175,7 @@ class ListHandler(RouteHandler): def do_get(self, path='/'): objs = {} mapper_data = request.route_data['map'] - tree = PathTree() + tree = obmc.utils.pathreee.PathTree() for x, y in mapper_data.iteritems(): tree[x] = y @@ -210,7 +212,7 @@ class ListHandler(RouteHandler): def enumerate_capable(path, bus_data): busses = [] for name, ifaces in bus_data.iteritems(): - if OpenBMCMapper.ENUMERATE_IFACE in ifaces: + if obmc.mapper.ENUMERATE_IFACE in ifaces: busses.append(name) return busses @@ -218,7 +220,7 @@ class ListHandler(RouteHandler): objs = {} for b in busses: obj = self.bus.get_object(b, path, introspect=False) - iface = dbus.Interface(obj, OpenBMCMapper.ENUMERATE_IFACE) + iface = dbus.Interface(obj, obmc.mapper.ENUMERATE_IFACE) objs.update(iface.enumerate()) return objs @@ -275,7 +277,7 @@ class MethodHandler(RouteHandler): data = iface.Introspect() parser = IntrospectionNodeParser( ElementTree.fromstring(data), - intf_match=ListMatch(interfaces)) + intf_match=obmc.utils.misc.ListMatch(interfaces)) for x, y in parser.get_interfaces().iteritems(): m = self.find_method_in_interface( method, obj, x, y.get('method')) @@ -722,7 +724,7 @@ class RestApp(Bottle): def __init__(self, bus): super(RestApp, self).__init__(autojson=False) self.bus = bus - self.mapper = Mapper(bus) + self.mapper = obmc.mapper.Mapper(bus) self.install_hooks() self.install_plugins() -- cgit v1.2.1 From 68caa1ee306e74f3a08fb2da6b4dbd0b020258db Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Fri, 4 Mar 2016 15:42:08 -0500 Subject: Added a license to obmc-rest file Apache2 --- obmc-rest | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/obmc-rest b/obmc-rest index 7c4ddfd..949a67c 100644 --- a/obmc-rest +++ b/obmc-rest @@ -1,5 +1,21 @@ #!/usr/bin/env python +# Contributors Listed Below - COPYRIGHT 2016 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. + import os import sys import dbus -- cgit v1.2.1 From 0f79e521dc1aa46a69140cb0aabaddd880e76c7b Mon Sep 17 00:00:00 2001 From: Brad Bishop Date: Fri, 18 Mar 2016 13:33:17 -0400 Subject: Enumerate with org.freedesktop.DBus.ObjectManager Previously using a custom enumerate interface. This is the standard interface. Also, try to find OM implementing objects higher up in the tree. This improves performance for sub-tree enumerate calls. Don't try to get properties for ObjectManager interfaces. For whatever reason sd-bus chokes on this, but it doesn't have any properties so it isn't needed anyway. --- obmc-rest | 93 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/obmc-rest b/obmc-rest index 949a67c..2eaa223 100644 --- a/obmc-rest +++ b/obmc-rest @@ -90,6 +90,7 @@ class RouteHandler(object): self.mapper = obmc.mapper.Mapper(bus) self._verbs = makelist(verbs) self._rules = rules + self.intf_match = obmc.utils.misc.org_dot_openbmc_match def _setup(self, **kw): request.route_data = {} @@ -191,53 +192,65 @@ class ListHandler(RouteHandler): def do_get(self, path='/'): objs = {} mapper_data = request.route_data['map'] - tree = obmc.utils.pathreee.PathTree() - for x, y in mapper_data.iteritems(): - tree[x] = y + managers = {} + owners = [] + # look for objectmanager implementations as they result + # in fewer dbus calls + for path, bus_data in mapper_data.iteritems(): + for owner, interfaces in bus_data.iteritems(): + owners.append(owner) + if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces: + managers[owner] = path + + # also look in the parent objects + ancestors = self.mapper.get_ancestors(path) + + # finally check the root for one too try: - # Check to see if the root path implements - # enumerate in addition to any sub tree - # objects. - root = self.try_mapper_call( - self.mapper.get_object, path=path) - mapper_data[path] = root - except: - pass + ancestors.update({path: self.mapper.get_object(path)}) + except dbus.exceptions.DBusException, e: + if e.get_dbus_name() != obmc.mapper.MAPPER_NOT_FOUND: + raise - have_enumerate = [ - (x[0], self.enumerate_capable(*x)) - for x in mapper_data.iteritems() if self.enumerate_capable(*x)] + for path, bus_data in ancestors.iteritems(): + for owner, interfaces in bus_data.iteritems(): + if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces: + managers[owner] = path - for x, y in have_enumerate: - objs.update(self.call_enumerate(x, y)) - tmp = tree[x] - # remove the subtree - del tree[x] - # add the new leaf back since enumerate results don't - # include the object enumerate is being invoked on - tree[x] = tmp + # make all the manager gmo (get managed objects) calls + results = {} + for owner, path in managers.iteritems(): + if owner not in owners: + continue + obj = self.bus.get_object(owner, path, introspect=False) + iface = dbus.Interface( + obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager') + + # flatten (remove interface names) gmo results + for path, interfaces in iface.GetManagedObjects().iteritems(): + if path not in mapper_data.iterkeys(): + continue + properties = {} + for iface, props in interfaces.iteritems(): + properties.update(props) + results.setdefault(path, {}).setdefault(owner, properties) # make dbus calls for any remaining objects - for x, y in tree.dataitems(): - objs[x] = self.app.instance_handler.do_get(x) - - return objs + for path, bus_data in mapper_data.iteritems(): + for owner, interfaces in bus_data.iteritems(): + if results.setdefault(path, {}).setdefault(owner, {}): + continue + results.setdefault(path, {}).setdefault( + owner, + self.app.instance_handler.get_properties_on_bus( + path, owner, interfaces)) - @staticmethod - def enumerate_capable(path, bus_data): - busses = [] - for name, ifaces in bus_data.iteritems(): - if obmc.mapper.ENUMERATE_IFACE in ifaces: - busses.append(name) - return busses - - def call_enumerate(self, path, busses): objs = {} - for b in busses: - obj = self.bus.get_object(b, path, introspect=False) - iface = dbus.Interface(obj, obmc.mapper.ENUMERATE_IFACE) - objs.update(iface.enumerate()) + for path, owners in results.iteritems(): + for owner, properties in owners.iteritems(): + objs.setdefault(path, {}).update(properties) + return objs @@ -442,6 +455,8 @@ class InstanceHandler(RouteHandler): properties_iface = dbus.Interface( obj, dbus_interface=dbus.PROPERTIES_IFACE) for i in interfaces: + if not self.intf_match(i): + continue properties.update(self.get_properties_on_iface( properties_iface, i)) -- cgit v1.2.1