blob: a9afee65f416ac9196aad512b2edd81fd95fa7a6 [file] [log] [blame]
Brad Bishop63f59a72016-07-25 12:05:57 -04001# Contributors Listed Below - COPYRIGHT 2016
2# [+] International Business Machines Corp.
3#
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14# implied. See the License for the specific language governing
15# permissions and limitations under the License.
16
17import dbus
18import dbus.service
19import dbus.exceptions
20import dbus.mainloop.glib
21import gobject
22import xml.etree.ElementTree as ET
23import obmc.utils.pathtree
24import obmc.utils.misc
25import obmc.mapper
26import obmc.dbuslib.bindings
27import obmc.dbuslib.enums
28
29
Brad Bishop2e0436c2016-09-19 18:02:19 -040030class MapperBusyException(dbus.exceptions.DBusException):
31 _dbus_error_name = 'org.freedesktop.DBus.Error.ObjectPathInUse'
32
33 def __init__(self):
34 super(MapperBusyException, self).__init__(
35 'busy processing bus traffic')
36
37
Brad Bishop63f59a72016-07-25 12:05:57 -040038class MapperNotFoundException(dbus.exceptions.DBusException):
39 _dbus_error_name = obmc.mapper.MAPPER_NOT_FOUND
40
41 def __init__(self, path):
42 super(MapperNotFoundException, self).__init__(
43 "path or object not found: %s" % path)
44
45
Brad Bishopbd8aa052016-09-19 09:30:06 -040046def find_dbus_interfaces(conn, service, path, **kw):
47 iface_match = kw.pop('iface_match', bool)
Brad Bishop6a0320b2016-09-19 11:03:06 -040048 subtree_match = kw.pop('subtree_match', bool)
Brad Bishopbd8aa052016-09-19 09:30:06 -040049
Brad Bishop63f59a72016-07-25 12:05:57 -040050 class _FindInterfaces(object):
51 def __init__(self):
52 self.results = {}
53
54 @staticmethod
55 def _get_object(path):
56 try:
57 return conn.get_object(service, path, introspect=False)
58 except dbus.exceptions.DBusException, e:
59 if e.get_dbus_name() in [
60 obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE,
61 obmc.dbuslib.enums.DBUS_NO_REPLY]:
62 print "Warning: Introspection failure: " \
63 "service `%s` is not running" % (service)
64 return None
65 raise
66
67 @staticmethod
Brad Bishop329472a2016-09-08 16:12:14 -040068 def _invoke_method(path, iface, method):
Brad Bishop63f59a72016-07-25 12:05:57 -040069 obj = _FindInterfaces._get_object(path)
70 if not obj:
71 return None
72
73 iface = dbus.Interface(obj, iface)
74 try:
Brad Bishop329472a2016-09-08 16:12:14 -040075 return method(iface)
Brad Bishop63f59a72016-07-25 12:05:57 -040076 except dbus.exceptions.DBusException, e:
77 if e.get_dbus_name() in [
78 obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE,
79 obmc.dbuslib.enums.DBUS_NO_REPLY]:
80 print "Warning: Introspection failure: " \
81 "service `%s` did not reply to "\
82 "method call on %s" % (service, path)
83 return None
84 raise
85
86 @staticmethod
87 def _introspect(path):
88 return _FindInterfaces._invoke_method(
89 path,
90 dbus.INTROSPECTABLE_IFACE,
Brad Bishop329472a2016-09-08 16:12:14 -040091 lambda x: x.Introspect())
Brad Bishop63f59a72016-07-25 12:05:57 -040092
93 @staticmethod
Brad Bishop926b35d2016-09-19 14:20:04 -040094 def _get(path, iface, prop):
95 return _FindInterfaces._invoke_method(
96 path,
97 dbus.PROPERTIES_IFACE,
98 lambda x: x.Get(iface, prop))
99
100 @staticmethod
Brad Bishop63f59a72016-07-25 12:05:57 -0400101 def _get_managed_objects(om):
102 return _FindInterfaces._invoke_method(
103 om,
104 dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishop329472a2016-09-08 16:12:14 -0400105 lambda x: x.GetManagedObjects())
Brad Bishop63f59a72016-07-25 12:05:57 -0400106
107 @staticmethod
108 def _to_path(elements):
109 return '/' + '/'.join(elements)
110
111 @staticmethod
112 def _to_path_elements(path):
113 return filter(bool, path.split('/'))
114
115 def __call__(self, path):
116 self.results = {}
117 self._find_interfaces(path)
118 return self.results
119
120 @staticmethod
121 def _match(iface):
122 return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' \
Brad Bishopbd8aa052016-09-19 09:30:06 -0400123 or iface_match(iface)
Brad Bishop63f59a72016-07-25 12:05:57 -0400124
125 def _find_interfaces(self, path):
126 path_elements = self._to_path_elements(path)
127 path = self._to_path(path_elements)
128 data = self._introspect(path)
129 if data is None:
130 return
131
132 root = ET.fromstring(data)
133 ifaces = filter(
134 self._match,
135 [x.attrib.get('name') for x in root.findall('interface')])
Brad Bishop926b35d2016-09-19 14:20:04 -0400136 ifaces = {x: {} for x in ifaces}
137
138 iface = obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE
139 if iface in ifaces:
140 associations = self._get(
141 path, iface, 'associations')
142 if associations:
143 ifaces[iface]['associations'] = associations
144
Brad Bishop63f59a72016-07-25 12:05:57 -0400145 self.results[path] = ifaces
146
147 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in ifaces:
148 objs = self._get_managed_objects(path)
149 for k, v in objs.iteritems():
150 self.results[k] = v
151 else:
152 children = filter(
153 bool,
154 [x.attrib.get('name') for x in root.findall('node')])
155 children = [
156 self._to_path(
157 path_elements + self._to_path_elements(x))
158 for x in sorted(children)]
Brad Bishop6a0320b2016-09-19 11:03:06 -0400159 for child in filter(subtree_match, children):
Brad Bishop63f59a72016-07-25 12:05:57 -0400160 if child not in self.results:
161 self._find_interfaces(child)
162
163 return _FindInterfaces()(path)
164
165
166class Association(dbus.service.Object):
167 def __init__(self, bus, path, endpoints):
Brad Bishop70dd5952016-09-08 22:33:33 -0400168 super(Association, self).__init__(conn=bus, object_path=path)
Brad Bishop63f59a72016-07-25 12:05:57 -0400169 self.endpoints = endpoints
170
171 def __getattr__(self, name):
172 if name == 'properties':
173 return {
174 obmc.dbuslib.enums.OBMC_ASSOC_IFACE: {
175 'endpoints': self.endpoints}}
176 return super(Association, self).__getattr__(name)
177
178 def emit_signal(self, old):
179 if old != self.endpoints:
180 self.PropertiesChanged(
181 obmc.dbuslib.enums.OBMC_ASSOC_IFACE,
182 {'endpoints': self.endpoints}, ['endpoints'])
183
184 def append(self, endpoints):
185 old = self.endpoints
186 self.endpoints = list(set(endpoints).union(self.endpoints))
187 self.emit_signal(old)
188
189 def remove(self, endpoints):
190 old = self.endpoints
191 self.endpoints = list(set(self.endpoints).difference(endpoints))
192 self.emit_signal(old)
193
194 @dbus.service.method(dbus.PROPERTIES_IFACE, 'ss', 'as')
195 def Get(self, interface_name, property_name):
196 if property_name != 'endpoints':
197 raise dbus.exceptions.DBusException(name=DBUS_UNKNOWN_PROPERTY)
198 return self.GetAll(interface_name)[property_name]
199
200 @dbus.service.method(dbus.PROPERTIES_IFACE, 's', 'a{sas}')
201 def GetAll(self, interface_name):
202 if interface_name != obmc.dbuslib.enums.OBMC_ASSOC_IFACE:
203 raise dbus.exceptions.DBusException(DBUS_UNKNOWN_INTERFACE)
204 return {'endpoints': self.endpoints}
205
206 @dbus.service.signal(
207 dbus.PROPERTIES_IFACE, signature='sa{sas}as')
208 def PropertiesChanged(
209 self, interface_name, changed_properties, invalidated_properties):
210 pass
211
212
213class Manager(obmc.dbuslib.bindings.DbusObjectManager):
214 def __init__(self, bus, path):
Brad Bishop70dd5952016-09-08 22:33:33 -0400215 super(Manager, self).__init__(conn=bus, object_path=path)
Brad Bishop63f59a72016-07-25 12:05:57 -0400216
217
218class ObjectMapper(dbus.service.Object):
219 def __init__(self, bus, path,
Brad Bishop63f59a72016-07-25 12:05:57 -0400220 intf_match=obmc.utils.misc.org_dot_openbmc_match):
221 super(ObjectMapper, self).__init__(bus, path)
222 self.cache = obmc.utils.pathtree.PathTree()
223 self.bus = bus
Brad Bishop63f59a72016-07-25 12:05:57 -0400224 self.intf_match = intf_match
Brad Bishop63f59a72016-07-25 12:05:57 -0400225 self.service = None
226 self.index = {}
227 self.manager = Manager(bus, obmc.dbuslib.bindings.OBJ_PREFIX)
228 self.unique = bus.get_unique_name()
229 self.bus_map = {}
Brad Bishop2e0436c2016-09-19 18:02:19 -0400230 self.defer_signals = {}
Brad Bishop5d4890c2016-09-19 11:28:47 -0400231 self.bus_map[self.unique] = obmc.mapper.MAPPER_NAME
Brad Bishop63f59a72016-07-25 12:05:57 -0400232
Brad Bishop5d4890c2016-09-19 11:28:47 -0400233 # add my object mananger instance
234 self.add_new_objmgr(obmc.dbuslib.bindings.OBJ_PREFIX, self.unique)
235
Brad Bishop63f59a72016-07-25 12:05:57 -0400236 self.bus.add_signal_receiver(
237 self.bus_handler,
238 dbus_interface=dbus.BUS_DAEMON_IFACE,
239 signal_name='NameOwnerChanged')
240 self.bus.add_signal_receiver(
241 self.interfaces_added_handler,
242 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
243 signal_name='InterfacesAdded',
244 sender_keyword='sender',
245 path_keyword='sender_path')
246 self.bus.add_signal_receiver(
247 self.interfaces_removed_handler,
248 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
249 signal_name='InterfacesRemoved',
250 sender_keyword='sender',
251 path_keyword='sender_path')
252 self.bus.add_signal_receiver(
253 self.properties_changed_handler,
254 dbus_interface=dbus.PROPERTIES_IFACE,
255 signal_name='PropertiesChanged',
256 path_keyword='path',
257 sender_keyword='sender')
258
Brad Bishop5d4890c2016-09-19 11:28:47 -0400259 print "ObjectMapper startup complete. Discovery in progress..."
260 self.discover()
261
262 print "ObjectMapper discovery complete"
263 self.service = dbus.service.BusName(
264 obmc.mapper.MAPPER_NAME, self.bus)
Brad Bishop63f59a72016-07-25 12:05:57 -0400265
Brad Bishop2e0436c2016-09-19 18:02:19 -0400266 def discovery_callback(self, owner, items):
267 if owner in self.defer_signals:
268 self.add_items(owner, items)
269 pending = self.defer_signals[owner]
270 del self.defer_signals[owner]
271
272 for x in pending:
273 x()
274
275 def discovery_error(self, owner, path, e):
276 if owner in self.defer_signals:
277 raise e
278
Brad Bishop63f59a72016-07-25 12:05:57 -0400279 def cache_get(self, path):
280 cache_entry = self.cache.get(path, {})
281 if cache_entry is None:
282 # hide path elements without any interfaces
283 cache_entry = {}
284 return cache_entry
285
286 def add_new_objmgr(self, path, owner):
287 # We don't get a signal for the ObjectManager
288 # interface itself, so if we see a signal from
289 # make sure its in our cache, and add it if not.
290 cache_entry = self.cache_get(path)
291 old = self.interfaces_get(cache_entry, owner)
292 new = list(set(old).union([dbus.BUS_DAEMON_IFACE + '.ObjectManager']))
293 self.update_interfaces(path, owner, old, new)
294
Brad Bishop2e0436c2016-09-19 18:02:19 -0400295 def defer_signal(self, owner, callback):
296 self.defer_signals.setdefault(owner, []).append(callback)
297
Brad Bishop63f59a72016-07-25 12:05:57 -0400298 def interfaces_added_handler(self, path, iprops, **kw):
299 path = str(path)
300 owner = str(kw['sender'])
301 interfaces = self.get_signal_interfaces(owner, iprops.iterkeys())
Brad Bishop2e0436c2016-09-19 18:02:19 -0400302 if not interfaces:
303 return
304
305 if owner not in self.defer_signals:
Brad Bishop63f59a72016-07-25 12:05:57 -0400306 self.add_new_objmgr(str(kw['sender_path']), owner)
307 cache_entry = self.cache_get(path)
308 old = self.interfaces_get(cache_entry, owner)
309 new = list(set(interfaces).union(old))
Brad Bishop926b35d2016-09-19 14:20:04 -0400310 new = {x: iprops[x] for x in new}
Brad Bishop63f59a72016-07-25 12:05:57 -0400311 self.update_interfaces(path, owner, old, new)
Brad Bishop2e0436c2016-09-19 18:02:19 -0400312 else:
313 self.defer_signal(
314 owner,
315 lambda: self.interfaces_added_handler(
316 path, iprops, **kw))
Brad Bishop63f59a72016-07-25 12:05:57 -0400317
318 def interfaces_removed_handler(self, path, interfaces, **kw):
319 path = str(path)
320 owner = str(kw['sender'])
321 interfaces = self.get_signal_interfaces(owner, interfaces)
Brad Bishop2e0436c2016-09-19 18:02:19 -0400322 if not interfaces:
323 return
324
325 if owner not in self.defer_signals:
Brad Bishop63f59a72016-07-25 12:05:57 -0400326 self.add_new_objmgr(str(kw['sender_path']), owner)
327 cache_entry = self.cache_get(path)
328 old = self.interfaces_get(cache_entry, owner)
329 new = list(set(old).difference(interfaces))
330 self.update_interfaces(path, owner, old, new)
Brad Bishop2e0436c2016-09-19 18:02:19 -0400331 else:
332 self.defer_signal(
333 owner,
334 lambda: self.interfaces_removed_handler(
335 path, interfaces, **kw))
Brad Bishop63f59a72016-07-25 12:05:57 -0400336
337 def properties_changed_handler(self, interface, new, old, **kw):
338 owner = str(kw['sender'])
339 path = str(kw['path'])
340 interfaces = self.get_signal_interfaces(owner, [interface])
341 if not self.is_association(interfaces):
342 return
343 associations = new.get('associations', None)
344 if associations is None:
345 return
346
Brad Bishop2e0436c2016-09-19 18:02:19 -0400347 if owner not in self.defer_signals:
348 associations = [
349 (str(x), str(y), str(z)) for x, y, z in associations]
350 self.update_associations(
351 path, owner,
352 self.index_get_associations(path, [owner]),
353 associations)
354 else:
355 self.defer_signal(
356 owner,
357 lambda: self.properties_changed_handler(
358 interface, new, old, **kw))
Brad Bishop63f59a72016-07-25 12:05:57 -0400359
360 def process_new_owner(self, owned_name, owner):
361 # unique name
362 try:
363 return self.discover([(owned_name, owner)])
364 except dbus.exceptions.DBusException, e:
365 if obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE \
366 not in e.get_dbus_name():
367 raise
368
369 def process_old_owner(self, owned_name, owner):
370 if owner in self.bus_map:
371 del self.bus_map[owner]
372
373 for path, item in self.cache.dataitems():
374 old = self.interfaces_get(item, owner)
375 # remove all interfaces for this service
376 self.update_interfaces(
377 path, owner, old=old, new=[])
378
379 def bus_handler(self, owned_name, old, new):
380 valid = False
381 if not obmc.dbuslib.bindings.is_unique(owned_name):
382 valid = self.valid_signal(owned_name)
383
384 if valid and new:
385 self.process_new_owner(owned_name, new)
386 if valid and old:
Brad Bishop2e0436c2016-09-19 18:02:19 -0400387 # discard any unhandled signals
388 # or in progress discovery
389 if old in self.defer_signals:
390 del self.defer_signals[old]
391
Brad Bishop63f59a72016-07-25 12:05:57 -0400392 self.process_old_owner(owned_name, old)
393
394 def update_interfaces(self, path, owner, old, new):
395 # __xx -> intf list
396 # xx -> intf dict
397 if isinstance(old, dict):
398 __old = old.keys()
399 else:
400 __old = old
401 old = {x: {} for x in old}
402 if isinstance(new, dict):
403 __new = new.keys()
404 else:
405 __new = new
406 new = {x: {} for x in new}
407
408 cache_entry = self.cache.setdefault(path, {})
409 created = [] if self.has_interfaces(cache_entry) else [path]
410 added = list(set(__new).difference(__old))
411 removed = list(set(__old).difference(__new))
412 self.interfaces_append(cache_entry, owner, added)
413 self.interfaces_remove(cache_entry, owner, removed, path)
414 destroyed = [] if self.has_interfaces(cache_entry) else [path]
415
416 # react to anything that requires association updates
417 new_assoc = []
418 old_assoc = []
419 if self.is_association(added):
Brad Bishop926b35d2016-09-19 14:20:04 -0400420 iface = obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE
421 new_assoc = new[iface]['associations']
Brad Bishop63f59a72016-07-25 12:05:57 -0400422 if self.is_association(removed):
423 old_assoc = self.index_get_associations(path, [owner])
424 self.update_associations(
425 path, owner, old_assoc, new_assoc, created, destroyed)
426
427 def add_items(self, owner, bus_items):
428 for path, items in bus_items.iteritems():
429 self.update_interfaces(path, str(owner), old=[], new=items)
430
431 def discover(self, owners=[]):
432 def match(iface):
433 return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' or \
434 self.intf_match(iface)
Brad Bishop6a0320b2016-09-19 11:03:06 -0400435
436 subtree_match = lambda x: obmc.utils.misc.org_dot_openbmc_match(
437 x, sep='/', prefix='/')
438
Brad Bishop63f59a72016-07-25 12:05:57 -0400439 if not owners:
Brad Bishopd0b8e392016-09-19 11:24:45 -0400440 owned_names = filter(
441 lambda x: not obmc.dbuslib.bindings.is_unique(x),
442 self.bus.list_names())
Brad Bishop63f59a72016-07-25 12:05:57 -0400443 owners = [self.bus.get_name_owner(x) for x in owned_names]
444 owners = zip(owned_names, owners)
445 for owned_name, o in owners:
446 self.add_items(
447 o,
Brad Bishopbd8aa052016-09-19 09:30:06 -0400448 find_dbus_interfaces(
Brad Bishop6a0320b2016-09-19 11:03:06 -0400449 self.bus, o, '/',
450 subtree_match=subtree_match,
451 iface_match=self.intf_match))
Brad Bishop63f59a72016-07-25 12:05:57 -0400452 self.bus_map[o] = owned_name
453
Brad Bishop63f59a72016-07-25 12:05:57 -0400454 def valid_signal(self, name):
Brad Bishop63f59a72016-07-25 12:05:57 -0400455 if obmc.dbuslib.bindings.is_unique(name):
456 name = self.bus_map.get(name)
457
Brad Bishopd0b8e392016-09-19 11:24:45 -0400458 return name is not None and name is not obmc.mapper.MAPPER_NAME
Brad Bishop63f59a72016-07-25 12:05:57 -0400459
460 def get_signal_interfaces(self, owner, interfaces):
461 filtered = []
462 if self.valid_signal(owner):
463 filtered = [str(x) for x in interfaces if self.intf_match(x)]
464
465 return filtered
466
467 @staticmethod
468 def interfaces_get(item, owner, default=[]):
469 return item.get(owner, default)
470
471 @staticmethod
472 def interfaces_append(item, owner, append):
473 interfaces = item.setdefault(owner, [])
474 item[owner] = list(set(append).union(interfaces))
475
476 def interfaces_remove(self, item, owner, remove, path):
477 interfaces = item.get(owner, [])
478 item[owner] = list(set(interfaces).difference(remove))
479
480 if not item[owner]:
481 # remove the owner if there aren't any interfaces left
482 del item[owner]
483
484 if item:
485 # other owners remain
486 return
487
488 if self.cache.get_children(path):
489 # there are still references to this path
490 # from objects further down the tree.
491 # mark it for removal if that changes
492 self.cache.demote(path)
493 else:
494 # delete the entire path if everything is gone
495 del self.cache[path]
496
497 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sas}')
498 def GetObject(self, path):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400499 if len(self.defer_signals):
500 raise MapperBusyException()
501
Brad Bishop63f59a72016-07-25 12:05:57 -0400502 o = self.cache_get(path)
503 if not o:
504 raise MapperNotFoundException(path)
505 return o
506
507 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'as')
508 def GetSubTreePaths(self, path, depth):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400509 if len(self.defer_signals):
510 raise MapperBusyException()
511
Brad Bishop63f59a72016-07-25 12:05:57 -0400512 try:
513 return self.cache.iterkeys(path, depth)
514 except KeyError:
515 raise MapperNotFoundException(path)
516
517 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
518 def GetSubTree(self, path, depth):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400519 if len(self.defer_signals):
520 raise MapperBusyException()
521
Brad Bishop63f59a72016-07-25 12:05:57 -0400522 try:
523 return {x: y for x, y in self.cache.dataitems(path, depth)}
524 except KeyError:
525 raise MapperNotFoundException(path)
526
527 @staticmethod
528 def has_interfaces(item):
529 for owner in item.iterkeys():
530 if ObjectMapper.interfaces_get(item, owner):
531 return True
532 return False
533
534 @staticmethod
535 def is_association(interfaces):
536 return obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE in interfaces
537
538 def index_get(self, index, path, owners):
539 items = []
540 item = self.index.get(index, {})
541 item = item.get(path, {})
542 for o in owners:
543 items.extend(item.get(o, []))
544 return items
545
546 def index_append(self, index, path, owner, assoc):
547 item = self.index.setdefault(index, {})
548 item = item.setdefault(path, {})
549 item = item.setdefault(owner, [])
550 item.append(assoc)
551
552 def index_remove(self, index, path, owner, assoc):
553 index = self.index.get(index, {})
554 owners = index.get(path, {})
555 items = owners.get(owner, [])
556 if assoc in items:
557 items.remove(assoc)
558 if not items:
559 del owners[owner]
560 if not owners:
561 del index[path]
562
Brad Bishop63f59a72016-07-25 12:05:57 -0400563 def index_get_associations(self, path, owners=[], direction='forward'):
564 forward = 'forward' if direction == 'forward' else 'reverse'
565 reverse = 'reverse' if direction == 'forward' else 'forward'
566
567 associations = []
568 if not owners:
569 index = self.index.get(forward, {})
570 owners = index.get(path, {}).keys()
571
572 # f: forward
573 # r: reverse
574 for rassoc in self.index_get(forward, path, owners):
575 elements = rassoc.split('/')
576 rtype = ''.join(elements[-1:])
577 fendpoint = '/'.join(elements[:-1])
578 for fassoc in self.index_get(reverse, fendpoint, owners):
579 elements = fassoc.split('/')
580 ftype = ''.join(elements[-1:])
581 rendpoint = '/'.join(elements[:-1])
582 if rendpoint != path:
583 continue
584 associations.append((ftype, rtype, fendpoint))
585
586 return associations
587
588 def update_association(self, path, removed, added):
589 iface = obmc.dbuslib.enums.OBMC_ASSOC_IFACE
590 create = [] if self.manager.get(path, False) else [iface]
591
592 if added and create:
593 self.manager.add(
594 path, Association(self.bus, path, added))
595 elif added:
596 self.manager.get(path).append(added)
597
598 obj = self.manager.get(path, None)
599 if obj and removed:
600 obj.remove(removed)
601
602 if obj and not obj.endpoints:
603 self.manager.remove(path)
604
605 delete = [] if self.manager.get(path, False) else [iface]
606
607 if create != delete:
608 self.update_interfaces(
609 path, self.unique, delete, create)
610
611 def update_associations(
612 self, path, owner, old, new, created=[], destroyed=[]):
613 added = list(set(new).difference(old))
614 removed = list(set(old).difference(new))
615 for forward, reverse, endpoint in added:
616 # update the index
617 forward_path = str(path + '/' + forward)
618 reverse_path = str(endpoint + '/' + reverse)
619 self.index_append(
620 'forward', path, owner, reverse_path)
621 self.index_append(
622 'reverse', endpoint, owner, forward_path)
623
624 # create the association if the endpoint exists
625 if not self.cache_get(endpoint):
626 continue
627
628 self.update_association(forward_path, [], [endpoint])
629 self.update_association(reverse_path, [], [path])
630
631 for forward, reverse, endpoint in removed:
632 # update the index
633 forward_path = str(path + '/' + forward)
634 reverse_path = str(endpoint + '/' + reverse)
635 self.index_remove(
636 'forward', path, owner, reverse_path)
637 self.index_remove(
638 'reverse', endpoint, owner, forward_path)
639
640 # destroy the association if it exists
641 self.update_association(forward_path, [endpoint], [])
642 self.update_association(reverse_path, [path], [])
643
644 # If the associations interface endpoint comes
645 # or goes create or destroy the appropriate
646 # associations
647 for path in created:
648 for forward, reverse, endpoint in \
649 self.index_get_associations(path, direction='reverse'):
650 forward_path = str(path + '/' + forward)
651 reverse_path = str(endpoint + '/' + reverse)
652 self.update_association(forward_path, [], [endpoint])
653 self.update_association(reverse_path, [], [path])
654
655 for path in destroyed:
656 for forward, reverse, endpoint in \
657 self.index_get_associations(path, direction='reverse'):
658 forward_path = str(path + '/' + forward)
659 reverse_path = str(endpoint + '/' + reverse)
660 self.update_association(forward_path, [endpoint], [])
661 self.update_association(reverse_path, [path], [])
662
663 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sa{sas}}')
664 def GetAncestors(self, path):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400665 if len(self.defer_signals):
666 raise MapperBusyException()
667
Brad Bishop63f59a72016-07-25 12:05:57 -0400668 elements = filter(bool, path.split('/'))
669 paths = []
670 objs = {}
671 while elements:
672 elements.pop()
673 paths.append('/' + '/'.join(elements))
674 if path != '/':
675 paths.append('/')
676
677 for path in paths:
678 obj = self.cache_get(path)
679 if not obj:
680 continue
681 objs[path] = obj
682
683 return objs
684
685
686def server_main():
687 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
688 bus = dbus.SystemBus()
689 o = ObjectMapper(bus, obmc.mapper.MAPPER_PATH)
690 loop = gobject.MainLoop()
691
692 loop.run()