blob: 0120de5d8976f5109e77a04a67c80e532d081008 [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
30class MapperNotFoundException(dbus.exceptions.DBusException):
31 _dbus_error_name = obmc.mapper.MAPPER_NOT_FOUND
32
33 def __init__(self, path):
34 super(MapperNotFoundException, self).__init__(
35 "path or object not found: %s" % path)
36
37
Brad Bishopbd8aa052016-09-19 09:30:06 -040038def find_dbus_interfaces(conn, service, path, **kw):
39 iface_match = kw.pop('iface_match', bool)
Brad Bishop6a0320b2016-09-19 11:03:06 -040040 subtree_match = kw.pop('subtree_match', bool)
Brad Bishopbd8aa052016-09-19 09:30:06 -040041
Brad Bishop63f59a72016-07-25 12:05:57 -040042 class _FindInterfaces(object):
43 def __init__(self):
44 self.results = {}
45
46 @staticmethod
47 def _get_object(path):
48 try:
49 return conn.get_object(service, path, introspect=False)
50 except dbus.exceptions.DBusException, e:
51 if e.get_dbus_name() in [
52 obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE,
53 obmc.dbuslib.enums.DBUS_NO_REPLY]:
54 print "Warning: Introspection failure: " \
55 "service `%s` is not running" % (service)
56 return None
57 raise
58
59 @staticmethod
Brad Bishop329472a2016-09-08 16:12:14 -040060 def _invoke_method(path, iface, method):
Brad Bishop63f59a72016-07-25 12:05:57 -040061 obj = _FindInterfaces._get_object(path)
62 if not obj:
63 return None
64
65 iface = dbus.Interface(obj, iface)
66 try:
Brad Bishop329472a2016-09-08 16:12:14 -040067 return method(iface)
Brad Bishop63f59a72016-07-25 12:05:57 -040068 except dbus.exceptions.DBusException, e:
69 if e.get_dbus_name() in [
70 obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE,
71 obmc.dbuslib.enums.DBUS_NO_REPLY]:
72 print "Warning: Introspection failure: " \
73 "service `%s` did not reply to "\
74 "method call on %s" % (service, path)
75 return None
76 raise
77
78 @staticmethod
79 def _introspect(path):
80 return _FindInterfaces._invoke_method(
81 path,
82 dbus.INTROSPECTABLE_IFACE,
Brad Bishop329472a2016-09-08 16:12:14 -040083 lambda x: x.Introspect())
Brad Bishop63f59a72016-07-25 12:05:57 -040084
85 @staticmethod
Brad Bishop926b35d2016-09-19 14:20:04 -040086 def _get(path, iface, prop):
87 return _FindInterfaces._invoke_method(
88 path,
89 dbus.PROPERTIES_IFACE,
90 lambda x: x.Get(iface, prop))
91
92 @staticmethod
Brad Bishop63f59a72016-07-25 12:05:57 -040093 def _get_managed_objects(om):
94 return _FindInterfaces._invoke_method(
95 om,
96 dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishop329472a2016-09-08 16:12:14 -040097 lambda x: x.GetManagedObjects())
Brad Bishop63f59a72016-07-25 12:05:57 -040098
99 @staticmethod
100 def _to_path(elements):
101 return '/' + '/'.join(elements)
102
103 @staticmethod
104 def _to_path_elements(path):
105 return filter(bool, path.split('/'))
106
107 def __call__(self, path):
108 self.results = {}
109 self._find_interfaces(path)
110 return self.results
111
112 @staticmethod
113 def _match(iface):
114 return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' \
Brad Bishopbd8aa052016-09-19 09:30:06 -0400115 or iface_match(iface)
Brad Bishop63f59a72016-07-25 12:05:57 -0400116
117 def _find_interfaces(self, path):
118 path_elements = self._to_path_elements(path)
119 path = self._to_path(path_elements)
120 data = self._introspect(path)
121 if data is None:
122 return
123
124 root = ET.fromstring(data)
125 ifaces = filter(
126 self._match,
127 [x.attrib.get('name') for x in root.findall('interface')])
Brad Bishop926b35d2016-09-19 14:20:04 -0400128 ifaces = {x: {} for x in ifaces}
129
130 iface = obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE
131 if iface in ifaces:
132 associations = self._get(
133 path, iface, 'associations')
134 if associations:
135 ifaces[iface]['associations'] = associations
136
Brad Bishop63f59a72016-07-25 12:05:57 -0400137 self.results[path] = ifaces
138
139 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in ifaces:
140 objs = self._get_managed_objects(path)
141 for k, v in objs.iteritems():
142 self.results[k] = v
143 else:
144 children = filter(
145 bool,
146 [x.attrib.get('name') for x in root.findall('node')])
147 children = [
148 self._to_path(
149 path_elements + self._to_path_elements(x))
150 for x in sorted(children)]
Brad Bishop6a0320b2016-09-19 11:03:06 -0400151 for child in filter(subtree_match, children):
Brad Bishop63f59a72016-07-25 12:05:57 -0400152 if child not in self.results:
153 self._find_interfaces(child)
154
155 return _FindInterfaces()(path)
156
157
158class Association(dbus.service.Object):
159 def __init__(self, bus, path, endpoints):
Brad Bishop70dd5952016-09-08 22:33:33 -0400160 super(Association, self).__init__(conn=bus, object_path=path)
Brad Bishop63f59a72016-07-25 12:05:57 -0400161 self.endpoints = endpoints
162
163 def __getattr__(self, name):
164 if name == 'properties':
165 return {
166 obmc.dbuslib.enums.OBMC_ASSOC_IFACE: {
167 'endpoints': self.endpoints}}
168 return super(Association, self).__getattr__(name)
169
170 def emit_signal(self, old):
171 if old != self.endpoints:
172 self.PropertiesChanged(
173 obmc.dbuslib.enums.OBMC_ASSOC_IFACE,
174 {'endpoints': self.endpoints}, ['endpoints'])
175
176 def append(self, endpoints):
177 old = self.endpoints
178 self.endpoints = list(set(endpoints).union(self.endpoints))
179 self.emit_signal(old)
180
181 def remove(self, endpoints):
182 old = self.endpoints
183 self.endpoints = list(set(self.endpoints).difference(endpoints))
184 self.emit_signal(old)
185
186 @dbus.service.method(dbus.PROPERTIES_IFACE, 'ss', 'as')
187 def Get(self, interface_name, property_name):
188 if property_name != 'endpoints':
189 raise dbus.exceptions.DBusException(name=DBUS_UNKNOWN_PROPERTY)
190 return self.GetAll(interface_name)[property_name]
191
192 @dbus.service.method(dbus.PROPERTIES_IFACE, 's', 'a{sas}')
193 def GetAll(self, interface_name):
194 if interface_name != obmc.dbuslib.enums.OBMC_ASSOC_IFACE:
195 raise dbus.exceptions.DBusException(DBUS_UNKNOWN_INTERFACE)
196 return {'endpoints': self.endpoints}
197
198 @dbus.service.signal(
199 dbus.PROPERTIES_IFACE, signature='sa{sas}as')
200 def PropertiesChanged(
201 self, interface_name, changed_properties, invalidated_properties):
202 pass
203
204
205class Manager(obmc.dbuslib.bindings.DbusObjectManager):
206 def __init__(self, bus, path):
Brad Bishop70dd5952016-09-08 22:33:33 -0400207 super(Manager, self).__init__(conn=bus, object_path=path)
Brad Bishop63f59a72016-07-25 12:05:57 -0400208
209
210class ObjectMapper(dbus.service.Object):
211 def __init__(self, bus, path,
Brad Bishop63f59a72016-07-25 12:05:57 -0400212 intf_match=obmc.utils.misc.org_dot_openbmc_match):
213 super(ObjectMapper, self).__init__(bus, path)
214 self.cache = obmc.utils.pathtree.PathTree()
215 self.bus = bus
Brad Bishop63f59a72016-07-25 12:05:57 -0400216 self.intf_match = intf_match
Brad Bishop63f59a72016-07-25 12:05:57 -0400217 self.service = None
218 self.index = {}
219 self.manager = Manager(bus, obmc.dbuslib.bindings.OBJ_PREFIX)
220 self.unique = bus.get_unique_name()
221 self.bus_map = {}
Brad Bishop5d4890c2016-09-19 11:28:47 -0400222 self.bus_map[self.unique] = obmc.mapper.MAPPER_NAME
Brad Bishop63f59a72016-07-25 12:05:57 -0400223
Brad Bishop5d4890c2016-09-19 11:28:47 -0400224 # add my object mananger instance
225 self.add_new_objmgr(obmc.dbuslib.bindings.OBJ_PREFIX, self.unique)
226
Brad Bishop63f59a72016-07-25 12:05:57 -0400227 self.bus.add_signal_receiver(
228 self.bus_handler,
229 dbus_interface=dbus.BUS_DAEMON_IFACE,
230 signal_name='NameOwnerChanged')
231 self.bus.add_signal_receiver(
232 self.interfaces_added_handler,
233 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
234 signal_name='InterfacesAdded',
235 sender_keyword='sender',
236 path_keyword='sender_path')
237 self.bus.add_signal_receiver(
238 self.interfaces_removed_handler,
239 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
240 signal_name='InterfacesRemoved',
241 sender_keyword='sender',
242 path_keyword='sender_path')
243 self.bus.add_signal_receiver(
244 self.properties_changed_handler,
245 dbus_interface=dbus.PROPERTIES_IFACE,
246 signal_name='PropertiesChanged',
247 path_keyword='path',
248 sender_keyword='sender')
249
Brad Bishop5d4890c2016-09-19 11:28:47 -0400250 print "ObjectMapper startup complete. Discovery in progress..."
251 self.discover()
252
253 print "ObjectMapper discovery complete"
254 self.service = dbus.service.BusName(
255 obmc.mapper.MAPPER_NAME, self.bus)
Brad Bishop63f59a72016-07-25 12:05:57 -0400256
257 def cache_get(self, path):
258 cache_entry = self.cache.get(path, {})
259 if cache_entry is None:
260 # hide path elements without any interfaces
261 cache_entry = {}
262 return cache_entry
263
264 def add_new_objmgr(self, path, owner):
265 # We don't get a signal for the ObjectManager
266 # interface itself, so if we see a signal from
267 # make sure its in our cache, and add it if not.
268 cache_entry = self.cache_get(path)
269 old = self.interfaces_get(cache_entry, owner)
270 new = list(set(old).union([dbus.BUS_DAEMON_IFACE + '.ObjectManager']))
271 self.update_interfaces(path, owner, old, new)
272
273 def interfaces_added_handler(self, path, iprops, **kw):
274 path = str(path)
275 owner = str(kw['sender'])
276 interfaces = self.get_signal_interfaces(owner, iprops.iterkeys())
277 if interfaces:
278 self.add_new_objmgr(str(kw['sender_path']), owner)
279 cache_entry = self.cache_get(path)
280 old = self.interfaces_get(cache_entry, owner)
281 new = list(set(interfaces).union(old))
Brad Bishop926b35d2016-09-19 14:20:04 -0400282 new = {x: iprops[x] for x in new}
Brad Bishop63f59a72016-07-25 12:05:57 -0400283 self.update_interfaces(path, owner, old, new)
284
285 def interfaces_removed_handler(self, path, interfaces, **kw):
286 path = str(path)
287 owner = str(kw['sender'])
288 interfaces = self.get_signal_interfaces(owner, interfaces)
289 if interfaces:
290 self.add_new_objmgr(str(kw['sender_path']), owner)
291 cache_entry = self.cache_get(path)
292 old = self.interfaces_get(cache_entry, owner)
293 new = list(set(old).difference(interfaces))
294 self.update_interfaces(path, owner, old, new)
295
296 def properties_changed_handler(self, interface, new, old, **kw):
297 owner = str(kw['sender'])
298 path = str(kw['path'])
299 interfaces = self.get_signal_interfaces(owner, [interface])
300 if not self.is_association(interfaces):
301 return
302 associations = new.get('associations', None)
303 if associations is None:
304 return
305
306 associations = [
307 (str(x), str(y), str(z)) for x, y, z in associations]
308 self.update_associations(
309 path, owner,
310 self.index_get_associations(path, [owner]),
311 associations)
312
313 def process_new_owner(self, owned_name, owner):
314 # unique name
315 try:
316 return self.discover([(owned_name, owner)])
317 except dbus.exceptions.DBusException, e:
318 if obmc.dbuslib.enums.DBUS_UNKNOWN_SERVICE \
319 not in e.get_dbus_name():
320 raise
321
322 def process_old_owner(self, owned_name, owner):
323 if owner in self.bus_map:
324 del self.bus_map[owner]
325
326 for path, item in self.cache.dataitems():
327 old = self.interfaces_get(item, owner)
328 # remove all interfaces for this service
329 self.update_interfaces(
330 path, owner, old=old, new=[])
331
332 def bus_handler(self, owned_name, old, new):
333 valid = False
334 if not obmc.dbuslib.bindings.is_unique(owned_name):
335 valid = self.valid_signal(owned_name)
336
337 if valid and new:
338 self.process_new_owner(owned_name, new)
339 if valid and old:
340 self.process_old_owner(owned_name, old)
341
342 def update_interfaces(self, path, owner, old, new):
343 # __xx -> intf list
344 # xx -> intf dict
345 if isinstance(old, dict):
346 __old = old.keys()
347 else:
348 __old = old
349 old = {x: {} for x in old}
350 if isinstance(new, dict):
351 __new = new.keys()
352 else:
353 __new = new
354 new = {x: {} for x in new}
355
356 cache_entry = self.cache.setdefault(path, {})
357 created = [] if self.has_interfaces(cache_entry) else [path]
358 added = list(set(__new).difference(__old))
359 removed = list(set(__old).difference(__new))
360 self.interfaces_append(cache_entry, owner, added)
361 self.interfaces_remove(cache_entry, owner, removed, path)
362 destroyed = [] if self.has_interfaces(cache_entry) else [path]
363
364 # react to anything that requires association updates
365 new_assoc = []
366 old_assoc = []
367 if self.is_association(added):
Brad Bishop926b35d2016-09-19 14:20:04 -0400368 iface = obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE
369 new_assoc = new[iface]['associations']
Brad Bishop63f59a72016-07-25 12:05:57 -0400370 if self.is_association(removed):
371 old_assoc = self.index_get_associations(path, [owner])
372 self.update_associations(
373 path, owner, old_assoc, new_assoc, created, destroyed)
374
375 def add_items(self, owner, bus_items):
376 for path, items in bus_items.iteritems():
377 self.update_interfaces(path, str(owner), old=[], new=items)
378
379 def discover(self, owners=[]):
380 def match(iface):
381 return iface == dbus.BUS_DAEMON_IFACE + '.ObjectManager' or \
382 self.intf_match(iface)
Brad Bishop6a0320b2016-09-19 11:03:06 -0400383
384 subtree_match = lambda x: obmc.utils.misc.org_dot_openbmc_match(
385 x, sep='/', prefix='/')
386
Brad Bishop63f59a72016-07-25 12:05:57 -0400387 if not owners:
Brad Bishopd0b8e392016-09-19 11:24:45 -0400388 owned_names = filter(
389 lambda x: not obmc.dbuslib.bindings.is_unique(x),
390 self.bus.list_names())
Brad Bishop63f59a72016-07-25 12:05:57 -0400391 owners = [self.bus.get_name_owner(x) for x in owned_names]
392 owners = zip(owned_names, owners)
393 for owned_name, o in owners:
394 self.add_items(
395 o,
Brad Bishopbd8aa052016-09-19 09:30:06 -0400396 find_dbus_interfaces(
Brad Bishop6a0320b2016-09-19 11:03:06 -0400397 self.bus, o, '/',
398 subtree_match=subtree_match,
399 iface_match=self.intf_match))
Brad Bishop63f59a72016-07-25 12:05:57 -0400400 self.bus_map[o] = owned_name
401
Brad Bishop63f59a72016-07-25 12:05:57 -0400402 def valid_signal(self, name):
Brad Bishop63f59a72016-07-25 12:05:57 -0400403 if obmc.dbuslib.bindings.is_unique(name):
404 name = self.bus_map.get(name)
405
Brad Bishopd0b8e392016-09-19 11:24:45 -0400406 return name is not None and name is not obmc.mapper.MAPPER_NAME
Brad Bishop63f59a72016-07-25 12:05:57 -0400407
408 def get_signal_interfaces(self, owner, interfaces):
409 filtered = []
410 if self.valid_signal(owner):
411 filtered = [str(x) for x in interfaces if self.intf_match(x)]
412
413 return filtered
414
415 @staticmethod
416 def interfaces_get(item, owner, default=[]):
417 return item.get(owner, default)
418
419 @staticmethod
420 def interfaces_append(item, owner, append):
421 interfaces = item.setdefault(owner, [])
422 item[owner] = list(set(append).union(interfaces))
423
424 def interfaces_remove(self, item, owner, remove, path):
425 interfaces = item.get(owner, [])
426 item[owner] = list(set(interfaces).difference(remove))
427
428 if not item[owner]:
429 # remove the owner if there aren't any interfaces left
430 del item[owner]
431
432 if item:
433 # other owners remain
434 return
435
436 if self.cache.get_children(path):
437 # there are still references to this path
438 # from objects further down the tree.
439 # mark it for removal if that changes
440 self.cache.demote(path)
441 else:
442 # delete the entire path if everything is gone
443 del self.cache[path]
444
445 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sas}')
446 def GetObject(self, path):
447 o = self.cache_get(path)
448 if not o:
449 raise MapperNotFoundException(path)
450 return o
451
452 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'as')
453 def GetSubTreePaths(self, path, depth):
454 try:
455 return self.cache.iterkeys(path, depth)
456 except KeyError:
457 raise MapperNotFoundException(path)
458
459 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 'si', 'a{sa{sas}}')
460 def GetSubTree(self, path, depth):
461 try:
462 return {x: y for x, y in self.cache.dataitems(path, depth)}
463 except KeyError:
464 raise MapperNotFoundException(path)
465
466 @staticmethod
467 def has_interfaces(item):
468 for owner in item.iterkeys():
469 if ObjectMapper.interfaces_get(item, owner):
470 return True
471 return False
472
473 @staticmethod
474 def is_association(interfaces):
475 return obmc.dbuslib.enums.OBMC_ASSOCIATIONS_IFACE in interfaces
476
477 def index_get(self, index, path, owners):
478 items = []
479 item = self.index.get(index, {})
480 item = item.get(path, {})
481 for o in owners:
482 items.extend(item.get(o, []))
483 return items
484
485 def index_append(self, index, path, owner, assoc):
486 item = self.index.setdefault(index, {})
487 item = item.setdefault(path, {})
488 item = item.setdefault(owner, [])
489 item.append(assoc)
490
491 def index_remove(self, index, path, owner, assoc):
492 index = self.index.get(index, {})
493 owners = index.get(path, {})
494 items = owners.get(owner, [])
495 if assoc in items:
496 items.remove(assoc)
497 if not items:
498 del owners[owner]
499 if not owners:
500 del index[path]
501
Brad Bishop63f59a72016-07-25 12:05:57 -0400502 def index_get_associations(self, path, owners=[], direction='forward'):
503 forward = 'forward' if direction == 'forward' else 'reverse'
504 reverse = 'reverse' if direction == 'forward' else 'forward'
505
506 associations = []
507 if not owners:
508 index = self.index.get(forward, {})
509 owners = index.get(path, {}).keys()
510
511 # f: forward
512 # r: reverse
513 for rassoc in self.index_get(forward, path, owners):
514 elements = rassoc.split('/')
515 rtype = ''.join(elements[-1:])
516 fendpoint = '/'.join(elements[:-1])
517 for fassoc in self.index_get(reverse, fendpoint, owners):
518 elements = fassoc.split('/')
519 ftype = ''.join(elements[-1:])
520 rendpoint = '/'.join(elements[:-1])
521 if rendpoint != path:
522 continue
523 associations.append((ftype, rtype, fendpoint))
524
525 return associations
526
527 def update_association(self, path, removed, added):
528 iface = obmc.dbuslib.enums.OBMC_ASSOC_IFACE
529 create = [] if self.manager.get(path, False) else [iface]
530
531 if added and create:
532 self.manager.add(
533 path, Association(self.bus, path, added))
534 elif added:
535 self.manager.get(path).append(added)
536
537 obj = self.manager.get(path, None)
538 if obj and removed:
539 obj.remove(removed)
540
541 if obj and not obj.endpoints:
542 self.manager.remove(path)
543
544 delete = [] if self.manager.get(path, False) else [iface]
545
546 if create != delete:
547 self.update_interfaces(
548 path, self.unique, delete, create)
549
550 def update_associations(
551 self, path, owner, old, new, created=[], destroyed=[]):
552 added = list(set(new).difference(old))
553 removed = list(set(old).difference(new))
554 for forward, reverse, endpoint in added:
555 # update the index
556 forward_path = str(path + '/' + forward)
557 reverse_path = str(endpoint + '/' + reverse)
558 self.index_append(
559 'forward', path, owner, reverse_path)
560 self.index_append(
561 'reverse', endpoint, owner, forward_path)
562
563 # create the association if the endpoint exists
564 if not self.cache_get(endpoint):
565 continue
566
567 self.update_association(forward_path, [], [endpoint])
568 self.update_association(reverse_path, [], [path])
569
570 for forward, reverse, endpoint in removed:
571 # update the index
572 forward_path = str(path + '/' + forward)
573 reverse_path = str(endpoint + '/' + reverse)
574 self.index_remove(
575 'forward', path, owner, reverse_path)
576 self.index_remove(
577 'reverse', endpoint, owner, forward_path)
578
579 # destroy the association if it exists
580 self.update_association(forward_path, [endpoint], [])
581 self.update_association(reverse_path, [path], [])
582
583 # If the associations interface endpoint comes
584 # or goes create or destroy the appropriate
585 # associations
586 for path in created:
587 for forward, reverse, endpoint in \
588 self.index_get_associations(path, direction='reverse'):
589 forward_path = str(path + '/' + forward)
590 reverse_path = str(endpoint + '/' + reverse)
591 self.update_association(forward_path, [], [endpoint])
592 self.update_association(reverse_path, [], [path])
593
594 for path in destroyed:
595 for forward, reverse, endpoint in \
596 self.index_get_associations(path, direction='reverse'):
597 forward_path = str(path + '/' + forward)
598 reverse_path = str(endpoint + '/' + reverse)
599 self.update_association(forward_path, [endpoint], [])
600 self.update_association(reverse_path, [path], [])
601
602 @dbus.service.method(obmc.mapper.MAPPER_IFACE, 's', 'a{sa{sas}}')
603 def GetAncestors(self, path):
604 elements = filter(bool, path.split('/'))
605 paths = []
606 objs = {}
607 while elements:
608 elements.pop()
609 paths.append('/' + '/'.join(elements))
610 if path != '/':
611 paths.append('/')
612
613 for path in paths:
614 obj = self.cache_get(path)
615 if not obj:
616 continue
617 objs[path] = obj
618
619 return objs
620
621
622def server_main():
623 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
624 bus = dbus.SystemBus()
625 o = ObjectMapper(bus, obmc.mapper.MAPPER_PATH)
626 loop = gobject.MainLoop()
627
628 loop.run()