blob: 5995ee09d357f0cac824e690d4032e730c340936 [file] [log] [blame]
Brad Bishop732c6db2015-10-19 14:49:21 -04001#!/usr/bin/env python
2
Brad Bishopb3385602016-03-04 15:32:01 -05003# Contributors Listed Below - COPYRIGHT 2016
Brad Bishop732c6db2015-10-19 14:49:21 -04004# [+] International Business Machines Corp.
5#
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16# implied. See the License for the specific language governing
17# permissions and limitations under the License.
18
Brad Bishop732c6db2015-10-19 14:49:21 -040019import dbus
20import dbus.service
Brad Bishopae0c0af2015-11-09 18:41:28 -050021import dbus.exceptions
Brad Bishop732c6db2015-10-19 14:49:21 -040022import dbus.mainloop.glib
23import gobject
Brad Bishopfb1f58e2016-03-04 15:19:13 -050024from obmc.dbuslib.introspection import IntrospectionParser
25import obmc.utils.pathtree
26import obmc.utils.misc
27import obmc.mapper
Brad Bishop732c6db2015-10-19 14:49:21 -040028
Brad Bishop4b849412016-02-04 15:40:26 -050029
Brad Bishopae0c0af2015-11-09 18:41:28 -050030class MapperNotFoundException(dbus.exceptions.DBusException):
Brad Bishopfb1f58e2016-03-04 15:19:13 -050031 _dbus_error_name = obmc.mapper.MAPPER_NOT_FOUND
Brad Bishop4b849412016-02-04 15:40:26 -050032
33 def __init__(self, path):
34 super(MapperNotFoundException, self).__init__(
35 "path or object not found: %s" % (path))
36
Brad Bishopae0c0af2015-11-09 18:41:28 -050037
Brad Bishop732c6db2015-10-19 14:49:21 -040038class ObjectMapper(dbus.service.Object):
Brad Bishop4b849412016-02-04 15:40:26 -050039 def __init__(self, bus, path,
Brad Bishopfb1f58e2016-03-04 15:19:13 -050040 name_match=obmc.utils.misc.org_dot_openbmc_match,
41 intf_match=obmc.utils.misc.org_dot_openbmc_match):
Brad Bishop4b849412016-02-04 15:40:26 -050042 super(ObjectMapper, self).__init__(bus.dbus, path)
Brad Bishopfb1f58e2016-03-04 15:19:13 -050043 self.cache = obmc.utils.pathtree.PathTree()
Brad Bishop4b849412016-02-04 15:40:26 -050044 self.bus = bus
45 self.name_match = name_match
46 self.intf_match = intf_match
Brad Bishopfb1f58e2016-03-04 15:19:13 -050047 self.tag_match = obmc.utils.misc.ListMatch(['children', 'interface'])
Brad Bishop4b849412016-02-04 15:40:26 -050048 self.service = None
Brad Bishop732c6db2015-10-19 14:49:21 -040049
Brad Bishop4b849412016-02-04 15:40:26 -050050 gobject.idle_add(self.discover)
51 self.bus.dbus.add_signal_receiver(
52 self.bus_handler,
53 dbus_interface=
54 dbus.BUS_DAEMON_IFACE,
55 signal_name='NameOwnerChanged')
56 self.bus.dbus.add_signal_receiver(
57 self.interfaces_added_handler,
58 dbus_interface=
59 dbus.BUS_DAEMON_IFACE + '.ObjectManager',
60 signal_name='InterfacesAdded',
61 sender_keyword='sender')
62 self.bus.dbus.add_signal_receiver(
63 self.interfaces_removed_handler,
64 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
65 signal_name='InterfacesRemoved',
66 sender_keyword='sender')
Brad Bishop732c6db2015-10-19 14:49:21 -040067
Brad Bishop4b849412016-02-04 15:40:26 -050068 def bus_match(self, name):
Brad Bishopfb1f58e2016-03-04 15:19:13 -050069 if name == obmc.mapper.MAPPER_NAME:
Brad Bishop4b849412016-02-04 15:40:26 -050070 return False
71 return self.name_match(name)
Brad Bishop65b7ceb2015-11-04 23:05:56 -050072
Brad Bishop4b849412016-02-04 15:40:26 -050073 def discovery_pending(self):
74 return not bool(self.service)
Brad Bishopcb7aa602015-11-03 10:40:17 -050075
Brad Bishop4b849412016-02-04 15:40:26 -050076 def interfaces_added_handler(self, path, iprops, **kw):
77 name = self.bus.get_owned_name(self.bus_match, kw['sender'])
78 if self.discovery_pending() or \
79 not self.bus_match(name):
80 return
Brad Bishop5ffc2a32015-11-25 08:46:01 -050081
Brad Bishop4b849412016-02-04 15:40:26 -050082 matches = [x for x in iprops.iterkeys() if self.intf_match(x)]
83 self.add_interfaces(path, kw['sender'], matches)
Brad Bishop732c6db2015-10-19 14:49:21 -040084
Brad Bishop4b849412016-02-04 15:40:26 -050085 def interfaces_removed_handler(self, path, interfaces, **kw):
86 name = self.bus.get_owned_name(self.bus_match, kw['sender'])
87 if self.discovery_pending() or \
88 not self.bus_match(name):
89 return
90 item = self.cache[path]
91 sender = kw['sender']
92 for x in interfaces:
93 if self.intf_match(x):
94 try:
95 item[sender].remove(x)
96 except ValueError:
97 pass
Brad Bishop54d3ec92015-11-03 09:32:34 -050098
Brad Bishop4b849412016-02-04 15:40:26 -050099 # remove the owner if there aren't any interfaces left
100 if not item[sender]:
101 del item[sender]
Brad Bishop54d3ec92015-11-03 09:32:34 -0500102
Brad Bishop4b849412016-02-04 15:40:26 -0500103 # update if interfaces remain
104 if item:
105 self.cache[path] = item
106 # mark for removal if no interfaces remain
107 elif self.cache.get_children(path):
108 self.cache.demote(path)
109 # delete the entire path if everything is gone
110 else:
111 del self.cache[path]
Brad Bishop732c6db2015-10-19 14:49:21 -0400112
Brad Bishop4b849412016-02-04 15:40:26 -0500113 def process_new_owner(self, name):
114 # unique name
115 return self.discover([IntrospectionParser(name,
116 self.bus.dbus,
117 self.tag_match,
118 self.intf_match)])
Brad Bishop732c6db2015-10-19 14:49:21 -0400119
Brad Bishop4b849412016-02-04 15:40:26 -0500120 def process_old_owner(self, name):
121 for x, y in self.cache.dataitems():
122 if name not in y:
123 continue
124 del y[name]
125 if y:
126 self.cache[x] = y
127 elif self.cache.get_children(x):
128 self.cache.demote(x)
129 else:
130 del self.cache[x]
Brad Bishop732c6db2015-10-19 14:49:21 -0400131
Brad Bishop4b849412016-02-04 15:40:26 -0500132 def bus_handler(self, service, old, new):
133 if self.discovery_pending() or \
134 not self.bus_match(service):
135 return
Brad Bishop732c6db2015-10-19 14:49:21 -0400136
Brad Bishop4b849412016-02-04 15:40:26 -0500137 if new:
138 self.process_new_owner(new)
139 if old:
140 self.process_old_owner(old)
Brad Bishop732c6db2015-10-19 14:49:21 -0400141
Brad Bishop4b849412016-02-04 15:40:26 -0500142 def add_interfaces(self, path, owner, interfaces):
143 d = self.cache.setdefault(path, {})
144 d = d.setdefault(owner, [])
145 self.cache[path][owner] = list(set(d + interfaces))
Brad Bishop86398d22015-10-28 21:58:31 -0400146
Brad Bishop4b849412016-02-04 15:40:26 -0500147 def add_items(self, owner, bus_items):
148 for x, y in bus_items.iteritems():
149 self.add_interfaces(x, owner, y['interfaces'])
Brad Bishop86398d22015-10-28 21:58:31 -0400150
Brad Bishop4b849412016-02-04 15:40:26 -0500151 def discover(self, owners=None):
152 if not owners:
153 owners = [IntrospectionParser(x, self.bus.dbus,
154 self.tag_match,
155 self.intf_match)
156 for x in self.bus.get_owner_names(self.bus_match)]
157 for o in owners:
158 self.add_items(o.name, o.introspect())
Brad Bishop732c6db2015-10-19 14:49:21 -0400159
Brad Bishop4b849412016-02-04 15:40:26 -0500160 if self.discovery_pending():
161 print "ObjectMapper discovery complete..."
162 self.service = dbus.service.BusName(
Brad Bishopfb1f58e2016-03-04 15:19:13 -0500163 obmc.mapper.MAPPER_NAME, self.bus.dbus)
Brad Bishop732c6db2015-10-19 14:49:21 -0400164
Brad Bishopfb1f58e2016-03-04 15:19:13 -0500165 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sas}')
Brad Bishop4b849412016-02-04 15:40:26 -0500166 def GetObject(self, path):
167 o = self.cache.get(path)
168 if not o:
169 raise MapperNotFoundException(path)
170 return o
Brad Bishop732c6db2015-10-19 14:49:21 -0400171
Brad Bishopfb1f58e2016-03-04 15:19:13 -0500172 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'as')
Brad Bishop4b849412016-02-04 15:40:26 -0500173 def GetSubTreePaths(self, path, depth):
174 try:
175 return self.cache.iterkeys(path, depth)
176 except KeyError:
177 raise MapperNotFoundException(path)
Brad Bishop732c6db2015-10-19 14:49:21 -0400178
Brad Bishopfb1f58e2016-03-04 15:19:13 -0500179 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
Brad Bishop4b849412016-02-04 15:40:26 -0500180 def GetSubTree(self, path, depth):
181 try:
182 return {x: y for x, y in self.cache.dataitems(path, depth)}
183 except KeyError:
184 raise MapperNotFoundException(path)
185
Brad Bishop732c6db2015-10-19 14:49:21 -0400186
Brad Bishop732c6db2015-10-19 14:49:21 -0400187class BusWrapper:
Brad Bishop4b849412016-02-04 15:40:26 -0500188 def __init__(self, bus):
189 self.dbus = bus
Brad Bishop732c6db2015-10-19 14:49:21 -0400190
Brad Bishop4b849412016-02-04 15:40:26 -0500191 def get_owned_name(self, match, bus):
192 for x in self.get_service_names(match):
193 if self.dbus.get_name_owner(x) == bus:
194 return x
Brad Bishop5ffc2a32015-11-25 08:46:01 -0500195
Brad Bishop4b849412016-02-04 15:40:26 -0500196 def get_service_names(self, match):
197 # these are well known names
198 return [x for x in self.dbus.list_names()
199 if match(x)]
Brad Bishop732c6db2015-10-19 14:49:21 -0400200
Brad Bishop4b849412016-02-04 15:40:26 -0500201 def get_owner_names(self, match):
202 # these are unique connection names
203 return list(set(
204 [self.dbus.get_name_owner(x)
205 for x in self.get_service_names(match)]))
Brad Bishop732c6db2015-10-19 14:49:21 -0400206
Brad Bishop732c6db2015-10-19 14:49:21 -0400207if __name__ == '__main__':
Brad Bishop4b849412016-02-04 15:40:26 -0500208 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
209 bus = dbus.SystemBus()
Brad Bishopfb1f58e2016-03-04 15:19:13 -0500210 o = ObjectMapper(BusWrapper(bus), obmc.mapper.MAPPER_PATH)
Brad Bishop4b849412016-02-04 15:40:26 -0500211 loop = gobject.MainLoop()
Brad Bishop732c6db2015-10-19 14:49:21 -0400212
Brad Bishop4b849412016-02-04 15:40:26 -0500213 loop.run()