blob: e61a39cb94eb5fdc7f73c2db275fa258584ded7d [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
Brad Bishopea2bc0c2016-07-25 09:05:39 -040019import obmc.utils.pathtree
20
Brad Bishop5fd9c472016-07-25 09:09:00 -040021
Brad Bishopb301f2f2016-10-05 20:02:57 -040022MAPPER_NAME = 'xyz.openbmc_project.ObjectMapper'
Brad Bishopea2bc0c2016-07-25 09:05:39 -040023MAPPER_IFACE = MAPPER_NAME
Leonel Gonzalez7fb0fe92017-03-09 15:27:36 -060024MAPPER_PATH = '/xyz/openbmc_project/object_mapper'
Brad Bishopfba8ea32016-09-20 15:45:18 -040025MAPPER_NOT_FOUND = 'org.freedesktop.DBus.Error.FileNotFound'
Brad Bishopea2bc0c2016-07-25 09:05:39 -040026
27
28class Mapper:
29 def __init__(self, bus):
30 self.bus = bus
31 obj = bus.get_object(MAPPER_NAME, MAPPER_PATH, introspect=False)
32 self.iface = dbus.Interface(
33 obj, dbus_interface=MAPPER_IFACE)
34
Brad Bishop1eba37d2016-09-20 08:12:25 -040035 @staticmethod
Lei YU9e94fb62017-01-11 11:23:58 +080036 def retry(func, retries, interval):
Brad Bishop1eba37d2016-09-20 08:12:25 -040037 e = None
38 count = 0
39 while count < retries:
40 try:
41 return func()
42 except dbus.exceptions.DBusException, e:
Matt Spinler3c18b9f2017-01-27 14:41:48 -060043 if e.get_dbus_name() not in \
44 ['org.freedesktop.DBus.Error.ObjectPathInUse',
45 'org.freedesktop.DBus.Error.LimitsExceeded']:
Brad Bishop1eba37d2016-09-20 08:12:25 -040046 raise
Brad Bishopea2bc0c2016-07-25 09:05:39 -040047
Brad Bishop1eba37d2016-09-20 08:12:25 -040048 count += 1
Lei YU9e94fb62017-01-11 11:23:58 +080049 if interval > 0:
50 from time import sleep
51 sleep(interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040052 if e:
53 raise e
Brad Bishopea2bc0c2016-07-25 09:05:39 -040054
Cory Klokmana5513ab2017-01-24 17:27:16 -060055 def get_object(self, path, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040056 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040057 lambda: self.iface.GetObject(
58 path, interfaces, signature='sas'),
Lei YU9e94fb62017-01-11 11:23:58 +080059 retries, interval)
Brad Bishopea2bc0c2016-07-25 09:05:39 -040060
Cory Klokmana5513ab2017-01-24 17:27:16 -060061 def get_subtree_paths(self, path='/', depth=0, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040062 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040063 lambda: self.iface.GetSubTreePaths(
64 path, depth, interfaces, signature='sias'),
Lei YU9e94fb62017-01-11 11:23:58 +080065 retries, interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040066
Cory Klokmana5513ab2017-01-24 17:27:16 -060067 def get_subtree(self, path='/', depth=0, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040068 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040069 lambda: self.iface.GetSubTree(
70 path, depth, interfaces, signature='sias'),
Lei YU9e94fb62017-01-11 11:23:58 +080071 retries, interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040072
Cory Klokmana5513ab2017-01-24 17:27:16 -060073 def get_ancestors(self, path, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040074 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040075 lambda: self.iface.GetAncestors(
76 path, interfaces, signature='sas'),
Lei YU9e94fb62017-01-11 11:23:58 +080077 retries, interval)
Brad Bishopea2bc0c2016-07-25 09:05:39 -040078
79 @staticmethod
80 def __try_properties_interface(f, *a):
81 try:
82 return f(*a)
83 except dbus.exceptions.DBusException, e:
84 if obmc.dbuslib.enums.DBUS_UNKNOWN_INTERFACE in \
85 e.get_dbus_message():
86 # interface doesn't have any properties
87 return None
88 if obmc.dbuslib.enums.DBUS_UNKNOWN_METHOD == e.get_dbus_name():
89 # properties interface not implemented at all
90 return None
91 raise
92
93 @staticmethod
94 def __get_properties_on_iface(properties_iface, iface):
95 properties = Mapper.__try_properties_interface(
96 properties_iface.GetAll, iface)
97 if properties is None:
98 return {}
99 return properties
100
101 def __get_properties_on_bus(self, path, bus, interfaces, match):
102 properties = {}
103 obj = self.bus.get_object(bus, path, introspect=False)
104 properties_iface = dbus.Interface(
105 obj, dbus_interface=dbus.PROPERTIES_IFACE)
106 for i in interfaces:
Brad Bishop8f301732017-09-11 20:09:48 -0400107 if match and not match(i):
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400108 continue
109 properties.update(self.__get_properties_on_iface(
110 properties_iface, i))
111
112 return properties
113
114 def enumerate_object(
115 self, path,
Brad Bishop8f301732017-09-11 20:09:48 -0400116 match=lambda x: x != dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400117 mapper_data=None):
118 if mapper_data is None:
119 mapper_data = {path: self.get_object(path)}
120
121 obj = {}
122
123 for owner, interfaces in mapper_data[path].iteritems():
124 obj.update(
125 self.__get_properties_on_bus(
126 path, owner, interfaces, match))
127
128 return obj
129
130 def enumerate_subtree(
131 self, path='/',
Brad Bishop8f301732017-09-11 20:09:48 -0400132 match=lambda x: x != dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400133 mapper_data=None):
134 if mapper_data is None:
135 mapper_data = self.get_subtree(path)
136 managers = {}
137 owners = []
138
139 # look for objectmanager implementations as they result
140 # in fewer dbus calls
141 for path, bus_data in mapper_data.iteritems():
142 for owner, interfaces in bus_data.iteritems():
143 owners.append(owner)
144 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces:
145 managers[owner] = path
146
147 # also look in the parent objects
148 ancestors = self.get_ancestors(path)
149
150 # finally check the root for one too
151 try:
152 ancestors.update({path: self.get_object(path)})
153 except dbus.exceptions.DBusException, e:
Brad Bishop5fd9c472016-07-25 09:09:00 -0400154 if e.get_dbus_name() != MAPPER_NOT_FOUND:
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400155 raise
156
157 for path, bus_data in ancestors.iteritems():
158 for owner, interfaces in bus_data.iteritems():
159 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces:
160 managers[owner] = path
161
162 # make all the manager gmo (get managed objects) calls
163 results = {}
164 for owner, path in managers.iteritems():
165 if owner not in owners:
166 continue
167 obj = self.bus.get_object(owner, path, introspect=False)
168 iface = dbus.Interface(
169 obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager')
170
171 # flatten (remove interface names) gmo results
172 for path, interfaces in iface.GetManagedObjects().iteritems():
173 if path not in mapper_data.iterkeys():
174 continue
175 properties = {}
176 for iface, props in interfaces.iteritems():
177 properties.update(props)
178 results.setdefault(path, {}).setdefault(owner, properties)
179
180 # make dbus calls for any remaining objects
181 for path, bus_data in mapper_data.iteritems():
182 for owner, interfaces in bus_data.iteritems():
183 if results.setdefault(path, {}).setdefault(owner, {}):
184 continue
185 results[path][owner].update(
186 self.__get_properties_on_bus(
187 path, owner, interfaces, match))
188
189 objs = obmc.utils.pathtree.PathTree()
190 for path, owners in results.iteritems():
191 for owner, properties in owners.iteritems():
192 objs.setdefault(path, {}).update(properties)
193
194 return objs