Brad Bishop | 8ffe1e4 | 2016-02-11 16:15:40 -0500 | [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 |
Brad Bishop | f6c2a94 | 2016-04-01 14:44:12 -0400 | [diff] [blame] | 18 | import obmc.dbuslib.enums |
| 19 | import obmc.utils.misc |
| 20 | import obmc.utils.pathtree |
Brad Bishop | 8ffe1e4 | 2016-02-11 16:15:40 -0500 | [diff] [blame] | 21 | |
Brad Bishop | 51c5539 | 2016-05-18 08:23:29 -0400 | [diff] [blame] | 22 | MAPPER_NAME = 'org.openbmc.ObjectMapper' |
| 23 | MAPPER_IFACE = MAPPER_NAME |
| 24 | MAPPER_PATH = '/org/openbmc/ObjectMapper' |
| 25 | MAPPER_NOT_FOUND = MAPPER_NAME + '.Error.NotFound' |
Brad Bishop | 8ffe1e4 | 2016-02-11 16:15:40 -0500 | [diff] [blame] | 26 | |
| 27 | |
| 28 | class 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 | |
| 35 | def get_object(self, path): |
| 36 | return self.iface.GetObject(path) |
| 37 | |
| 38 | def get_subtree_paths(self, path='/', depth=0): |
| 39 | return self.iface.GetSubTreePaths(path, depth) |
| 40 | |
| 41 | def get_subtree(self, path='/', depth=0): |
| 42 | return self.iface.GetSubTree(path, depth) |
| 43 | |
| 44 | def get_ancestors(self, path): |
| 45 | return self.iface.GetAncestors(path) |
Brad Bishop | f6c2a94 | 2016-04-01 14:44:12 -0400 | [diff] [blame] | 46 | |
| 47 | @staticmethod |
| 48 | def __try_properties_interface(f, *a): |
| 49 | try: |
| 50 | return f(*a) |
| 51 | except dbus.exceptions.DBusException, e: |
| 52 | if obmc.dbuslib.enums.DBUS_UNKNOWN_INTERFACE in \ |
| 53 | e.get_dbus_message(): |
| 54 | # interface doesn't have any properties |
| 55 | return None |
| 56 | if obmc.dbuslib.enums.DBUS_UNKNOWN_METHOD == e.get_dbus_name(): |
| 57 | # properties interface not implemented at all |
| 58 | return None |
| 59 | raise |
| 60 | |
| 61 | @staticmethod |
| 62 | def __get_properties_on_iface(properties_iface, iface): |
| 63 | properties = Mapper.__try_properties_interface( |
| 64 | properties_iface.GetAll, iface) |
| 65 | if properties is None: |
| 66 | return {} |
| 67 | return properties |
| 68 | |
| 69 | def __get_properties_on_bus(self, path, bus, interfaces, match): |
| 70 | properties = {} |
| 71 | obj = self.bus.get_object(bus, path, introspect=False) |
| 72 | properties_iface = dbus.Interface( |
| 73 | obj, dbus_interface=dbus.PROPERTIES_IFACE) |
| 74 | for i in interfaces: |
| 75 | if not match(i): |
| 76 | continue |
| 77 | properties.update(self.__get_properties_on_iface( |
| 78 | properties_iface, i)) |
| 79 | |
| 80 | return properties |
| 81 | |
| 82 | def enumerate_object( |
| 83 | self, path, |
| 84 | match=obmc.utils.misc.org_dot_openbmc_match, |
| 85 | mapper_data=None): |
| 86 | if mapper_data is None: |
| 87 | mapper_data = {path: self.get_object(path)} |
| 88 | |
| 89 | obj = {} |
| 90 | |
| 91 | for owner, interfaces in mapper_data[path].iteritems(): |
| 92 | obj.update( |
| 93 | self.__get_properties_on_bus( |
| 94 | path, owner, interfaces, match)) |
| 95 | |
| 96 | return obj |
| 97 | |
| 98 | def enumerate_subtree( |
| 99 | self, path='/', |
| 100 | match=obmc.utils.misc.org_dot_openbmc_match, |
| 101 | mapper_data=None): |
| 102 | if mapper_data is None: |
| 103 | mapper_data = self.get_subtree(path) |
| 104 | managers = {} |
| 105 | owners = [] |
| 106 | |
| 107 | # look for objectmanager implementations as they result |
| 108 | # in fewer dbus calls |
| 109 | for path, bus_data in mapper_data.iteritems(): |
| 110 | for owner, interfaces in bus_data.iteritems(): |
| 111 | owners.append(owner) |
| 112 | if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces: |
| 113 | managers[owner] = path |
| 114 | |
| 115 | # also look in the parent objects |
| 116 | ancestors = self.get_ancestors(path) |
| 117 | |
| 118 | # finally check the root for one too |
| 119 | try: |
| 120 | ancestors.update({path: self.get_object(path)}) |
| 121 | except dbus.exceptions.DBusException, e: |
| 122 | if e.get_dbus_name() != obmc.mapper.MAPPER_NOT_FOUND: |
| 123 | raise |
| 124 | |
| 125 | for path, bus_data in ancestors.iteritems(): |
| 126 | for owner, interfaces in bus_data.iteritems(): |
| 127 | if dbus.BUS_DAEMON_IFACE + '.ObjectManager' in interfaces: |
| 128 | managers[owner] = path |
| 129 | |
| 130 | # make all the manager gmo (get managed objects) calls |
| 131 | results = {} |
| 132 | for owner, path in managers.iteritems(): |
| 133 | if owner not in owners: |
| 134 | continue |
| 135 | obj = self.bus.get_object(owner, path, introspect=False) |
| 136 | iface = dbus.Interface( |
| 137 | obj, dbus.BUS_DAEMON_IFACE + '.ObjectManager') |
| 138 | |
| 139 | # flatten (remove interface names) gmo results |
| 140 | for path, interfaces in iface.GetManagedObjects().iteritems(): |
| 141 | if path not in mapper_data.iterkeys(): |
| 142 | continue |
| 143 | properties = {} |
| 144 | for iface, props in interfaces.iteritems(): |
| 145 | properties.update(props) |
| 146 | results.setdefault(path, {}).setdefault(owner, properties) |
| 147 | |
| 148 | # make dbus calls for any remaining objects |
| 149 | for path, bus_data in mapper_data.iteritems(): |
| 150 | for owner, interfaces in bus_data.iteritems(): |
| 151 | if results.setdefault(path, {}).setdefault(owner, {}): |
| 152 | continue |
| 153 | results[path][owner].update( |
| 154 | self.__get_properties_on_bus( |
| 155 | path, owner, interfaces, match)) |
| 156 | |
| 157 | objs = obmc.utils.pathtree.PathTree() |
| 158 | for path, owners in results.iteritems(): |
| 159 | for owner, properties in owners.iteritems(): |
| 160 | objs.setdefault(path, {}).update(properties) |
| 161 | |
| 162 | return objs |