blob: f5b1def3d36ae5ea9cd2609b8086632c887496f7 [file] [log] [blame]
Brad Bishop732c6db2015-10-19 14:49:21 -04001#!/usr/bin/env python
2
3# Contributors Listed Below - COPYRIGHT 2015
4# [+] 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 Bishopae0c0af2015-11-09 18:41:28 -050024from OpenBMCMapper import IntrospectionParser, PathTree
Brad Bishop732c6db2015-10-19 14:49:21 -040025import OpenBMCMapper
26
Brad Bishopae0c0af2015-11-09 18:41:28 -050027class MapperNotFoundException(dbus.exceptions.DBusException):
28 _dbus_error_name = OpenBMCMapper.MAPPER_NOT_FOUND
29 def __init__(self, path):
30 super(MapperNotFoundException, self).__init__(
31 "path or object not found: %s" %(path))
32
Brad Bishop732c6db2015-10-19 14:49:21 -040033class ObjectMapper(dbus.service.Object):
34 def __init__(self, bus, path,
Brad Bishop6fb84612015-11-01 00:06:24 -040035 name_match = OpenBMCMapper.org_dot_openbmc_match,
36 intf_match = OpenBMCMapper.org_dot_openbmc_match):
Brad Bishop732c6db2015-10-19 14:49:21 -040037 super(ObjectMapper, self).__init__(bus.dbus, path)
Brad Bishop54d3ec92015-11-03 09:32:34 -050038 self.cache = PathTree()
Brad Bishop732c6db2015-10-19 14:49:21 -040039 self.bus = bus
40 self.name_match = name_match
41 self.intf_match = intf_match
Brad Bishopa8e752f2015-11-03 09:24:48 -050042 self.tag_match = OpenBMCMapper.ListMatch(['children', 'interface'])
Brad Bishopcb7aa602015-11-03 10:40:17 -050043 self.service = None
Brad Bishop732c6db2015-10-19 14:49:21 -040044
45 gobject.idle_add(self.discover)
46 self.bus.dbus.add_signal_receiver(self.bus_handler,
47 dbus_interface = dbus.BUS_DAEMON_IFACE,
48 signal_name = 'NameOwnerChanged')
49 self.bus.dbus.add_signal_receiver(self.interfaces_added_handler,
50 dbus_interface = dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishop5ffc2a32015-11-25 08:46:01 -050051 signal_name = 'InterfacesAdded',
Brad Bishop732c6db2015-10-19 14:49:21 -040052 sender_keyword = 'sender')
53 self.bus.dbus.add_signal_receiver(self.interfaces_removed_handler,
54 dbus_interface = dbus.BUS_DAEMON_IFACE + '.ObjectManager',
55 signal_name = 'InterfacesRemoved',
56 sender_keyword = 'sender')
57
Brad Bishop65b7ceb2015-11-04 23:05:56 -050058 def bus_match(self, name):
59 if name == OpenBMCMapper.MAPPER_NAME:
60 return False
61 return self.name_match(name)
62
Brad Bishopcb7aa602015-11-03 10:40:17 -050063 def discovery_pending(self):
64 return not bool(self.service)
65
Brad Bishop732c6db2015-10-19 14:49:21 -040066 def interfaces_added_handler(self, path, iprops, **kw):
Brad Bishop5ffc2a32015-11-25 08:46:01 -050067 name = self.bus.get_owned_name(self.bus_match, kw['sender'])
Brad Bishop65b7ceb2015-11-04 23:05:56 -050068 if self.discovery_pending() or \
Brad Bishop5ffc2a32015-11-25 08:46:01 -050069 not self.bus_match(name):
Brad Bishopcb7aa602015-11-03 10:40:17 -050070 return
Brad Bishop5ffc2a32015-11-25 08:46:01 -050071
Brad Bishop54d3ec92015-11-03 09:32:34 -050072 matches = [ x for x in iprops.iterkeys() if self.intf_match(x) ]
73 d = self.cache.setdefault(path, {})
Brad Bishop5ffc2a32015-11-25 08:46:01 -050074 d.setdefault(kw['sender'], []).extend(matches)
Brad Bishop54d3ec92015-11-03 09:32:34 -050075 self.cache[path] = d
Brad Bishop732c6db2015-10-19 14:49:21 -040076
77 def interfaces_removed_handler(self, path, interfaces, **kw):
Brad Bishop5ffc2a32015-11-25 08:46:01 -050078 name = self.bus.get_owned_name(self.bus_match, kw['sender'])
Brad Bishop65b7ceb2015-11-04 23:05:56 -050079 if self.discovery_pending() or \
Brad Bishop5ffc2a32015-11-25 08:46:01 -050080 not self.bus_match(name):
Brad Bishopcb7aa602015-11-03 10:40:17 -050081 return
Brad Bishop54d3ec92015-11-03 09:32:34 -050082 item = self.cache[path]
Brad Bishop5ffc2a32015-11-25 08:46:01 -050083 sender = kw['sender']
Brad Bishop732c6db2015-10-19 14:49:21 -040084 for x in interfaces:
Brad Bishop5ffc2a32015-11-25 08:46:01 -050085 if self.intf_match(x):
86 try:
87 item[sender].remove(x)
88 except ValueError:
89 pass
Brad Bishop54d3ec92015-11-03 09:32:34 -050090
91 # remove the owner if there aren't any interfaces left
Brad Bishop5ffc2a32015-11-25 08:46:01 -050092 if not item[sender]:
93 del item[sender]
Brad Bishop54d3ec92015-11-03 09:32:34 -050094
95 # update if interfaces remain
96 if item:
97 self.cache[path] = item
98 # mark for removal if no interfaces remain
Brad Bishop5ffc2a32015-11-25 08:46:01 -050099 elif self.cache.get_children(path):
100 self.cache.demote(path)
Brad Bishop54d3ec92015-11-03 09:32:34 -0500101 # delete the entire path if everything is gone
102 else:
103 del self.cache[path]
Brad Bishop732c6db2015-10-19 14:49:21 -0400104
105 def process_new_owner(self, name):
106 # unique name
Brad Bishop6fb84612015-11-01 00:06:24 -0400107 return self.discover([ IntrospectionParser(name,
108 self.bus.dbus, self.tag_match, self.intf_match) ])
Brad Bishop732c6db2015-10-19 14:49:21 -0400109
110 def process_old_owner(self, name):
Brad Bishop54d3ec92015-11-03 09:32:34 -0500111 for x,y in self.cache.dataitems():
112 if name not in y:
113 continue
114 del y[name]
115 if y:
116 self.cache[x] = y
117 elif self.cache.get_children(x):
118 self.cache.demote(x)
119 else:
120 del self.cache[x]
Brad Bishop732c6db2015-10-19 14:49:21 -0400121
122 def bus_handler(self, service, old, new):
Brad Bishopcb7aa602015-11-03 10:40:17 -0500123 if self.discovery_pending() or \
Brad Bishop65b7ceb2015-11-04 23:05:56 -0500124 not self.bus_match(service):
Brad Bishop732c6db2015-10-19 14:49:21 -0400125 return
126
127 if new:
128 self.process_new_owner(new)
129 if old:
130 self.process_old_owner(old)
131
Brad Bishop54d3ec92015-11-03 09:32:34 -0500132 def add_interfaces(self, path, owner, interfaces):
133 d = self.cache.setdefault(path, { })
134 d.setdefault(owner, []).extend(interfaces)
135 self.cache[path] = d
Brad Bishop86398d22015-10-28 21:58:31 -0400136
Brad Bishop6fb84612015-11-01 00:06:24 -0400137 def add_items(self, owner, bus_items):
Brad Bishop86398d22015-10-28 21:58:31 -0400138 for x,y in bus_items.iteritems():
Brad Bishop54d3ec92015-11-03 09:32:34 -0500139 self.add_interfaces(x, owner, y['interfaces'])
Brad Bishop86398d22015-10-28 21:58:31 -0400140
Brad Bishop732c6db2015-10-19 14:49:21 -0400141 def discover(self, owners = None):
Brad Bishop732c6db2015-10-19 14:49:21 -0400142 if not owners:
Brad Bishop6fb84612015-11-01 00:06:24 -0400143 owners = [ IntrospectionParser(x, self.bus.dbus,
144 self.tag_match, self.intf_match) \
Brad Bishop65b7ceb2015-11-04 23:05:56 -0500145 for x in self.bus.get_owner_names(self.bus_match) ]
Brad Bishop732c6db2015-10-19 14:49:21 -0400146 for o in owners:
Brad Bishop6fb84612015-11-01 00:06:24 -0400147 self.add_items(o.name, o.introspect())
Brad Bishop732c6db2015-10-19 14:49:21 -0400148
Brad Bishopcb7aa602015-11-03 10:40:17 -0500149 if self.discovery_pending():
Brad Bishop732c6db2015-10-19 14:49:21 -0400150 print "ObjectMapper discovery complete..."
Brad Bishopcb7aa602015-11-03 10:40:17 -0500151 self.service = dbus.service.BusName(
152 OpenBMCMapper.MAPPER_NAME, self.bus.dbus)
Brad Bishop732c6db2015-10-19 14:49:21 -0400153
Brad Bishop54d3ec92015-11-03 09:32:34 -0500154 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 's', 'a{sas}')
155 def GetObject(self, path):
Brad Bishop3640ecd2015-11-03 14:46:10 -0500156 o = self.cache.get(path)
157 if not o:
158 raise MapperNotFoundException(path)
159 return o
Brad Bishop732c6db2015-10-19 14:49:21 -0400160
Brad Bishop54d3ec92015-11-03 09:32:34 -0500161 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'as')
162 def GetSubTreePaths(self, path, depth):
Brad Bishop3640ecd2015-11-03 14:46:10 -0500163 try:
164 return self.cache.iterkeys(path, depth)
165 except KeyError:
166 raise MapperNotFoundException(path)
Brad Bishop732c6db2015-10-19 14:49:21 -0400167
Brad Bishop54d3ec92015-11-03 09:32:34 -0500168 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
169 def GetSubTree(self, path, depth):
Brad Bishop3640ecd2015-11-03 14:46:10 -0500170 try:
171 return { x:y for x, y in self.cache.dataitems(path, depth) }
172 except KeyError:
173 raise MapperNotFoundException(path)
Brad Bishop732c6db2015-10-19 14:49:21 -0400174
Brad Bishop732c6db2015-10-19 14:49:21 -0400175class BusWrapper:
176 def __init__(self, bus):
177 self.dbus = bus
178
Brad Bishop5ffc2a32015-11-25 08:46:01 -0500179 def get_owned_name(self, match, bus):
180 for x in self.get_service_names(match):
181 if self.dbus.get_name_owner(x) == bus:
182 return x
183
Brad Bishop732c6db2015-10-19 14:49:21 -0400184 def get_service_names(self, match):
185 # these are well known names
186 return [ x for x in self.dbus.list_names() \
Brad Bishop65b7ceb2015-11-04 23:05:56 -0500187 if match(x) ]
Brad Bishop732c6db2015-10-19 14:49:21 -0400188
189 def get_owner_names(self, match):
190 # these are unique connection names
191 return list( set( [ self.dbus.get_name_owner(x) \
192 for x in self.get_service_names(match) ] ) )
193
Brad Bishop732c6db2015-10-19 14:49:21 -0400194if __name__ == '__main__':
195 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
196 bus = dbus.SystemBus()
Brad Bishop732c6db2015-10-19 14:49:21 -0400197 o = ObjectMapper(BusWrapper(bus), OpenBMCMapper.MAPPER_PATH)
198 loop = gobject.MainLoop()
199
200 loop.run()