blob: 255897f1942cc57f95fc22fbf5de6dbf335b6939 [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 Bishop4b849412016-02-04 15:40:26 -050027
Brad Bishopae0c0af2015-11-09 18:41:28 -050028class MapperNotFoundException(dbus.exceptions.DBusException):
Brad Bishop4b849412016-02-04 15:40:26 -050029 _dbus_error_name = OpenBMCMapper.MAPPER_NOT_FOUND
30
31 def __init__(self, path):
32 super(MapperNotFoundException, self).__init__(
33 "path or object not found: %s" % (path))
34
Brad Bishopae0c0af2015-11-09 18:41:28 -050035
Brad Bishop732c6db2015-10-19 14:49:21 -040036class ObjectMapper(dbus.service.Object):
Brad Bishop4b849412016-02-04 15:40:26 -050037 def __init__(self, bus, path,
38 name_match=OpenBMCMapper.org_dot_openbmc_match,
39 intf_match=OpenBMCMapper.org_dot_openbmc_match):
40 super(ObjectMapper, self).__init__(bus.dbus, path)
41 self.cache = PathTree()
42 self.bus = bus
43 self.name_match = name_match
44 self.intf_match = intf_match
45 self.tag_match = OpenBMCMapper.ListMatch(['children', 'interface'])
46 self.service = None
Brad Bishop732c6db2015-10-19 14:49:21 -040047
Brad Bishop4b849412016-02-04 15:40:26 -050048 gobject.idle_add(self.discover)
49 self.bus.dbus.add_signal_receiver(
50 self.bus_handler,
51 dbus_interface=
52 dbus.BUS_DAEMON_IFACE,
53 signal_name='NameOwnerChanged')
54 self.bus.dbus.add_signal_receiver(
55 self.interfaces_added_handler,
56 dbus_interface=
57 dbus.BUS_DAEMON_IFACE + '.ObjectManager',
58 signal_name='InterfacesAdded',
59 sender_keyword='sender')
60 self.bus.dbus.add_signal_receiver(
61 self.interfaces_removed_handler,
62 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
63 signal_name='InterfacesRemoved',
64 sender_keyword='sender')
Brad Bishop732c6db2015-10-19 14:49:21 -040065
Brad Bishop4b849412016-02-04 15:40:26 -050066 def bus_match(self, name):
67 if name == OpenBMCMapper.MAPPER_NAME:
68 return False
69 return self.name_match(name)
Brad Bishop65b7ceb2015-11-04 23:05:56 -050070
Brad Bishop4b849412016-02-04 15:40:26 -050071 def discovery_pending(self):
72 return not bool(self.service)
Brad Bishopcb7aa602015-11-03 10:40:17 -050073
Brad Bishop4b849412016-02-04 15:40:26 -050074 def interfaces_added_handler(self, path, iprops, **kw):
75 name = self.bus.get_owned_name(self.bus_match, kw['sender'])
76 if self.discovery_pending() or \
77 not self.bus_match(name):
78 return
Brad Bishop5ffc2a32015-11-25 08:46:01 -050079
Brad Bishop4b849412016-02-04 15:40:26 -050080 matches = [x for x in iprops.iterkeys() if self.intf_match(x)]
81 self.add_interfaces(path, kw['sender'], matches)
Brad Bishop732c6db2015-10-19 14:49:21 -040082
Brad Bishop4b849412016-02-04 15:40:26 -050083 def interfaces_removed_handler(self, path, interfaces, **kw):
84 name = self.bus.get_owned_name(self.bus_match, kw['sender'])
85 if self.discovery_pending() or \
86 not self.bus_match(name):
87 return
88 item = self.cache[path]
89 sender = kw['sender']
90 for x in interfaces:
91 if self.intf_match(x):
92 try:
93 item[sender].remove(x)
94 except ValueError:
95 pass
Brad Bishop54d3ec92015-11-03 09:32:34 -050096
Brad Bishop4b849412016-02-04 15:40:26 -050097 # remove the owner if there aren't any interfaces left
98 if not item[sender]:
99 del item[sender]
Brad Bishop54d3ec92015-11-03 09:32:34 -0500100
Brad Bishop4b849412016-02-04 15:40:26 -0500101 # update if interfaces remain
102 if item:
103 self.cache[path] = item
104 # mark for removal if no interfaces remain
105 elif self.cache.get_children(path):
106 self.cache.demote(path)
107 # delete the entire path if everything is gone
108 else:
109 del self.cache[path]
Brad Bishop732c6db2015-10-19 14:49:21 -0400110
Brad Bishop4b849412016-02-04 15:40:26 -0500111 def process_new_owner(self, name):
112 # unique name
113 return self.discover([IntrospectionParser(name,
114 self.bus.dbus,
115 self.tag_match,
116 self.intf_match)])
Brad Bishop732c6db2015-10-19 14:49:21 -0400117
Brad Bishop4b849412016-02-04 15:40:26 -0500118 def process_old_owner(self, name):
119 for x, y in self.cache.dataitems():
120 if name not in y:
121 continue
122 del y[name]
123 if y:
124 self.cache[x] = y
125 elif self.cache.get_children(x):
126 self.cache.demote(x)
127 else:
128 del self.cache[x]
Brad Bishop732c6db2015-10-19 14:49:21 -0400129
Brad Bishop4b849412016-02-04 15:40:26 -0500130 def bus_handler(self, service, old, new):
131 if self.discovery_pending() or \
132 not self.bus_match(service):
133 return
Brad Bishop732c6db2015-10-19 14:49:21 -0400134
Brad Bishop4b849412016-02-04 15:40:26 -0500135 if new:
136 self.process_new_owner(new)
137 if old:
138 self.process_old_owner(old)
Brad Bishop732c6db2015-10-19 14:49:21 -0400139
Brad Bishop4b849412016-02-04 15:40:26 -0500140 def add_interfaces(self, path, owner, interfaces):
141 d = self.cache.setdefault(path, {})
142 d = d.setdefault(owner, [])
143 self.cache[path][owner] = list(set(d + interfaces))
Brad Bishop86398d22015-10-28 21:58:31 -0400144
Brad Bishop4b849412016-02-04 15:40:26 -0500145 def add_items(self, owner, bus_items):
146 for x, y in bus_items.iteritems():
147 self.add_interfaces(x, owner, y['interfaces'])
Brad Bishop86398d22015-10-28 21:58:31 -0400148
Brad Bishop4b849412016-02-04 15:40:26 -0500149 def discover(self, owners=None):
150 if not owners:
151 owners = [IntrospectionParser(x, self.bus.dbus,
152 self.tag_match,
153 self.intf_match)
154 for x in self.bus.get_owner_names(self.bus_match)]
155 for o in owners:
156 self.add_items(o.name, o.introspect())
Brad Bishop732c6db2015-10-19 14:49:21 -0400157
Brad Bishop4b849412016-02-04 15:40:26 -0500158 if self.discovery_pending():
159 print "ObjectMapper discovery complete..."
160 self.service = dbus.service.BusName(
161 OpenBMCMapper.MAPPER_NAME, self.bus.dbus)
Brad Bishop732c6db2015-10-19 14:49:21 -0400162
Brad Bishop4b849412016-02-04 15:40:26 -0500163 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 's', 'a{sas}')
164 def GetObject(self, path):
165 o = self.cache.get(path)
166 if not o:
167 raise MapperNotFoundException(path)
168 return o
Brad Bishop732c6db2015-10-19 14:49:21 -0400169
Brad Bishop4b849412016-02-04 15:40:26 -0500170 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'as')
171 def GetSubTreePaths(self, path, depth):
172 try:
173 return self.cache.iterkeys(path, depth)
174 except KeyError:
175 raise MapperNotFoundException(path)
Brad Bishop732c6db2015-10-19 14:49:21 -0400176
Brad Bishop4b849412016-02-04 15:40:26 -0500177 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
178 def GetSubTree(self, path, depth):
179 try:
180 return {x: y for x, y in self.cache.dataitems(path, depth)}
181 except KeyError:
182 raise MapperNotFoundException(path)
183
Brad Bishop732c6db2015-10-19 14:49:21 -0400184
Brad Bishop732c6db2015-10-19 14:49:21 -0400185class BusWrapper:
Brad Bishop4b849412016-02-04 15:40:26 -0500186 def __init__(self, bus):
187 self.dbus = bus
Brad Bishop732c6db2015-10-19 14:49:21 -0400188
Brad Bishop4b849412016-02-04 15:40:26 -0500189 def get_owned_name(self, match, bus):
190 for x in self.get_service_names(match):
191 if self.dbus.get_name_owner(x) == bus:
192 return x
Brad Bishop5ffc2a32015-11-25 08:46:01 -0500193
Brad Bishop4b849412016-02-04 15:40:26 -0500194 def get_service_names(self, match):
195 # these are well known names
196 return [x for x in self.dbus.list_names()
197 if match(x)]
Brad Bishop732c6db2015-10-19 14:49:21 -0400198
Brad Bishop4b849412016-02-04 15:40:26 -0500199 def get_owner_names(self, match):
200 # these are unique connection names
201 return list(set(
202 [self.dbus.get_name_owner(x)
203 for x in self.get_service_names(match)]))
Brad Bishop732c6db2015-10-19 14:49:21 -0400204
Brad Bishop732c6db2015-10-19 14:49:21 -0400205if __name__ == '__main__':
Brad Bishop4b849412016-02-04 15:40:26 -0500206 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
207 bus = dbus.SystemBus()
208 o = ObjectMapper(BusWrapper(bus), OpenBMCMapper.MAPPER_PATH)
209 loop = gobject.MainLoop()
Brad Bishop732c6db2015-10-19 14:49:21 -0400210
Brad Bishop4b849412016-02-04 15:40:26 -0500211 loop.run()