blob: a7b93b2a2af36ffd24ae47d10b7baf9110032f8f [file] [log] [blame]
Brad Bishopc656a862016-07-25 09:11:41 -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 sys
18import dbus
19import dbus.mainloop.glib
CamVan Nguyen2fd4b1f2018-03-05 12:19:46 -060020# TODO: openbmc/openbmc#2994 remove python 2 support
21try: # python 2
22 import gobject
23except ImportError: # python 3
24 from gi.repository import GObject as gobject
Brad Bishopc656a862016-07-25 09:11:41 -040025import obmc.mapper
26
27
28class Wait(object):
29 def __init__(self, bus, waitlist, *a, **kw):
30 self.bus = bus
Brad Bishopcabc6382018-01-29 15:39:07 -050031 self.waitlist = dict(list(zip(waitlist, [None] * len(waitlist))))
Brad Bishopc656a862016-07-25 09:11:41 -040032 mapper = bus.get_object(
33 obmc.mapper.MAPPER_NAME,
34 obmc.mapper.MAPPER_PATH,
35 introspect=False)
Brad Bishopa5627042016-09-20 16:08:51 -040036 self.iface = dbus.Interface(
Brad Bishopc656a862016-07-25 09:11:41 -040037 mapper, dbus_interface=obmc.mapper.MAPPER_IFACE)
38 self.done = False
39 self.callback = kw.pop('callback', None)
Brad Bishopa5627042016-09-20 16:08:51 -040040 self.error_callback = kw.pop('error_callback', self.default_error)
Lei YU5205b162016-12-21 10:49:09 +080041 self.busy_retries = kw.pop('busy_retries', 20)
Brad Bishopa5627042016-09-20 16:08:51 -040042 self.busy_retry_delay_milliseconds = kw.pop(
Lei YU5205b162016-12-21 10:49:09 +080043 'busy_retry_delay_milliseconds', 500)
Brad Bishopa5627042016-09-20 16:08:51 -040044 self.waitlist_keyword = kw.pop('waitlist_keyword', None)
Brad Bishopc656a862016-07-25 09:11:41 -040045
46 self.bus.add_signal_receiver(
Brad Bishop829181d2017-02-24 09:49:14 -050047 self.introspection_handler,
48 dbus_interface=obmc.mapper.MAPPER_IFACE + '.Private',
49 signal_name='IntrospectionComplete')
Brad Bishopc656a862016-07-25 09:11:41 -040050 self.bus.add_signal_receiver(
Brad Bishop829181d2017-02-24 09:49:14 -050051 self.introspection_handler,
52 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager')
Brad Bishopc656a862016-07-25 09:11:41 -040053
Brad Bishop829181d2017-02-24 09:49:14 -050054 self.introspection_handler()
Brad Bishopa5627042016-09-20 16:08:51 -040055
56 @staticmethod
57 def default_error(e):
58 raise e
59
60 def force_done(self):
61 if self.done:
Brad Bishopc656a862016-07-25 09:11:41 -040062 return
63
64 self.done = True
65 self.bus.remove_signal_receiver(
Brad Bishop829181d2017-02-24 09:49:14 -050066 self.introspection_handler,
67 dbus_interface=obmc.mapper.MAPPER_IFACE + '.Private',
68 signal_name='IntrospectionComplete')
Brad Bishopc656a862016-07-25 09:11:41 -040069 self.bus.remove_signal_receiver(
Brad Bishop829181d2017-02-24 09:49:14 -050070 self.introspection_handler,
Brad Bishopc656a862016-07-25 09:11:41 -040071 dbus_interface=dbus.BUS_DAEMON_IFACE + '.ObjectManager',
72 signal_name='InterfacesAdded')
Brad Bishopa5627042016-09-20 16:08:51 -040073
74 def check_done(self):
75 if not all(self.waitlist.values()) or self.done:
76 return
77
78 self.force_done()
79
Brad Bishopc656a862016-07-25 09:11:41 -040080 if self.callback:
Brad Bishopa5627042016-09-20 16:08:51 -040081 kwargs = {}
82 if self.waitlist_keyword:
83 kwargs[waitlist_keyword] = self.waitlist
84 self.callback(**kwargs)
85
86 def get_object_async(self, path, retry):
87 method = getattr(self.iface, 'GetObject')
88 method.call_async(
89 path,
Brad Bishopbf464f42016-11-02 00:37:06 -040090 [],
91 signature='sas',
Brad Bishopa5627042016-09-20 16:08:51 -040092 reply_handler=lambda x: self.get_object_callback(
93 path, x),
94 error_handler=lambda x: self.get_object_error(
95 path, retry, x))
96 return False
97
98 def get_object_error(self, path, retry, e):
99 if self.done:
100 return
101
102 if e.get_dbus_name() == 'org.freedesktop.DBus.Error.FileNotFound':
103 pass
Matt Spinler3c18b9f2017-01-27 14:41:48 -0600104 elif e.get_dbus_name() in \
105 ['org.freedesktop.DBus.Error.ObjectPathInUse',
106 'org.freedesktop.DBus.Error.LimitsExceeded']:
Brad Bishopa5627042016-09-20 16:08:51 -0400107 if retry > self.busy_retries:
108 self.force_done()
109 self.error_callback(e)
110 else:
111 gobject.timeout_add(
112 self.busy_retry_delay_milliseconds,
113 self.get_object_async,
114 path,
115 retry + 1)
116 else:
117 self.force_done()
118 self.error_callback(e)
Brad Bishopc656a862016-07-25 09:11:41 -0400119
120 def get_object_callback(self, path, info):
121 self.waitlist[path] = list(info)[0]
122 self.check_done()
123
Brad Bishop829181d2017-02-24 09:49:14 -0500124 def introspection_handler(self, *a, **kw):
Brad Bishopc656a862016-07-25 09:11:41 -0400125 if self.done:
126 return
127
Brad Bishopcabc6382018-01-29 15:39:07 -0500128 for path in [
129 x for x in list(self.waitlist.keys()) if not self.waitlist[x]]:
Brad Bishopa5627042016-09-20 16:08:51 -0400130 self.get_object_async(path, 0)