blob: 1415e2437b18160a03609f58d1eb34dc132fff15 [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
19import sys
20import dbus
21import dbus.service
22import dbus.mainloop.glib
23import gobject
Brad Bishop54d3ec92015-11-03 09:32:34 -050024from OpenBMCMapper import Path, IntrospectionParser, PathTree
Brad Bishop732c6db2015-10-19 14:49:21 -040025import OpenBMCMapper
26
Brad Bishop732c6db2015-10-19 14:49:21 -040027class ObjectMapper(dbus.service.Object):
28 def __init__(self, bus, path,
Brad Bishop6fb84612015-11-01 00:06:24 -040029 name_match = OpenBMCMapper.org_dot_openbmc_match,
30 intf_match = OpenBMCMapper.org_dot_openbmc_match):
Brad Bishop732c6db2015-10-19 14:49:21 -040031 super(ObjectMapper, self).__init__(bus.dbus, path)
Brad Bishop54d3ec92015-11-03 09:32:34 -050032 self.cache = PathTree()
Brad Bishop732c6db2015-10-19 14:49:21 -040033 self.bus = bus
34 self.name_match = name_match
35 self.intf_match = intf_match
Brad Bishopa8e752f2015-11-03 09:24:48 -050036 self.tag_match = OpenBMCMapper.ListMatch(['children', 'interface'])
Brad Bishop6fb84612015-11-01 00:06:24 -040037
Brad Bishop732c6db2015-10-19 14:49:21 -040038 self.discovery_done = False
39
40 gobject.idle_add(self.discover)
41 self.bus.dbus.add_signal_receiver(self.bus_handler,
42 dbus_interface = dbus.BUS_DAEMON_IFACE,
43 signal_name = 'NameOwnerChanged')
44 self.bus.dbus.add_signal_receiver(self.interfaces_added_handler,
45 dbus_interface = dbus.BUS_DAEMON_IFACE + '.ObjectManager',
46 signal_name = 'InterfaceesAdded',
47 sender_keyword = 'sender')
48 self.bus.dbus.add_signal_receiver(self.interfaces_removed_handler,
49 dbus_interface = dbus.BUS_DAEMON_IFACE + '.ObjectManager',
50 signal_name = 'InterfacesRemoved',
51 sender_keyword = 'sender')
52
53 def interfaces_added_handler(self, path, iprops, **kw):
Brad Bishop54d3ec92015-11-03 09:32:34 -050054 matches = [ x for x in iprops.iterkeys() if self.intf_match(x) ]
55 d = self.cache.setdefault(path, {})
56 d[path].setdefault(kw['sender'], []).extend(matches)
57 self.cache[path] = d
Brad Bishop732c6db2015-10-19 14:49:21 -040058
59 def interfaces_removed_handler(self, path, interfaces, **kw):
Brad Bishop54d3ec92015-11-03 09:32:34 -050060 item = self.cache[path]
61 name = kw['sender']
Brad Bishop732c6db2015-10-19 14:49:21 -040062 for x in interfaces:
Brad Bishop54d3ec92015-11-03 09:32:34 -050063 item[name].remove(x)
64
65 # remove the owner if there aren't any interfaces left
66 if not item[name]:
67 del item[name]
68
69 # update if interfaces remain
70 if item:
71 self.cache[path] = item
72 # mark for removal if no interfaces remain
73 elif self.cache.get_children(item):
74 self.cache.demote(item)
75 # delete the entire path if everything is gone
76 else:
77 del self.cache[path]
Brad Bishop732c6db2015-10-19 14:49:21 -040078
79 def process_new_owner(self, name):
80 # unique name
Brad Bishop6fb84612015-11-01 00:06:24 -040081 return self.discover([ IntrospectionParser(name,
82 self.bus.dbus, self.tag_match, self.intf_match) ])
Brad Bishop732c6db2015-10-19 14:49:21 -040083
84 def process_old_owner(self, name):
Brad Bishop54d3ec92015-11-03 09:32:34 -050085 for x,y in self.cache.dataitems():
86 if name not in y:
87 continue
88 del y[name]
89 if y:
90 self.cache[x] = y
91 elif self.cache.get_children(x):
92 self.cache.demote(x)
93 else:
94 del self.cache[x]
Brad Bishop732c6db2015-10-19 14:49:21 -040095
96 def bus_handler(self, service, old, new):
97 if not self.discovery_done or \
Brad Bishop6fb84612015-11-01 00:06:24 -040098 not self.name_match(service):
Brad Bishop732c6db2015-10-19 14:49:21 -040099 return
100
101 if new:
102 self.process_new_owner(new)
103 if old:
104 self.process_old_owner(old)
105
Brad Bishop54d3ec92015-11-03 09:32:34 -0500106 def add_interfaces(self, path, owner, interfaces):
107 d = self.cache.setdefault(path, { })
108 d.setdefault(owner, []).extend(interfaces)
109 self.cache[path] = d
Brad Bishop86398d22015-10-28 21:58:31 -0400110
Brad Bishop6fb84612015-11-01 00:06:24 -0400111 def add_items(self, owner, bus_items):
Brad Bishop86398d22015-10-28 21:58:31 -0400112 for x,y in bus_items.iteritems():
Brad Bishop54d3ec92015-11-03 09:32:34 -0500113 self.add_interfaces(x, owner, y['interfaces'])
Brad Bishop86398d22015-10-28 21:58:31 -0400114
Brad Bishop732c6db2015-10-19 14:49:21 -0400115 def discover(self, owners = None):
116 discovery = not self.discovery_done
117 if not owners:
Brad Bishop6fb84612015-11-01 00:06:24 -0400118 owners = [ IntrospectionParser(x, self.bus.dbus,
119 self.tag_match, self.intf_match) \
120 for x in self.bus.get_owner_names(self.name_match) ]
Brad Bishop732c6db2015-10-19 14:49:21 -0400121 self.discovery_done = True
122 for o in owners:
Brad Bishop6fb84612015-11-01 00:06:24 -0400123 self.add_items(o.name, o.introspect())
Brad Bishop732c6db2015-10-19 14:49:21 -0400124
125 if discovery:
126 print "ObjectMapper discovery complete..."
127
Brad Bishop54d3ec92015-11-03 09:32:34 -0500128 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 's', 'a{sas}')
129 def GetObject(self, path):
130 return self.cache[path]
Brad Bishop732c6db2015-10-19 14:49:21 -0400131
Brad Bishop54d3ec92015-11-03 09:32:34 -0500132 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'as')
133 def GetSubTreePaths(self, path, depth):
134 return self.cache.iterkeys(path, depth)
Brad Bishop732c6db2015-10-19 14:49:21 -0400135
Brad Bishop54d3ec92015-11-03 09:32:34 -0500136 @dbus.service.method(OpenBMCMapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
137 def GetSubTree(self, path, depth):
138 return { x:y for x, y in self.cache.dataitems(path, depth) }
Brad Bishop732c6db2015-10-19 14:49:21 -0400139
Brad Bishop732c6db2015-10-19 14:49:21 -0400140class BusWrapper:
141 def __init__(self, bus):
142 self.dbus = bus
143
144 def get_service_names(self, match):
145 # these are well known names
146 return [ x for x in self.dbus.list_names() \
Brad Bishop6fb84612015-11-01 00:06:24 -0400147 if match(x) and x != OpenBMCMapper.MAPPER_NAME ]
Brad Bishop732c6db2015-10-19 14:49:21 -0400148
149 def get_owner_names(self, match):
150 # these are unique connection names
151 return list( set( [ self.dbus.get_name_owner(x) \
152 for x in self.get_service_names(match) ] ) )
153
Brad Bishop732c6db2015-10-19 14:49:21 -0400154if __name__ == '__main__':
155 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
156 bus = dbus.SystemBus()
157 s = dbus.service.BusName(OpenBMCMapper.MAPPER_NAME, bus)
158 o = ObjectMapper(BusWrapper(bus), OpenBMCMapper.MAPPER_PATH)
159 loop = gobject.MainLoop()
160
161 loop.run()