blob: 18edf55e66bff4480d3bdb4129fd645d97a79836 [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 Bishop520473f2016-09-19 21:46:36 -040046def find_dbus_interfaces(conn, service, path, callback, error_callback, **kw):
Brad Bishopbd8aa052016-09-19 09:30:06 -040047 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 = {}
Brad Bishop520473f2016-09-19 21:46:36 -040053 self.introspect_pending = []
54 self.gmo_pending = []
55 self.assoc_pending = []
Brad Bishop63f59a72016-07-25 12:05:57 -040056
57 @staticmethod
58 def _to_path(elements):
59 return '/' + '/'.join(elements)
60
61 @staticmethod
62 def _to_path_elements(path):
63 return filter(bool, path.split('/'))
64
65 def __call__(self, path):
Brad Bishop520473f2016-09-19 21:46:36 -040066 try:
67 self._find_interfaces(path)
68 except Exception, e:
69 error_callback(service, path, e)
Brad Bishop63f59a72016-07-25 12:05:57 -040070
71 @staticmethod
72 def _match(iface):
73 return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' \
Brad Bishopbd8aa052016-09-19 09:30:06 -040074 or iface_match(iface)
Brad Bishop63f59a72016-07-25 12:05:57 -040075
Brad Bishop520473f2016-09-19 21:46:36 -040076 def check_done(self):
77 if any([
78 self.introspect_pending,
79 self.gmo_pending,
80 self.assoc_pending]):
81 return
82
83 callback(service, self.results)
84
85 def _assoc_callback(self, path, associations):
86 try:
87 iface = obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE
88 self.assoc_pending.remove(path)
89 if associations:
90 self.results[path][iface]['associations'] = associations
91 except Exception, e:
92 error_callback(service, path, e)
93 return None
94
95 self.check_done()
96
97 def _gmo_callback(self, path, objs):
98 try:
99 self.gmo_pending.remove(path)
100 for k, v in objs.iteritems():
101 self.results[k] = v
102 except Exception, e:
103 error_callback(service, path, e)
104 return None
105
106 self.check_done()
107
108 def _introspect_callback(self, path, data):
109 self.introspect_pending.remove(path)
110 if data is None:
111 self.check_done()
112 return
113
114 try:
115 path_elements = self._to_path_elements(path)
116 root = ET.fromstring(data)
117 ifaces = filter(
118 self._match,
119 [x.attrib.get('name') for x in root.findall('interface')])
120 ifaces = {x: {} for x in ifaces}
121 self.results[path] = ifaces
122
123 if obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE in ifaces:
124 obj = conn.get_object(service, path, introspect=False)
125 iface = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
126 self.assoc_pending.append(path)
127 iface.Get.call_async(
128 obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE,
129 'associations',
130 reply_handler=lambda x: self._assoc_callback(
131 path, x),
132 error_handler=lambda e: error_callback(
133 service, path, e))
134
135 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in ifaces:
136 obj = conn.get_object(service, path, introspect=False)
137 iface = dbus.Interface(
138 obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager')
139 self.gmo_pending.append(path)
140 iface.GetManagedObjects.call_async(
141 reply_handler=lambda x: self._gmo_callback(
142 path, x),
143 error_handler=lambda e: error_callback(
144 service, path, e))
145 else:
146 children = filter(
147 bool,
148 [x.attrib.get('name') for x in root.findall('node')])
149 children = [
150 self._to_path(
151 path_elements + self._to_path_elements(x))
152 for x in sorted(children)]
153 for child in filter(subtree_match, children):
154 if child not in self.results:
155 self._find_interfaces(child)
156 except Exception, e:
157 error_callback(service, path, e)
158 return None
159
160 self.check_done()
161
Brad Bishop63f59a72016-07-25 12:05:57 -0400162 def _find_interfaces(self, path):
163 path_elements = self._to_path_elements(path)
164 path = self._to_path(path_elements)
Brad Bishop520473f2016-09-19 21:46:36 -0400165 obj = conn.get_object(service, path, introspect=False)
166 iface = dbus.Interface(obj, dbus.INTROSPECTABLE_IFACE)
167 self.introspect_pending.append(path)
168 iface.Introspect.call_async(
169 reply_handler=lambda x: self._introspect_callback(path, x),
170 error_handler=lambda x: error_callback(service, path, x))
Brad Bishop63f59a72016-07-25 12:05:57 -0400171
172 return _FindInterfaces()(path)
173
174
175class Association(dbus.service.Object):
176 def __init__(self, bus, path, endpoints):
Brad Bishop70dd5952016-09-08 22:33:33 -0400177 super(Association, self).__init__(conn=bus, object_path=path)
Brad Bishop63f59a72016-07-25 12:05:57 -0400178 self.endpoints = endpoints
179
180 def __getattr__(self, name):
181 if name == 'properties':
182 return {
183 obmc.dbuslib.enums.OBMC_ASSOC_IFACE: {
184 'endpoints': self.endpoints}}
185 return super(Association, self).__getattr__(name)
186
187 def emit_signal(self, old):
188 if old != self.endpoints:
189 self.PropertiesChanged(
190 obmc.dbuslib.enums.OBMC_ASSOC_IFACE,
191 {'endpoints': self.endpoints}, ['endpoints'])
192
193 def append(self, endpoints):
194 old = self.endpoints
195 self.endpoints = list(set(endpoints).union(self.endpoints))
196 self.emit_signal(old)
197
198 def remove(self, endpoints):
199 old = self.endpoints
200 self.endpoints = list(set(self.endpoints).difference(endpoints))
201 self.emit_signal(old)
202
203 @dbus.service.method(dbus.PROPERTIES_IFACE, 'ss', 'as')
204 def Get(self, interface_name, property_name):
205 if property_name != 'endpoints':
206 raise dbus.exceptions.DBusException(name=DBUS_UNKNOWN_PROPERTY)
207 return self.GetAll(interface_name)[property_name]
208
209 @dbus.service.method(dbus.PROPERTIES_IFACE, 's', 'a{sas}')
210 def GetAll(self, interface_name):
211 if interface_name != obmc.dbuslib.enums.OBMC_ASSOC_IFACE:
212 raise dbus.exceptions.DBusException(DBUS_UNKNOWN_INTERFACE)
213 return {'endpoints': self.endpoints}
214
215 @dbus.service.signal(
216 dbus.PROPERTIES_IFACE, signature='sa{sas}as')
217 def PropertiesChanged(
218 self, interface_name, changed_properties, invalidated_properties):
219 pass
220
221
222class Manager(obmc.dbuslib.bindings.DbusObjectManager):
223 def __init__(self, bus, path):
Brad Bishop70dd5952016-09-08 22:33:33 -0400224 super(Manager, self).__init__(conn=bus, object_path=path)
Brad Bishop63f59a72016-07-25 12:05:57 -0400225
226
227class ObjectMapper(dbus.service.Object):
228 def __init__(self, bus, path,
Brad Bishop63f59a72016-07-25 12:05:57 -0400229 intf_match=obmc.utils.misc.org_dot_openbmc_match):
230 super(ObjectMapper, self).__init__(bus, path)
231 self.cache = obmc.utils.pathtree.PathTree()
232 self.bus = bus
Brad Bishop63f59a72016-07-25 12:05:57 -0400233 self.intf_match = intf_match
Brad Bishop63f59a72016-07-25 12:05:57 -0400234 self.service = None
235 self.index = {}
236 self.manager = Manager(bus, obmc.dbuslib.bindings.OBJ_PREFIX)
237 self.unique = bus.get_unique_name()
238 self.bus_map = {}
Brad Bishop2e0436c2016-09-19 18:02:19 -0400239 self.defer_signals = {}
Brad Bishop5d4890c2016-09-19 11:28:47 -0400240 self.bus_map[self.unique] = obmc.mapper.MAPPER_NAME
Brad Bishop63f59a72016-07-25 12:05:57 -0400241
Brad Bishop5d4890c2016-09-19 11:28:47 -0400242 # add my object mananger instance
243 self.add_new_objmgr(obmc.dbuslib.bindings.OBJ_PREFIX, self.unique)
244
Brad Bishop63f59a72016-07-25 12:05:57 -0400245 self.bus.add_signal_receiver(
246 self.bus_handler,
247 dbus_interface=dbus.BUS_DAEMON_IFACE,
248 signal_name='NameOwnerChanged')
249 self.bus.add_signal_receiver(
250 self.interfaces_added_handler,
251 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
252 signal_name='InterfacesAdded',
253 sender_keyword='sender',
254 path_keyword='sender_path')
255 self.bus.add_signal_receiver(
256 self.interfaces_removed_handler,
257 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
258 signal_name='InterfacesRemoved',
259 sender_keyword='sender',
260 path_keyword='sender_path')
261 self.bus.add_signal_receiver(
262 self.properties_changed_handler,
263 dbus_interface=dbus.PROPERTIES_IFACE,
264 signal_name='PropertiesChanged',
265 path_keyword='path',
266 sender_keyword='sender')
267
Brad Bishop5d4890c2016-09-19 11:28:47 -0400268 print "ObjectMapper startup complete. Discovery in progress..."
269 self.discover()
Brad Bishop520473f2016-09-19 21:46:36 -0400270 gobject.idle_add(self.claim_name)
Brad Bishop5d4890c2016-09-19 11:28:47 -0400271
Brad Bishop520473f2016-09-19 21:46:36 -0400272 def claim_name(self):
273 if len(self.defer_signals):
274 return True
Brad Bishop5d4890c2016-09-19 11:28:47 -0400275 print "ObjectMapper discovery complete"
276 self.service = dbus.service.BusName(
277 obmc.mapper.MAPPER_NAME, self.bus)
Brad Bishop520473f2016-09-19 21:46:36 -0400278 return False
Brad Bishop63f59a72016-07-25 12:05:57 -0400279
Brad Bishop2e0436c2016-09-19 18:02:19 -0400280 def discovery_callback(self, owner, items):
281 if owner in self.defer_signals:
282 self.add_items(owner, items)
283 pending = self.defer_signals[owner]
284 del self.defer_signals[owner]
285
286 for x in pending:
287 x()
288
289 def discovery_error(self, owner, path, e):
290 if owner in self.defer_signals:
291 raise e
292
Brad Bishop63f59a72016-07-25 12:05:57 -0400293 def cache_get(self, path):
294 cache_entry = self.cache.get(path, {})
295 if cache_entry is None:
296 # hide path elements without any interfaces
297 cache_entry = {}
298 return cache_entry
299
300 def add_new_objmgr(self, path, owner):
301 # We don't get a signal for the ObjectManager
302 # interface itself, so if we see a signal from
303 # make sure its in our cache, and add it if not.
304 cache_entry = self.cache_get(path)
305 old = self.interfaces_get(cache_entry, owner)
306 new = list(set(old).union([dbus.BUS_DAEMON_IFACE + '.ObjectManager']))
307 self.update_interfaces(path, owner, old, new)
308
Brad Bishop2e0436c2016-09-19 18:02:19 -0400309 def defer_signal(self, owner, callback):
310 self.defer_signals.setdefault(owner, []).append(callback)
311
Brad Bishop63f59a72016-07-25 12:05:57 -0400312 def interfaces_added_handler(self, path, iprops, **kw):
313 path = str(path)
314 owner = str(kw['sender'])
315 interfaces = self.get_signal_interfaces(owner, iprops.iterkeys())
Brad Bishop2e0436c2016-09-19 18:02:19 -0400316 if not interfaces:
317 return
318
319 if owner not in self.defer_signals:
Brad Bishop63f59a72016-07-25 12:05:57 -0400320 self.add_new_objmgr(str(kw['sender_path']), owner)
321 cache_entry = self.cache_get(path)
322 old = self.interfaces_get(cache_entry, owner)
323 new = list(set(interfaces).union(old))
Brad Bishop926b35d2016-09-19 14:20:04 -0400324 new = {x: iprops[x] for x in new}
Brad Bishop63f59a72016-07-25 12:05:57 -0400325 self.update_interfaces(path, owner, old, new)
Brad Bishop2e0436c2016-09-19 18:02:19 -0400326 else:
327 self.defer_signal(
328 owner,
329 lambda: self.interfaces_added_handler(
330 path, iprops, **kw))
Brad Bishop63f59a72016-07-25 12:05:57 -0400331
332 def interfaces_removed_handler(self, path, interfaces, **kw):
333 path = str(path)
334 owner = str(kw['sender'])
335 interfaces = self.get_signal_interfaces(owner, interfaces)
Brad Bishop2e0436c2016-09-19 18:02:19 -0400336 if not interfaces:
337 return
338
339 if owner not in self.defer_signals:
Brad Bishop63f59a72016-07-25 12:05:57 -0400340 self.add_new_objmgr(str(kw['sender_path']), owner)
341 cache_entry = self.cache_get(path)
342 old = self.interfaces_get(cache_entry, owner)
343 new = list(set(old).difference(interfaces))
344 self.update_interfaces(path, owner, old, new)
Brad Bishop2e0436c2016-09-19 18:02:19 -0400345 else:
346 self.defer_signal(
347 owner,
348 lambda: self.interfaces_removed_handler(
349 path, interfaces, **kw))
Brad Bishop63f59a72016-07-25 12:05:57 -0400350
351 def properties_changed_handler(self, interface, new, old, **kw):
352 owner = str(kw['sender'])
353 path = str(kw['path'])
354 interfaces = self.get_signal_interfaces(owner, [interface])
355 if not self.is_association(interfaces):
356 return
357 associations = new.get('associations', None)
358 if associations is None:
359 return
360
Brad Bishop2e0436c2016-09-19 18:02:19 -0400361 if owner not in self.defer_signals:
362 associations = [
363 (str(x), str(y), str(z)) for x, y, z in associations]
364 self.update_associations(
365 path, owner,
366 self.index_get_associations(path, [owner]),
367 associations)
368 else:
369 self.defer_signal(
370 owner,
371 lambda: self.properties_changed_handler(
372 interface, new, old, **kw))
Brad Bishop63f59a72016-07-25 12:05:57 -0400373
374 def process_new_owner(self, owned_name, owner):
375 # unique name
376 try:
377 return self.discover([(owned_name, owner)])
378 except dbus.exceptions.DBusException, e:
379 if obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE \
380 not in e.get_dbus_name():
381 raise
382
383 def process_old_owner(self, owned_name, owner):
384 if owner in self.bus_map:
385 del self.bus_map[owner]
386
387 for path, item in self.cache.dataitems():
388 old = self.interfaces_get(item, owner)
389 # remove all interfaces for this service
390 self.update_interfaces(
391 path, owner, old=old, new=[])
392
393 def bus_handler(self, owned_name, old, new):
394 valid = False
395 if not obmc.dbuslib.bindings.is_unique(owned_name):
396 valid = self.valid_signal(owned_name)
397
398 if valid and new:
399 self.process_new_owner(owned_name, new)
400 if valid and old:
Brad Bishop2e0436c2016-09-19 18:02:19 -0400401 # discard any unhandled signals
402 # or in progress discovery
403 if old in self.defer_signals:
404 del self.defer_signals[old]
405
Brad Bishop63f59a72016-07-25 12:05:57 -0400406 self.process_old_owner(owned_name, old)
407
408 def update_interfaces(self, path, owner, old, new):
409 # __xx -> intf list
410 # xx -> intf dict
411 if isinstance(old, dict):
412 __old = old.keys()
413 else:
414 __old = old
415 old = {x: {} for x in old}
416 if isinstance(new, dict):
417 __new = new.keys()
418 else:
419 __new = new
420 new = {x: {} for x in new}
421
422 cache_entry = self.cache.setdefault(path, {})
423 created = [] if self.has_interfaces(cache_entry) else [path]
424 added = list(set(__new).difference(__old))
425 removed = list(set(__old).difference(__new))
426 self.interfaces_append(cache_entry, owner, added)
427 self.interfaces_remove(cache_entry, owner, removed, path)
428 destroyed = [] if self.has_interfaces(cache_entry) else [path]
429
430 # react to anything that requires association updates
431 new_assoc = []
432 old_assoc = []
433 if self.is_association(added):
Brad Bishop926b35d2016-09-19 14:20:04 -0400434 iface = obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE
435 new_assoc = new[iface]['associations']
Brad Bishop63f59a72016-07-25 12:05:57 -0400436 if self.is_association(removed):
437 old_assoc = self.index_get_associations(path, [owner])
438 self.update_associations(
439 path, owner, old_assoc, new_assoc, created, destroyed)
440
441 def add_items(self, owner, bus_items):
442 for path, items in bus_items.iteritems():
443 self.update_interfaces(path, str(owner), old=[], new=items)
444
445 def discover(self, owners=[]):
446 def match(iface):
447 return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' or \
448 self.intf_match(iface)
Brad Bishop6a0320b2016-09-19 11:03:06 -0400449
450 subtree_match = lambda x: obmc.utils.misc.org_dot_openbmc_match(
451 x, sep='/', prefix='/')
452
Brad Bishop63f59a72016-07-25 12:05:57 -0400453 if not owners:
Brad Bishopd0b8e392016-09-19 11:24:45 -0400454 owned_names = filter(
455 lambda x: not obmc.dbuslib.bindings.is_unique(x),
456 self.bus.list_names())
Brad Bishop63f59a72016-07-25 12:05:57 -0400457 owners = [self.bus.get_name_owner(x) for x in owned_names]
458 owners = zip(owned_names, owners)
459 for owned_name, o in owners:
Brad Bishop63f59a72016-07-25 12:05:57 -0400460 self.bus_map[o] = owned_name
Brad Bishop520473f2016-09-19 21:46:36 -0400461 self.defer_signals[o] = []
462 find_dbus_interfaces(
463 self.bus, o, '/',
464 self.discovery_callback,
465 self.discovery_error,
466 subtree_match=subtree_match,
467 iface_match=self.intf_match)
Brad Bishop63f59a72016-07-25 12:05:57 -0400468
Brad Bishop63f59a72016-07-25 12:05:57 -0400469 def valid_signal(self, name):
Brad Bishop63f59a72016-07-25 12:05:57 -0400470 if obmc.dbuslib.bindings.is_unique(name):
471 name = self.bus_map.get(name)
472
Brad Bishopd0b8e392016-09-19 11:24:45 -0400473 return name is not None and name is not obmc.mapper.MAPPER_NAME
Brad Bishop63f59a72016-07-25 12:05:57 -0400474
475 def get_signal_interfaces(self, owner, interfaces):
476 filtered = []
477 if self.valid_signal(owner):
478 filtered = [str(x) for x in interfaces if self.intf_match(x)]
479
480 return filtered
481
482 @staticmethod
483 def interfaces_get(item, owner, default=[]):
484 return item.get(owner, default)
485
486 @staticmethod
487 def interfaces_append(item, owner, append):
488 interfaces = item.setdefault(owner, [])
489 item[owner] = list(set(append).union(interfaces))
490
491 def interfaces_remove(self, item, owner, remove, path):
492 interfaces = item.get(owner, [])
493 item[owner] = list(set(interfaces).difference(remove))
494
495 if not item[owner]:
496 # remove the owner if there aren't any interfaces left
497 del item[owner]
498
499 if item:
500 # other owners remain
501 return
502
503 if self.cache.get_children(path):
504 # there are still references to this path
505 # from objects further down the tree.
506 # mark it for removal if that changes
507 self.cache.demote(path)
508 else:
509 # delete the entire path if everything is gone
510 del self.cache[path]
511
512 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sas}')
513 def GetObject(self, path):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400514 if len(self.defer_signals):
515 raise MapperBusyException()
516
Brad Bishop63f59a72016-07-25 12:05:57 -0400517 o = self.cache_get(path)
518 if not o:
519 raise MapperNotFoundException(path)
520 return o
521
522 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'as')
523 def GetSubTreePaths(self, path, depth):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400524 if len(self.defer_signals):
525 raise MapperBusyException()
526
Brad Bishop63f59a72016-07-25 12:05:57 -0400527 try:
528 return self.cache.iterkeys(path, depth)
529 except KeyError:
530 raise MapperNotFoundException(path)
531
532 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
533 def GetSubTree(self, path, depth):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400534 if len(self.defer_signals):
535 raise MapperBusyException()
536
Brad Bishop63f59a72016-07-25 12:05:57 -0400537 try:
538 return {x: y for x, y in self.cache.dataitems(path, depth)}
539 except KeyError:
540 raise MapperNotFoundException(path)
541
542 @staticmethod
543 def has_interfaces(item):
544 for owner in item.iterkeys():
545 if ObjectMapper.interfaces_get(item, owner):
546 return True
547 return False
548
549 @staticmethod
550 def is_association(interfaces):
551 return obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE in interfaces
552
553 def index_get(self, index, path, owners):
554 items = []
555 item = self.index.get(index, {})
556 item = item.get(path, {})
557 for o in owners:
558 items.extend(item.get(o, []))
559 return items
560
561 def index_append(self, index, path, owner, assoc):
562 item = self.index.setdefault(index, {})
563 item = item.setdefault(path, {})
564 item = item.setdefault(owner, [])
565 item.append(assoc)
566
567 def index_remove(self, index, path, owner, assoc):
568 index = self.index.get(index, {})
569 owners = index.get(path, {})
570 items = owners.get(owner, [])
571 if assoc in items:
572 items.remove(assoc)
573 if not items:
574 del owners[owner]
575 if not owners:
576 del index[path]
577
Brad Bishop63f59a72016-07-25 12:05:57 -0400578 def index_get_associations(self, path, owners=[], direction='forward'):
579 forward = 'forward' if direction == 'forward' else 'reverse'
580 reverse = 'reverse' if direction == 'forward' else 'forward'
581
582 associations = []
583 if not owners:
584 index = self.index.get(forward, {})
585 owners = index.get(path, {}).keys()
586
587 # f: forward
588 # r: reverse
589 for rassoc in self.index_get(forward, path, owners):
590 elements = rassoc.split('/')
591 rtype = ''.join(elements[-1:])
592 fendpoint = '/'.join(elements[:-1])
593 for fassoc in self.index_get(reverse, fendpoint, owners):
594 elements = fassoc.split('/')
595 ftype = ''.join(elements[-1:])
596 rendpoint = '/'.join(elements[:-1])
597 if rendpoint != path:
598 continue
599 associations.append((ftype, rtype, fendpoint))
600
601 return associations
602
603 def update_association(self, path, removed, added):
604 iface = obmc.dbuslib.enums.OBMC_ASSOC_IFACE
605 create = [] if self.manager.get(path, False) else [iface]
606
607 if added and create:
608 self.manager.add(
609 path, Association(self.bus, path, added))
610 elif added:
611 self.manager.get(path).append(added)
612
613 obj = self.manager.get(path, None)
614 if obj and removed:
615 obj.remove(removed)
616
617 if obj and not obj.endpoints:
618 self.manager.remove(path)
619
620 delete = [] if self.manager.get(path, False) else [iface]
621
622 if create != delete:
623 self.update_interfaces(
624 path, self.unique, delete, create)
625
626 def update_associations(
627 self, path, owner, old, new, created=[], destroyed=[]):
628 added = list(set(new).difference(old))
629 removed = list(set(old).difference(new))
630 for forward, reverse, endpoint in added:
631 # update the index
632 forward_path = str(path + '/' + forward)
633 reverse_path = str(endpoint + '/' + reverse)
634 self.index_append(
635 'forward', path, owner, reverse_path)
636 self.index_append(
637 'reverse', endpoint, owner, forward_path)
638
639 # create the association if the endpoint exists
640 if not self.cache_get(endpoint):
641 continue
642
643 self.update_association(forward_path, [], [endpoint])
644 self.update_association(reverse_path, [], [path])
645
646 for forward, reverse, endpoint in removed:
647 # update the index
648 forward_path = str(path + '/' + forward)
649 reverse_path = str(endpoint + '/' + reverse)
650 self.index_remove(
651 'forward', path, owner, reverse_path)
652 self.index_remove(
653 'reverse', endpoint, owner, forward_path)
654
655 # destroy the association if it exists
656 self.update_association(forward_path, [endpoint], [])
657 self.update_association(reverse_path, [path], [])
658
659 # If the associations interface endpoint comes
660 # or goes create or destroy the appropriate
661 # associations
662 for path in created:
663 for forward, reverse, endpoint in \
664 self.index_get_associations(path, direction='reverse'):
665 forward_path = str(path + '/' + forward)
666 reverse_path = str(endpoint + '/' + reverse)
667 self.update_association(forward_path, [], [endpoint])
668 self.update_association(reverse_path, [], [path])
669
670 for path in destroyed:
671 for forward, reverse, endpoint in \
672 self.index_get_associations(path, direction='reverse'):
673 forward_path = str(path + '/' + forward)
674 reverse_path = str(endpoint + '/' + reverse)
675 self.update_association(forward_path, [endpoint], [])
676 self.update_association(reverse_path, [path], [])
677
678 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sa{sas}}')
679 def GetAncestors(self, path):
Brad Bishop2e0436c2016-09-19 18:02:19 -0400680 if len(self.defer_signals):
681 raise MapperBusyException()
682
Brad Bishop63f59a72016-07-25 12:05:57 -0400683 elements = filter(bool, path.split('/'))
684 paths = []
685 objs = {}
686 while elements:
687 elements.pop()
688 paths.append('/' + '/'.join(elements))
689 if path != '/':
690 paths.append('/')
691
692 for path in paths:
693 obj = self.cache_get(path)
694 if not obj:
695 continue
696 objs[path] = obj
697
698 return objs
699
700
701def server_main():
702 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
703 bus = dbus.SystemBus()
704 o = ObjectMapper(bus, obmc.mapper.MAPPER_PATH)
705 loop = gobject.MainLoop()
706
707 loop.run()