Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 1 | # 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 | |
| 17 | import dbus |
| 18 | import obmc.dbuslib.enums |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 19 | import obmc.utils.pathtree |
| 20 | |
Brad Bishop | 5fd9c47 | 2016-07-25 09:09:00 -0400 | [diff] [blame] | 21 | |
Brad Bishop | b301f2f | 2016-10-05 20:02:57 -0400 | [diff] [blame] | 22 | MAPPER_NAME = 'xyz.openbmc_project.ObjectMapper' |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 23 | MAPPER_IFACE = MAPPER_NAME |
Leonel Gonzalez | 7fb0fe9 | 2017-03-09 15:27:36 -0600 | [diff] [blame] | 24 | MAPPER_PATH = '/xyz/openbmc_project/object_mapper' |
Brad Bishop | fba8ea3 | 2016-09-20 15:45:18 -0400 | [diff] [blame] | 25 | MAPPER_NOT_FOUND = 'org.freedesktop.DBus.Error.FileNotFound' |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 26 | |
Matt Spinler | 06e5d2f | 2018-11-13 10:33:50 -0600 | [diff] [blame] | 27 | # The default D-Bus interfaces that we don't need to get |
| 28 | # properties on during an enumerate. |
| 29 | DEFAULT_IFACES = ['org.freedesktop.DBus.Introspectable', |
| 30 | 'org.freedesktop.DBus.Peer', |
| 31 | 'org.freedesktop.DBus.Properties'] |
| 32 | |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 33 | |
| 34 | class 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 Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 41 | @staticmethod |
Lei YU | 9e94fb6 | 2017-01-11 11:23:58 +0800 | [diff] [blame] | 42 | def retry(func, retries, interval): |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 43 | e = None |
| 44 | count = 0 |
| 45 | while count < retries: |
| 46 | try: |
| 47 | return func() |
Balaji B Rao | 84e331a | 2017-11-09 21:19:13 -0600 | [diff] [blame] | 48 | except dbus.exceptions.DBusException as e: |
Matt Spinler | 3c18b9f | 2017-01-27 14:41:48 -0600 | [diff] [blame] | 49 | if e.get_dbus_name() not in \ |
| 50 | ['org.freedesktop.DBus.Error.ObjectPathInUse', |
| 51 | 'org.freedesktop.DBus.Error.LimitsExceeded']: |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 52 | raise |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 53 | |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 54 | count += 1 |
Lei YU | 9e94fb6 | 2017-01-11 11:23:58 +0800 | [diff] [blame] | 55 | if interval > 0: |
| 56 | from time import sleep |
| 57 | sleep(interval) |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 58 | if e: |
| 59 | raise e |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 60 | |
Cory Klokman | a5513ab | 2017-01-24 17:27:16 -0600 | [diff] [blame] | 61 | def get_object(self, path, retries=5, interfaces=[], interval=0.2): |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 62 | return self.retry( |
Brad Bishop | bf464f4 | 2016-11-02 00:37:06 -0400 | [diff] [blame] | 63 | lambda: self.iface.GetObject( |
| 64 | path, interfaces, signature='sas'), |
Lei YU | 9e94fb6 | 2017-01-11 11:23:58 +0800 | [diff] [blame] | 65 | retries, interval) |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 66 | |
Adriana Kobylak | a1f2422 | 2018-01-10 16:09:07 -0600 | [diff] [blame] | 67 | def get_subtree_paths( |
| 68 | self, path='/', depth=0, retries=5, interfaces=[], interval=0.2): |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 69 | return self.retry( |
Brad Bishop | bf464f4 | 2016-11-02 00:37:06 -0400 | [diff] [blame] | 70 | lambda: self.iface.GetSubTreePaths( |
| 71 | path, depth, interfaces, signature='sias'), |
Lei YU | 9e94fb6 | 2017-01-11 11:23:58 +0800 | [diff] [blame] | 72 | retries, interval) |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 73 | |
Adriana Kobylak | a1f2422 | 2018-01-10 16:09:07 -0600 | [diff] [blame] | 74 | def get_subtree( |
| 75 | self, path='/', depth=0, retries=5, interfaces=[], interval=0.2): |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 76 | return self.retry( |
Brad Bishop | bf464f4 | 2016-11-02 00:37:06 -0400 | [diff] [blame] | 77 | lambda: self.iface.GetSubTree( |
| 78 | path, depth, interfaces, signature='sias'), |
Lei YU | 9e94fb6 | 2017-01-11 11:23:58 +0800 | [diff] [blame] | 79 | retries, interval) |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 80 | |
Cory Klokman | a5513ab | 2017-01-24 17:27:16 -0600 | [diff] [blame] | 81 | def get_ancestors(self, path, retries=5, interfaces=[], interval=0.2): |
Brad Bishop | 1eba37d | 2016-09-20 08:12:25 -0400 | [diff] [blame] | 82 | return self.retry( |
Brad Bishop | bf464f4 | 2016-11-02 00:37:06 -0400 | [diff] [blame] | 83 | lambda: self.iface.GetAncestors( |
| 84 | path, interfaces, signature='sas'), |
Lei YU | 9e94fb6 | 2017-01-11 11:23:58 +0800 | [diff] [blame] | 85 | retries, interval) |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 86 | |
| 87 | @staticmethod |
| 88 | def __try_properties_interface(f, *a): |
| 89 | try: |
| 90 | return f(*a) |
Balaji B Rao | 84e331a | 2017-11-09 21:19:13 -0600 | [diff] [blame] | 91 | except dbus.exceptions.DBusException as e: |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 92 | if obmc.dbuslib.enums.DBUS_UNKNOWN_INTERFACE in \ |
Adriana Kobylak | a8f9765 | 2017-12-11 13:32:10 -0600 | [diff] [blame] | 93 | e.get_dbus_name(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 94 | # 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 Bishop | 8f30173 | 2017-09-11 20:09:48 -0400 | [diff] [blame] | 115 | if match and not match(i): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 116 | continue |
Matt Spinler | 06e5d2f | 2018-11-13 10:33:50 -0600 | [diff] [blame] | 117 | if i in DEFAULT_IFACES: |
| 118 | continue |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 119 | properties.update(self.__get_properties_on_iface( |
| 120 | properties_iface, i)) |
| 121 | |
| 122 | return properties |
| 123 | |
| 124 | def enumerate_object( |
| 125 | self, path, |
Brad Bishop | 8f30173 | 2017-09-11 20:09:48 -0400 | [diff] [blame] | 126 | match=lambda x: x != dbus.BUS_DAEMON_IFACE + '.ObjectManager', |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 127 | mapper_data=None): |
| 128 | if mapper_data is None: |
| 129 | mapper_data = {path: self.get_object(path)} |
| 130 | |
| 131 | obj = {} |
| 132 | |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 133 | for owner, interfaces in mapper_data[path].items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 134 | 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 Bishop | 8f30173 | 2017-09-11 20:09:48 -0400 | [diff] [blame] | 142 | match=lambda x: x != dbus.BUS_DAEMON_IFACE + '.ObjectManager', |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 143 | 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 Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 151 | for path, bus_data in mapper_data.items(): |
| 152 | for owner, interfaces in bus_data.items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 153 | 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 Rao | 84e331a | 2017-11-09 21:19:13 -0600 | [diff] [blame] | 163 | except dbus.exceptions.DBusException as e: |
Brad Bishop | 5fd9c47 | 2016-07-25 09:09:00 -0400 | [diff] [blame] | 164 | if e.get_dbus_name() != MAPPER_NOT_FOUND: |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 165 | raise |
| 166 | |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 167 | for path, bus_data in ancestors.items(): |
| 168 | for owner, interfaces in bus_data.items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 169 | if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces: |
| 170 | managers[owner] = path |
| 171 | |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 172 | mapper_keys = set(mapper_data.keys()) |
| 173 | |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 174 | # make all the manager gmo (get managed objects) calls |
| 175 | results = {} |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 176 | for owner, path in managers.items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 177 | 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 Nguyen | 2fd4b1f | 2018-03-05 12:19:46 -0600 | [diff] [blame] | 184 | for path, interfaces in \ |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 185 | iface.GetManagedObjects().items(): |
| 186 | if path not in mapper_keys: |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 187 | continue |
| 188 | properties = {} |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 189 | for iface, props in interfaces.items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 190 | properties.update(props) |
| 191 | results.setdefault(path, {}).setdefault(owner, properties) |
| 192 | |
| 193 | # make dbus calls for any remaining objects |
Matt Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 194 | for path, bus_data in mapper_data.items(): |
| 195 | for owner, interfaces in bus_data.items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 196 | 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 Spinler | b659386 | 2018-05-31 13:12:39 -0500 | [diff] [blame] | 203 | for path, owners in results.items(): |
| 204 | for owner, properties in owners.items(): |
Brad Bishop | ea2bc0c | 2016-07-25 09:05:39 -0400 | [diff] [blame] | 205 | objs.setdefault(path, {}).update(properties) |
| 206 | |
| 207 | return objs |