diff options
Diffstat (limited to 'obmc/dbuslib')
-rw-r--r-- | obmc/dbuslib/__init__.py | 0 | ||||
-rw-r--r-- | obmc/dbuslib/bindings.py | 172 | ||||
-rw-r--r-- | obmc/dbuslib/enums.py | 29 | ||||
-rw-r--r-- | obmc/dbuslib/introspection.py | 136 |
4 files changed, 337 insertions, 0 deletions
diff --git a/obmc/dbuslib/__init__.py b/obmc/dbuslib/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/obmc/dbuslib/__init__.py diff --git a/obmc/dbuslib/bindings.py b/obmc/dbuslib/bindings.py new file mode 100644 index 0000000..51b9e59 --- /dev/null +++ b/obmc/dbuslib/bindings.py @@ -0,0 +1,172 @@ +# 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 dbus + +BUS_PREFIX = 'org.openbmc' +OBJ_PREFIX = "/org/openbmc" +BUS = "system" + + +def is_unique(connection): + return connection[0] == ':' + + +def get_system_name(): + #use filename as system name, strip off path and ext + parts = __file__.replace('.pyc', '').replace('.py', '').split('/') + return parts[len(parts)-1] + + +def get_dbus(): + bus = None + if (BUS == "session"): + bus = dbus.SessionBus() + else: + bus = dbus.SystemBus() + return bus + + +class DbusProperties(dbus.service.Object): + def __init__(self): + dbus.service.Object.__init__(self) + self.properties = {} + self.object_path = "" + + @dbus.service.method( + dbus.PROPERTIES_IFACE, + in_signature='ss', out_signature='v') + def Get(self, interface_name, property_name): + d = self.GetAll(interface_name) + try: + v = d[property_name] + return v + except: + raise dbus.exceptions.DBusException( + "org.freedesktop.UnknownProperty: "+property_name) + + @dbus.service.method( + dbus.PROPERTIES_IFACE, + in_signature='s', out_signature='a{sv}') + def GetAll(self, interface_name): + try: + d = self.properties[interface_name] + return d + except: + raise dbus.exceptions.DBusException( + "org.freedesktop.UnknownInterface: "+interface_name) + + @dbus.service.method( + dbus.PROPERTIES_IFACE, + in_signature='ssv') + def Set(self, interface_name, property_name, new_value): + if (interface_name not in self.properties): + self.properties[interface_name] = {} + try: + old_value = self.properties[interface_name][property_name] + if (old_value != new_value): + self.properties[interface_name][property_name] = new_value + self.PropertiesChanged( + interface_name, {property_name: new_value}, []) + + except: + self.properties[interface_name][property_name] = new_value + self.PropertiesChanged( + interface_name, {property_name: new_value}, []) + + @dbus.service.method( + "org.openbmc.Object.Properties", in_signature='sa{sv}') + def SetMultiple(self, interface_name, prop_dict): + if (interface_name in self.properties): + self.properties[interface_name] = {} + + value_changed = False + for property_name in prop_dict: + new_value = prop_dict[property_name] + try: + old_value = self.properties[interface_name][property_name] + if (old_value != new_value): + self.properties[interface_name][property_name] = new_value + value_changed = True + + except: + self.properties[interface_name][property_name] = new_value + value_changed = True + if (value_changed is True): + self.PropertiesChanged(interface_name, prop_dict, []) + + @dbus.service.signal( + dbus.PROPERTIES_IFACE, signature='sa{sv}as') + def PropertiesChanged( + self, interface_name, changed_properties, invalidated_properties): + pass + + +class DbusObjectManager(dbus.service.Object): + def __init__(self): + dbus.service.Object.__init__(self) + self.objects = {} + + def add(self, object_path, obj): + self.objects[object_path] = obj + self.InterfacesAdded(object_path, obj.properties) + + def remove(self, object_path): + obj = self.objects.pop(object_path, None) + obj.remove_from_connection() + self.InterfacesRemoved(object_path, obj.properties.keys()) + + def get(self, object_path, default=None): + return self.objects.get(object_path, default) + + @dbus.service.method( + "org.freedesktop.DBus.ObjectManager", + in_signature='', out_signature='a{oa{sa{sv}}}') + def GetManagedObjects(self): + data = {} + for objpath in self.objects.keys(): + data[objpath] = self.objects[objpath].properties + return data + + @dbus.service.signal( + "org.freedesktop.DBus.ObjectManager", signature='oa{sa{sv}}') + def InterfacesAdded(self, object_path, properties): + self.ObjectAdded(object_path, "") + + @dbus.service.signal( + "org.freedesktop.DBus.ObjectManager", signature='oas') + def InterfacesRemoved(self, object_path, interfaces): + pass + + ## Legacy support, need to eventually refactor out + @dbus.service.signal( + "org.openbmc.Object.ObjectMapper", signature='ss') + def ObjectAdded(self, object_path, interface_name): + pass + + ## flattens interfaces + @dbus.service.method( + 'org.openbmc.Object.Enumerate', in_signature='', + out_signature='a{sa{sv}}') + def enumerate(self): + data = {} + for objpath in self.objects.keys(): + props = self.objects[objpath].properties + data[objpath] = {} + for iface in props.keys(): + data[objpath].update(props[iface]) + + return data diff --git a/obmc/dbuslib/enums.py b/obmc/dbuslib/enums.py new file mode 100644 index 0000000..910594a --- /dev/null +++ b/obmc/dbuslib/enums.py @@ -0,0 +1,29 @@ +# 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 dbus + +DBUS_OBJMGR_IFACE = dbus.BUS_DAEMON_IFACE + '.ObjectManager' +DBUS_UNKNOWN_INTERFACE = 'org.freedesktop.UnknownInterface' +DBUS_UNKNOWN_PROPERTY = 'org.freedesktop.DBus.Error.UnknownProperty' +DBUS_UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod' +DBUS_INVALID_ARGS = 'org.freedesktop.DBus.Error.InvalidArgs' +DBUS_TYPE_ERROR = 'org.freedesktop.DBus.Python.TypeError' +OBMC_ASSOCIATIONS_IFACE = 'org.openbmc.Associations' +OBMC_ASSOC_IFACE = 'org.openbmc.Association' +OBMC_DELETE_IFACE = 'org.openbmc.Object.Delete' +OBMC_PROPERTIES_IFACE = "org.openbmc.Object.Properties" +OBMC_ENUMERATE_IFACE = "org.openbmc.Object.Enumerate" diff --git a/obmc/dbuslib/introspection.py b/obmc/dbuslib/introspection.py new file mode 100644 index 0000000..db83c6e --- /dev/null +++ b/obmc/dbuslib/introspection.py @@ -0,0 +1,136 @@ +# 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. + +from xml.etree import ElementTree +import dbus + + +class IntrospectionNodeParser: + def __init__(self, data, tag_match=bool, intf_match=bool): + self.data = data + self.cache = {} + self.tag_match = tag_match + self.intf_match = intf_match + + def parse_args(self): + return [x.attrib for x in self.data.findall('arg')] + + def parse_children(self): + return [x.attrib['name'] for x in self.data.findall('node')] + + def parse_method_or_signal(self): + name = self.data.attrib['name'] + return name, self.parse_args() + + def parse_interface(self): + iface = {} + iface['method'] = {} + iface['signal'] = {} + + for node in self.data: + if node.tag not in ['method', 'signal']: + continue + if not self.tag_match(node.tag): + continue + p = IntrospectionNodeParser( + node, self.tag_match, self.intf_match) + n, element = p.parse_method_or_signal() + iface[node.tag][n] = element + + return iface + + def parse_node(self): + if self.cache: + return self.cache + + self.cache['interfaces'] = {} + self.cache['children'] = [] + + for node in self.data: + if node.tag == 'interface': + p = IntrospectionNodeParser( + node, self.tag_match, self.intf_match) + name = p.data.attrib['name'] + if not self.intf_match(name): + continue + self.cache['interfaces'][name] = p.parse_interface() + elif node.tag == 'node': + self.cache['children'] = self.parse_children() + + return self.cache + + def get_interfaces(self): + return self.parse_node()['interfaces'] + + def get_children(self): + return self.parse_node()['children'] + + def recursive_binding(self): + return any('/' in s for s in self.get_children()) + + +class IntrospectionParser: + def __init__(self, name, bus, tag_match=bool, intf_match=bool): + self.name = name + self.bus = bus + self.tag_match = tag_match + self.intf_match = intf_match + + def _introspect(self, path): + try: + obj = self.bus.get_object(self.name, path, introspect=False) + iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE) + data = iface.Introspect() + except dbus.DBusException: + return None + + return IntrospectionNodeParser( + ElementTree.fromstring(data), + self.tag_match, + self.intf_match) + + def _discover_flat(self, path, parser): + items = {} + interfaces = parser.get_interfaces().keys() + if interfaces: + items[path] = {} + items[path]['interfaces'] = interfaces + + return items + + def introspect(self, path='/', parser=None): + items = {} + if not parser: + parser = self._introspect(path) + if not parser: + return {} + items.update(self._discover_flat(path, parser)) + + if path != '/': + path += '/' + + if parser.recursive_binding(): + callback = self._discover_flat + else: + callback = self.introspect + + for k in parser.get_children(): + parser = self._introspect(path + k) + if not parser: + continue + items.update(callback(path + k, parser)) + + return items |