xref: /openbmc/pyphosphor/obmc/dbuslib/bindings.py (revision aea38c650b8554e8f6293483286eba18a5547cd9)
18ffe1e44SBrad Bishop# Contributors Listed Below - COPYRIGHT 2016
28ffe1e44SBrad Bishop# [+] International Business Machines Corp.
38ffe1e44SBrad Bishop#
48ffe1e44SBrad Bishop#
58ffe1e44SBrad Bishop# Licensed under the Apache License, Version 2.0 (the "License");
68ffe1e44SBrad Bishop# you may not use this file except in compliance with the License.
78ffe1e44SBrad Bishop# You may obtain a copy of the License at
88ffe1e44SBrad Bishop#
98ffe1e44SBrad Bishop#     http://www.apache.org/licenses/LICENSE-2.0
108ffe1e44SBrad Bishop#
118ffe1e44SBrad Bishop# Unless required by applicable law or agreed to in writing, software
128ffe1e44SBrad Bishop# distributed under the License is distributed on an "AS IS" BASIS,
138ffe1e44SBrad Bishop# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148ffe1e44SBrad Bishop# implied. See the License for the specific language governing
158ffe1e44SBrad Bishop# permissions and limitations under the License.
168ffe1e44SBrad Bishop
178ffe1e44SBrad Bishopimport dbus
1884ed6e17SBrad Bishopimport dbus.service
1984ed6e17SBrad Bishopimport dbus.exceptions
208ffe1e44SBrad Bishop
21c88b0958SBrad BishopOBJ_PREFIX = '/xyz/openbmc_project'
228ffe1e44SBrad Bishop
238ffe1e44SBrad Bishop
248ffe1e44SBrad Bishopdef is_unique(connection):
258ffe1e44SBrad Bishop    return connection[0] == ':'
268ffe1e44SBrad Bishop
278ffe1e44SBrad Bishop
288ffe1e44SBrad Bishopdef get_dbus():
2993d0cf05SBrad Bishop    return dbus.SystemBus()
308ffe1e44SBrad Bishop
318ffe1e44SBrad Bishop
328ffe1e44SBrad Bishopclass DbusProperties(dbus.service.Object):
33d874f0b0SBrad Bishop    def __init__(self, **kw):
344fed868cSPatrick Williams        self.validator = kw.pop('validator', None)
35d874f0b0SBrad Bishop        super(DbusProperties, self).__init__(**kw)
368ffe1e44SBrad Bishop        self.properties = {}
376835b67aSBrad Bishop        self._export = False
386835b67aSBrad Bishop
396835b67aSBrad Bishop    def unmask_signals(self):
406835b67aSBrad Bishop        self._export = True
416835b67aSBrad Bishop        inst = super(DbusProperties, self)
426835b67aSBrad Bishop        if hasattr(inst, 'unmask_signals'):
436835b67aSBrad Bishop            inst.unmask_signals()
446835b67aSBrad Bishop
456835b67aSBrad Bishop    def mask_signals(self):
466835b67aSBrad Bishop        self._export = False
476835b67aSBrad Bishop        inst = super(DbusProperties, self)
486835b67aSBrad Bishop        if hasattr(inst, 'mask_signals'):
496835b67aSBrad Bishop            inst.mask_signals()
508ffe1e44SBrad Bishop
518ffe1e44SBrad Bishop    @dbus.service.method(
528ffe1e44SBrad Bishop        dbus.PROPERTIES_IFACE,
538ffe1e44SBrad Bishop        in_signature='ss', out_signature='v')
548ffe1e44SBrad Bishop    def Get(self, interface_name, property_name):
558ffe1e44SBrad Bishop        d = self.GetAll(interface_name)
568ffe1e44SBrad Bishop        try:
578ffe1e44SBrad Bishop            v = d[property_name]
588ffe1e44SBrad Bishop            return v
59*aea38c65SBrad Bishop        except Exception:
608ffe1e44SBrad Bishop            raise dbus.exceptions.DBusException(
61dc7f067dSAdriana Kobylak                "Unknown property: '{}'".format(property_name),
62dc7f067dSAdriana Kobylak                name="org.freedesktop.DBus.Error.UnknownProperty")
638ffe1e44SBrad Bishop
648ffe1e44SBrad Bishop    @dbus.service.method(
658ffe1e44SBrad Bishop        dbus.PROPERTIES_IFACE,
668ffe1e44SBrad Bishop        in_signature='s', out_signature='a{sv}')
678ffe1e44SBrad Bishop    def GetAll(self, interface_name):
688ffe1e44SBrad Bishop        try:
698ffe1e44SBrad Bishop            d = self.properties[interface_name]
708ffe1e44SBrad Bishop            return d
71*aea38c65SBrad Bishop        except Exception:
728ffe1e44SBrad Bishop            raise dbus.exceptions.DBusException(
73dc7f067dSAdriana Kobylak                "Unknown interface: '{}'".format(interface_name),
74dc7f067dSAdriana Kobylak                name="org.freedesktop.DBus.Error.UnknownInterface")
758ffe1e44SBrad Bishop
768ffe1e44SBrad Bishop    @dbus.service.method(
778ffe1e44SBrad Bishop        dbus.PROPERTIES_IFACE,
788ffe1e44SBrad Bishop        in_signature='ssv')
798ffe1e44SBrad Bishop    def Set(self, interface_name, property_name, new_value):
808ffe1e44SBrad Bishop        if (interface_name not in self.properties):
818ffe1e44SBrad Bishop            self.properties[interface_name] = {}
820722564eSVishwanatha Subbanna
830722564eSVishwanatha Subbanna        if self.validator:
840722564eSVishwanatha Subbanna            self.validator(interface_name, property_name, new_value)
850722564eSVishwanatha Subbanna
868ffe1e44SBrad Bishop        try:
878ffe1e44SBrad Bishop            old_value = self.properties[interface_name][property_name]
888ffe1e44SBrad Bishop            if (old_value != new_value):
898ffe1e44SBrad Bishop                self.properties[interface_name][property_name] = new_value
906835b67aSBrad Bishop                if self._export:
918ffe1e44SBrad Bishop                    self.PropertiesChanged(
928ffe1e44SBrad Bishop                        interface_name, {property_name: new_value}, [])
938ffe1e44SBrad Bishop
94*aea38c65SBrad Bishop        except Exception:
958ffe1e44SBrad Bishop            self.properties[interface_name][property_name] = new_value
966835b67aSBrad Bishop            if self._export:
978ffe1e44SBrad Bishop                self.PropertiesChanged(
988ffe1e44SBrad Bishop                    interface_name, {property_name: new_value}, [])
998ffe1e44SBrad Bishop
1008ffe1e44SBrad Bishop    @dbus.service.method(
1018ffe1e44SBrad Bishop        "org.openbmc.Object.Properties", in_signature='sa{sv}')
1028ffe1e44SBrad Bishop    def SetMultiple(self, interface_name, prop_dict):
103d0827b16SBrad Bishop        if (interface_name not in self.properties):
1048ffe1e44SBrad Bishop            self.properties[interface_name] = {}
1058ffe1e44SBrad Bishop
1068ffe1e44SBrad Bishop        value_changed = False
1078ffe1e44SBrad Bishop        for property_name in prop_dict:
1088ffe1e44SBrad Bishop            new_value = prop_dict[property_name]
1098ffe1e44SBrad Bishop            try:
1108ffe1e44SBrad Bishop                old_value = self.properties[interface_name][property_name]
1118ffe1e44SBrad Bishop                if (old_value != new_value):
1128ffe1e44SBrad Bishop                    self.properties[interface_name][property_name] = new_value
1138ffe1e44SBrad Bishop                    value_changed = True
1148ffe1e44SBrad Bishop
115*aea38c65SBrad Bishop            except Exception:
1168ffe1e44SBrad Bishop                self.properties[interface_name][property_name] = new_value
1178ffe1e44SBrad Bishop                value_changed = True
1186835b67aSBrad Bishop        if (value_changed is True and self._export):
1198ffe1e44SBrad Bishop            self.PropertiesChanged(interface_name, prop_dict, [])
1208ffe1e44SBrad Bishop
1218ffe1e44SBrad Bishop    @dbus.service.signal(
1228ffe1e44SBrad Bishop        dbus.PROPERTIES_IFACE, signature='sa{sv}as')
1238ffe1e44SBrad Bishop    def PropertiesChanged(
1248ffe1e44SBrad Bishop            self, interface_name, changed_properties, invalidated_properties):
1258ffe1e44SBrad Bishop        pass
1268ffe1e44SBrad Bishop
1278ffe1e44SBrad Bishop
1282b054348SBrad Bishopdef add_interfaces_to_class(cls, ifaces):
1292b054348SBrad Bishop    """
1302b054348SBrad Bishop    The built-in Introspect method in dbus-python doesn't find
1312b054348SBrad Bishop    interfaces if the @method or @signal decorators aren't used
1322b054348SBrad Bishop    (property-only interfaces).  Use this method on a class
1332b054348SBrad Bishop    derived from dbus.service.Object to help the dbus-python provided
1342b054348SBrad Bishop    Introspect method find these interfaces.
1352b054348SBrad Bishop
1362b054348SBrad Bishop    Arguments:
1372b054348SBrad Bishop    cls -- The dbus.service.Object superclass to add interfaces to.
1382b054348SBrad Bishop    ifaces -- The property-only interfaces to add to the class.
1392b054348SBrad Bishop    """
1402b054348SBrad Bishop
1412b054348SBrad Bishop    for iface in ifaces:
1422b054348SBrad Bishop        class_table_key = '{}.{}'.format(cls.__module__, cls.__name__)
1432b054348SBrad Bishop        cls._dbus_class_table[class_table_key].setdefault(iface, {})
1442b054348SBrad Bishop
1452b054348SBrad Bishop
1462b054348SBrad Bishopdef add_interfaces(ifaces):
1472b054348SBrad Bishop    """
1482b054348SBrad Bishop    A class decorator for add_interfaces_to_class.
1492b054348SBrad Bishop    """
1502b054348SBrad Bishop
1512b054348SBrad Bishop    def decorator(cls):
1522b054348SBrad Bishop        undecorated = cls.__init__
1532b054348SBrad Bishop
1542b054348SBrad Bishop        def ctor(obj, *a, **kw):
1552b054348SBrad Bishop            undecorated(obj, *a, **kw)
1562b054348SBrad Bishop            add_interfaces_to_class(cls, ifaces)
1572b054348SBrad Bishop
1582b054348SBrad Bishop        cls.__init__ = ctor
1592b054348SBrad Bishop        return cls
1602b054348SBrad Bishop    return decorator
1612b054348SBrad Bishop
1622b054348SBrad Bishop
1638ffe1e44SBrad Bishopclass DbusObjectManager(dbus.service.Object):
164d874f0b0SBrad Bishop    def __init__(self, **kw):
165d874f0b0SBrad Bishop        super(DbusObjectManager, self).__init__(**kw)
1668ffe1e44SBrad Bishop        self.objects = {}
1676835b67aSBrad Bishop        self._export = False
1686835b67aSBrad Bishop
1696835b67aSBrad Bishop    def unmask_signals(self):
1706835b67aSBrad Bishop        self._export = True
1716835b67aSBrad Bishop        inst = super(DbusObjectManager, self)
1726835b67aSBrad Bishop        if hasattr(inst, 'unmask_signals'):
1736835b67aSBrad Bishop            inst.unmask_signals()
1746835b67aSBrad Bishop
1756835b67aSBrad Bishop    def mask_signals(self):
1766835b67aSBrad Bishop        self._export = False
1776835b67aSBrad Bishop        inst = super(DbusObjectManager, self)
1786835b67aSBrad Bishop        if hasattr(inst, 'mask_signals'):
1796835b67aSBrad Bishop            inst.mask_signals()
1808ffe1e44SBrad Bishop
1818ffe1e44SBrad Bishop    def add(self, object_path, obj):
1828ffe1e44SBrad Bishop        self.objects[object_path] = obj
1836835b67aSBrad Bishop        if self._export:
1848ffe1e44SBrad Bishop            self.InterfacesAdded(object_path, obj.properties)
1858ffe1e44SBrad Bishop
1868ffe1e44SBrad Bishop    def remove(self, object_path):
1878ffe1e44SBrad Bishop        obj = self.objects.pop(object_path, None)
1888ffe1e44SBrad Bishop        obj.remove_from_connection()
1896835b67aSBrad Bishop        if self._export:
1909172f3e7SCamVan Nguyen            self.InterfacesRemoved(object_path, list(obj.properties.keys()))
1918ffe1e44SBrad Bishop
1928ffe1e44SBrad Bishop    def get(self, object_path, default=None):
1938ffe1e44SBrad Bishop        return self.objects.get(object_path, default)
1948ffe1e44SBrad Bishop
1958ffe1e44SBrad Bishop    @dbus.service.method(
1968ffe1e44SBrad Bishop        "org.freedesktop.DBus.ObjectManager",
1978ffe1e44SBrad Bishop        in_signature='', out_signature='a{oa{sa{sv}}}')
1988ffe1e44SBrad Bishop    def GetManagedObjects(self):
1998ffe1e44SBrad Bishop        data = {}
2009172f3e7SCamVan Nguyen        for objpath in list(self.objects.keys()):
2018ffe1e44SBrad Bishop            data[objpath] = self.objects[objpath].properties
2028ffe1e44SBrad Bishop        return data
2038ffe1e44SBrad Bishop
2048ffe1e44SBrad Bishop    @dbus.service.signal(
2058ffe1e44SBrad Bishop        "org.freedesktop.DBus.ObjectManager", signature='oa{sa{sv}}')
2068ffe1e44SBrad Bishop    def InterfacesAdded(self, object_path, properties):
2070b30e97dSBrad Bishop        pass
2088ffe1e44SBrad Bishop
2098ffe1e44SBrad Bishop    @dbus.service.signal(
2108ffe1e44SBrad Bishop        "org.freedesktop.DBus.ObjectManager", signature='oas')
2118ffe1e44SBrad Bishop    def InterfacesRemoved(self, object_path, interfaces):
2128ffe1e44SBrad Bishop        pass
213