blob: 80241052254d84b318eca15877c4847be6c6880b [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
Matt Spinler06e5d2f2018-11-13 10:33:50 -060027# The default D-Bus interfaces that we don't need to get
28# properties on during an enumerate.
29DEFAULT_IFACES = ['org.freedesktop.DBus.Introspectable',
30 'org.freedesktop.DBus.Peer',
31 'org.freedesktop.DBus.Properties']
32
Brad Bishopea2bc0c2016-07-25 09:05:39 -040033
34class Mapper:
35 def __init__(self, bus):
36 self.bus = bus
37 obj = bus.get_object(MAPPER_NAME, MAPPER_PATH, introspect=False)
38 self.iface = dbus.Interface(
39 obj, dbus_interface=MAPPER_IFACE)
40
Brad Bishop1eba37d2016-09-20 08:12:25 -040041 @staticmethod
Lei YU9e94fb62017-01-11 11:23:58 +080042 def retry(func, retries, interval):
Brad Bishop1eba37d2016-09-20 08:12:25 -040043 e = None
44 count = 0
45 while count < retries:
46 try:
47 return func()
Balaji B Rao84e331a2017-11-09 21:19:13 -060048 except dbus.exceptions.DBusException as e:
Matt Spinler3c18b9f2017-01-27 14:41:48 -060049 if e.get_dbus_name() not in \
50 ['org.freedesktop.DBus.Error.ObjectPathInUse',
51 'org.freedesktop.DBus.Error.LimitsExceeded']:
Brad Bishop1eba37d2016-09-20 08:12:25 -040052 raise
Brad Bishopea2bc0c2016-07-25 09:05:39 -040053
Brad Bishop1eba37d2016-09-20 08:12:25 -040054 count += 1
Lei YU9e94fb62017-01-11 11:23:58 +080055 if interval > 0:
56 from time import sleep
57 sleep(interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040058 if e:
59 raise e
Brad Bishopea2bc0c2016-07-25 09:05:39 -040060
Cory Klokmana5513ab2017-01-24 17:27:16 -060061 def get_object(self, path, 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.GetObject(
64 path, interfaces, signature='sas'),
Lei YU9e94fb62017-01-11 11:23:58 +080065 retries, interval)
Brad Bishopea2bc0c2016-07-25 09:05:39 -040066
Adriana Kobylaka1f24222018-01-10 16:09:07 -060067 def get_subtree_paths(
68 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.GetSubTreePaths(
71 path, depth, interfaces, signature='sias'),
Lei YU9e94fb62017-01-11 11:23:58 +080072 retries, interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040073
Adriana Kobylaka1f24222018-01-10 16:09:07 -060074 def get_subtree(
75 self, path='/', depth=0, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040076 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040077 lambda: self.iface.GetSubTree(
78 path, depth, interfaces, signature='sias'),
Lei YU9e94fb62017-01-11 11:23:58 +080079 retries, interval)
Brad Bishop1eba37d2016-09-20 08:12:25 -040080
Cory Klokmana5513ab2017-01-24 17:27:16 -060081 def get_ancestors(self, path, retries=5, interfaces=[], interval=0.2):
Brad Bishop1eba37d2016-09-20 08:12:25 -040082 return self.retry(
Brad Bishopbf464f42016-11-02 00:37:06 -040083 lambda: self.iface.GetAncestors(
84 path, interfaces, signature='sas'),
Lei YU9e94fb62017-01-11 11:23:58 +080085 retries, interval)
Brad Bishopea2bc0c2016-07-25 09:05:39 -040086
87 @staticmethod
88 def __try_properties_interface(f, *a):
89 try:
90 return f(*a)
Balaji B Rao84e331a2017-11-09 21:19:13 -060091 except dbus.exceptions.DBusException as e:
Brad Bishopea2bc0c2016-07-25 09:05:39 -040092 if obmc.dbuslib.enums.DBUS_UNKNOWN_INTERFACE in \
Adriana Kobylaka8f97652017-12-11 13:32:10 -060093 e.get_dbus_name():
Brad Bishopea2bc0c2016-07-25 09:05:39 -040094 # interface doesn't have any properties
95 return None
96 if obmc.dbuslib.enums.DBUS_UNKNOWN_METHOD == e.get_dbus_name():
97 # properties interface not implemented at all
98 return None
99 raise
100
101 @staticmethod
102 def __get_properties_on_iface(properties_iface, iface):
103 properties = Mapper.__try_properties_interface(
104 properties_iface.GetAll, iface)
105 if properties is None:
106 return {}
107 return properties
108
109 def __get_properties_on_bus(self, path, bus, interfaces, match):
110 properties = {}
111 obj = self.bus.get_object(bus, path, introspect=False)
112 properties_iface = dbus.Interface(
113 obj, dbus_interface=dbus.PROPERTIES_IFACE)
114 for i in interfaces:
Brad Bishop8f301732017-09-11 20:09:48 -0400115 if match and not match(i):
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400116 continue
Matt Spinler06e5d2f2018-11-13 10:33:50 -0600117 if i in DEFAULT_IFACES:
118 continue
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400119 properties.update(self.__get_properties_on_iface(
120 properties_iface, i))
121
122 return properties
123
124 def enumerate_object(
125 self, path,
Brad Bishop8f301732017-09-11 20:09:48 -0400126 match=lambda x: x != dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400127 mapper_data=None):
128 if mapper_data is None:
129 mapper_data = {path: self.get_object(path)}
130
131 obj = {}
132
Matt Spinlerb6593862018-05-31 13:12:39 -0500133 for owner, interfaces in mapper_data[path].items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400134 obj.update(
135 self.__get_properties_on_bus(
136 path, owner, interfaces, match))
137
138 return obj
139
140 def enumerate_subtree(
141 self, path='/',
Brad Bishop8f301732017-09-11 20:09:48 -0400142 match=lambda x: x != dbus.BUS_DAEMON_IFACE + '.ObjectManager',
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400143 mapper_data=None):
144 if mapper_data is None:
145 mapper_data = self.get_subtree(path)
146 managers = {}
147 owners = []
148
149 # look for objectmanager implementations as they result
150 # in fewer dbus calls
Matt Spinlerb6593862018-05-31 13:12:39 -0500151 for path, bus_data in mapper_data.items():
152 for owner, interfaces in bus_data.items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400153 owners.append(owner)
154 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces:
155 managers[owner] = path
156
157 # also look in the parent objects
158 ancestors = self.get_ancestors(path)
159
160 # finally check the root for one too
161 try:
162 ancestors.update({path: self.get_object(path)})
Balaji B Rao84e331a2017-11-09 21:19:13 -0600163 except dbus.exceptions.DBusException as e:
Brad Bishop5fd9c472016-07-25 09:09:00 -0400164 if e.get_dbus_name() != MAPPER_NOT_FOUND:
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400165 raise
166
Matt Spinlerb6593862018-05-31 13:12:39 -0500167 for path, bus_data in ancestors.items():
168 for owner, interfaces in bus_data.items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400169 if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces:
170 managers[owner] = path
171
Matt Spinlerb6593862018-05-31 13:12:39 -0500172 mapper_keys = set(mapper_data.keys())
173
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400174 # make all the manager gmo (get managed objects) calls
175 results = {}
Matt Spinlerb6593862018-05-31 13:12:39 -0500176 for owner, path in managers.items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400177 if owner not in owners:
178 continue
179 obj = self.bus.get_object(owner, path, introspect=False)
180 iface = dbus.Interface(
181 obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager')
182
183 # flatten (remove interface names) gmo results
CamVan Nguyen2fd4b1f2018-03-05 12:19:46 -0600184 for path, interfaces in \
Matt Spinlerb6593862018-05-31 13:12:39 -0500185 iface.GetManagedObjects().items():
186 if path not in mapper_keys:
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400187 continue
188 properties = {}
Matt Spinlerb6593862018-05-31 13:12:39 -0500189 for iface, props in interfaces.items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400190 properties.update(props)
191 results.setdefault(path, {}).setdefault(owner, properties)
192
193 # make dbus calls for any remaining objects
Matt Spinlerb6593862018-05-31 13:12:39 -0500194 for path, bus_data in mapper_data.items():
195 for owner, interfaces in bus_data.items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400196 if results.setdefault(path, {}).setdefault(owner, {}):
197 continue
198 results[path][owner].update(
199 self.__get_properties_on_bus(
200 path, owner, interfaces, match))
201
202 objs = obmc.utils.pathtree.PathTree()
Matt Spinlerb6593862018-05-31 13:12:39 -0500203 for path, owners in results.items():
204 for owner, properties in owners.items():
Brad Bishopea2bc0c2016-07-25 09:05:39 -0400205 objs.setdefault(path, {}).update(properties)
206
207 return objs