blob: 2e2df0adca02fd161db90c15e9e97195473e7ed2 [file] [log] [blame]
Brad Bishopea2bc0c2016-07-25 09:05:39 -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 obmc.dbuslib.enums
19import obmc.utils.misc
20import obmc.utils.pathtree
21
Brad Bishop5fd9c472016-07-25 09:09:00 -040022
Brad Bishopb301f2f2016-10-05 20:02:57 -040023MAPPER_NAME = 'xyz.openbmc_project.ObjectMapper'
Brad Bishopea2bc0c2016-07-25 09:05:39 -040024MAPPER_IFACE = MAPPER_NAME
Leonel Gonzalez7fb0fe92017-03-09 15:27:36 -060025MAPPER_PATH = '/xyz/openbmc_project/object_mapper'
Brad Bishopfba8ea32016-09-20 15:45:18 -040026MAPPER_NOT_FOUND = 'org.freedesktop.DBus.Error.FileNotFound'
Brad Bishopea2bc0c2016-07-25 09:05:39 -040027
28
29class Mapper:
30 def __init__(self, bus):
31 self.bus = bus
32 obj = bus.get_object(MAPPER_NAME, MAPPER_PATH, introspect=False)
33 self.iface = dbus.Interface(
34 obj, dbus_interface=MAPPER_IFACE)
35
Brad Bishop1eba37d2016-09-20 08:12:25 -040036 @staticmethod
Lei YU9e94fb62017-01-11 11:23:58 +080037 def retry(func, retries, interval):
Brad Bishop1eba37d2016-09-20 08:12:25 -040038 e = None
39 count = 0
40 while count < retries:
41 try:
42 return func()
43 except dbus.exceptions.DBusException, e:
Matt Spinler3c18b9f2017-01-27 14:41:48 -060044 if e.get_dbus_name() not in \
45 ['org.freedesktop.DBus.Error.ObjectPathInUse',
46 'org.freedesktop.DBus.Error.LimitsExceeded']:
Brad Bishop1eba37d2016-09-20 08:12:25 -040047 raise
Brad Bishopea2bc0c2016-07-25 09:05:39 -040048
Brad Bishop1eba37d2016-09-20 08:12:25 -040049 count += 1
Lei YU9e94fb62017-01-11 11:23:58 +080050 if interval > 0:
51 from time import sleep
52 sleep(interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040053 if e:
54 raise e
Brad Bishopea2bc0c2016-07-25 09:05:39 -040055
Cory Klokmana5513ab2017-01-24 17:27:16 -060056 def get_object(self, path, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040057 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040058 lambda: self.iface.GetObject(
59 path, interfaces, signature='sas'),
Lei YU9e94fb62017-01-11 11:23:58 +080060 retries, interval)
Brad Bishopea2bc0c2016-07-25 09:05:39 -040061
Cory Klokmana5513ab2017-01-24 17:27:16 -060062 def get_subtree_paths(self, path='/', depth=0, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040063 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040064 lambda: self.iface.GetSubTreePaths(
65 path, depth, interfaces, signature='sias'),
Lei YU9e94fb62017-01-11 11:23:58 +080066 retries, interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040067
Cory Klokmana5513ab2017-01-24 17:27:16 -060068 def get_subtree(self, path='/', depth=0, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040069 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040070 lambda: self.iface.GetSubTree(
71 path, depth, interfaces, signature='sias'),
Lei YU9e94fb62017-01-11 11:23:58 +080072 retries, interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040073
Cory Klokmana5513ab2017-01-24 17:27:16 -060074 def get_ancestors(self, path, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040075 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040076 lambda: self.iface.GetAncestors(
77 path, interfaces, signature='sas'),
Lei YU9e94fb62017-01-11 11:23:58 +080078 retries, interval)
Brad Bishopea2bc0c2016-07-25 09:05:39 -040079
80 @staticmethod
81 def __try_properties_interface(f, *a):
82 try:
83 return f(*a)
84 except dbus.exceptions.DBusException, e:
85 if obmc.dbuslib.enums.DBUS_UNKNOWN_INTERFACE in \
86 e.get_dbus_message():
87 # interface doesn't have any properties
88 return None
89 if obmc.dbuslib.enums.DBUS_UNKNOWN_METHOD == e.get_dbus_name():
90 # properties interface not implemented at all
91 return None
92 raise
93
94 @staticmethod
95 def __get_properties_on_iface(properties_iface, iface):
96 properties = Mapper.__try_properties_interface(
97 properties_iface.GetAll, iface)
98 if properties is None:
99 return {}
100 return properties
101
102 def __get_properties_on_bus(self, path, bus, interfaces, match):
103 properties = {}
104 obj = self.bus.get_object(bus, path, introspect=False)
105 properties_iface = dbus.Interface(
106 obj, dbus_interface=dbus.PROPERTIES_IFACE)
107 for i in interfaces:
108 if not match(i):
109 continue
110 properties.update(self.__get_properties_on_iface(
111 properties_iface, i))
112
113 return properties
114
115 def enumerate_object(
116 self, path,
117 match=obmc.utils.misc.org_dot_openbmc_match,
118 mapper_data=None):
119 if mapper_data is None:
120 mapper_data = {path: self.get_object(path)}
121
122 obj = {}
123
124 for owner, interfaces in mapper_data[path].iteritems():
125 obj.update(
126 self.__get_properties_on_bus(
127 path, owner, interfaces, match))
128
129 return obj
130
131 def enumerate_subtree(
132 self, path='/',
133 match=obmc.utils.misc.org_dot_openbmc_match,
134 mapper_data=None):
135 if mapper_data is None:
136 mapper_data = self.get_subtree(path)
137 managers = {}
138 owners = []
139
140 # look for objectmanager implementations as they result
141 # in fewer dbus calls
142 for path, bus_data in mapper_data.iteritems():
143 for owner, interfaces in bus_data.iteritems():
144 owners.append(owner)
145 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces:
146 managers[owner] = path
147
148 # also look in the parent objects
149 ancestors = self.get_ancestors(path)
150
151 # finally check the root for one too
152 try:
153 ancestors.update({path: self.get_object(path)})
154 except dbus.exceptions.DBusException, e:
Brad Bishop5fd9c472016-07-25 09:09:00 -0400155 if e.get_dbus_name() != MAPPER_NOT_FOUND:
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400156 raise
157
158 for path, bus_data in ancestors.iteritems():
159 for owner, interfaces in bus_data.iteritems():
160 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces:
161 managers[owner] = path
162
163 # make all the manager gmo (get managed objects) calls
164 results = {}
165 for owner, path in managers.iteritems():
166 if owner not in owners:
167 continue
168 obj = self.bus.get_object(owner, path, introspect=False)
169 iface = dbus.Interface(
170 obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager')
171
172 # flatten (remove interface names) gmo results
173 for path, interfaces in iface.GetManagedObjects().iteritems():
174 if path not in mapper_data.iterkeys():
175 continue
176 properties = {}
177 for iface, props in interfaces.iteritems():
178 properties.update(props)
179 results.setdefault(path, {}).setdefault(owner, properties)
180
181 # make dbus calls for any remaining objects
182 for path, bus_data in mapper_data.iteritems():
183 for owner, interfaces in bus_data.iteritems():
184 if results.setdefault(path, {}).setdefault(owner, {}):
185 continue
186 results[path][owner].update(
187 self.__get_properties_on_bus(
188 path, owner, interfaces, match))
189
190 objs = obmc.utils.pathtree.PathTree()
191 for path, owners in results.iteritems():
192 for owner, properties in owners.iteritems():
193 objs.setdefault(path, {}).update(properties)
194
195 return objs