Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | import os |
| 4 | import sys |
| 5 | import gobject |
| 6 | import dbus |
| 7 | import dbus.service |
| 8 | import dbus.mainloop.glib |
| 9 | import cPickle |
| 10 | import json |
| 11 | |
| 12 | if (len(sys.argv) < 2): |
| 13 | print "Usage: inventory_manager.py [system name]" |
| 14 | exit(1) |
| 15 | System = __import__(sys.argv[1]) |
| 16 | import Openbmc |
| 17 | |
| 18 | DBUS_NAME = 'org.openbmc.managers.Inventory' |
| 19 | OBJ_NAME = '/org/openbmc/managers/Inventory' |
| 20 | FRUS = System.FRU_INSTANCES |
| 21 | FRU_PATH = System.FRU_PATH |
| 22 | |
| 23 | ## accessor class to FRU data structure |
| 24 | class Fru: |
| 25 | def __init__(self,fru): |
| 26 | ## validation |
| 27 | if (FRUS.has_key(fru) == False): |
| 28 | # TODO: event log |
| 29 | raise Exception("Invalid FRU path: "+fru) |
| 30 | |
| 31 | self.fru = fru |
| 32 | |
| 33 | def getField(self,field): |
| 34 | if (FRUS[self.fru].has_key(field) == False): |
| 35 | # TODO: event log |
| 36 | raise Exception("Invalid field: "+field) |
| 37 | |
| 38 | return FRUS[self.fru][field] |
| 39 | |
| 40 | def isFru(self): |
| 41 | return FRUS[self.fru]['fru'] |
| 42 | |
| 43 | def update(self,data): |
| 44 | for k in data.keys(): |
| 45 | FRUS[self.fru][k] = data[k] |
| 46 | |
| 47 | def isCached(self): |
| 48 | return True |
| 49 | |
| 50 | def getCacheFilename(self): |
| 51 | global FRU_PATH |
Norman James | 7caa10e | 2015-09-27 22:39:52 -0500 | [diff] [blame^] | 52 | name = self.fru.replace('/','.') |
| 53 | filename = FRU_PATH+name[1:]+".fru" |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 54 | return filename |
| 55 | |
| 56 | def saveToCache(self): |
| 57 | if (self.isCached() == False): |
| 58 | return |
| 59 | print "Caching: "+self.fru |
Norman James | 7caa10e | 2015-09-27 22:39:52 -0500 | [diff] [blame^] | 60 | # TODO: error handling |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 61 | output = open(self.getCacheFilename(), 'wb') |
| 62 | ## just pickle dict not whole object |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 63 | cPickle.dump(FRUS[self.fru],output) |
| 64 | output.close() |
| 65 | |
| 66 | def loadFromCache(self): |
| 67 | if (self.isCached() == False): |
| 68 | return; |
| 69 | ## overlay with pickled data |
| 70 | filename=self.getCacheFilename() |
| 71 | if (os.path.isfile(filename)): |
| 72 | print "Loading from cache: "+filename |
Norman James | 7caa10e | 2015-09-27 22:39:52 -0500 | [diff] [blame^] | 73 | # TODO: error handling |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 74 | p = open(filename, 'rb') |
| 75 | data2 = cPickle.load(p) |
| 76 | for k in data2.keys(): |
| 77 | FRUS[self.fru][k] = data2[k] |
| 78 | |
| 79 | def __str__(self): |
| 80 | r = "Fru: "+str(self.fru_id)+"\n" |
| 81 | for f in self.data.keys(): |
| 82 | r = r+f+" = "+str(self.data[f])+"\n" |
| 83 | return r |
| 84 | |
| 85 | |
| 86 | |
| 87 | class InventoryManager(dbus.service.Object): |
| 88 | def __init__(self,bus,name): |
| 89 | dbus.service.Object.__init__(self,bus,name) |
| 90 | |
| 91 | bus.add_signal_receiver(self.UpdateFruHandler, |
Norman James | dfdaca9 | 2015-09-27 22:11:15 -0500 | [diff] [blame] | 92 | dbus_interface = "org.openbmc.sensors.IpmiBt", |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 93 | signal_name = 'UpdateFru') |
| 94 | |
Norman James | dfdaca9 | 2015-09-27 22:11:15 -0500 | [diff] [blame] | 95 | bus.add_signal_receiver(self.SetSensorHandler, |
| 96 | dbus_interface = "org.openbmc.sensors.IpmiBt", |
| 97 | signal_name = "SetSensor") |
| 98 | |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 99 | self.fru_db = {} |
| 100 | self.fru_id_lookup = {} |
| 101 | self.sensor_id_lookup = {} |
| 102 | |
| 103 | for fru_path in FRUS.keys(): |
| 104 | self.addFru(fru_path) |
| 105 | f = FRUS[fru_path] |
| 106 | if (f.has_key('fru_id')): |
| 107 | self.fru_id_lookup[f['fru_id']] = fru_path |
| 108 | if (f.has_key('sensor_id')): |
| 109 | self.sensor_id_lookup[f['sensor_id']] = fru_path |
| 110 | |
Norman James | 7caa10e | 2015-09-27 22:39:52 -0500 | [diff] [blame^] | 111 | @dbus.service.signal('org.openbmc.EventLog') |
| 112 | def EventLog(self, priority, message, rc): |
| 113 | pass |
| 114 | |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 115 | def UpdateFruHandler(self,fru_id,data): |
Norman James | dfdaca9 | 2015-09-27 22:11:15 -0500 | [diff] [blame] | 116 | self.updateFruFromId(fru_id,data) |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 117 | |
Norman James | dfdaca9 | 2015-09-27 22:11:15 -0500 | [diff] [blame] | 118 | def SetSensorHandler(self,sensor_id,data): |
| 119 | fru_path = self.getFruSensor(sensor_id) |
| 120 | if (fru_path != ""): |
| 121 | state = { 'state' : data } |
| 122 | self.updateFru(fru_path,state) |
| 123 | |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 124 | @dbus.service.method(DBUS_NAME, |
| 125 | in_signature='y', out_signature='s') |
| 126 | def getFruSensor(self,sensor_id): |
| 127 | if (self.sensor_id_lookup.has_key(sensor_id) == False): |
| 128 | return "" |
| 129 | return self.sensor_id_lookup[sensor_id] |
| 130 | |
| 131 | def addFru(self,fru_path): |
| 132 | new_fru = Fru(fru_path) |
| 133 | new_fru.loadFromCache() |
| 134 | self.fru_db[fru_path] = new_fru |
| 135 | |
| 136 | @dbus.service.method(DBUS_NAME, |
| 137 | in_signature='ia{sv}', out_signature='') |
| 138 | def updateFruFromId(self,fru_id,data): |
| 139 | iid = int(fru_id) |
| 140 | if (self.fru_id_lookup.has_key(iid) == False): |
Norman James | 7caa10e | 2015-09-27 22:39:52 -0500 | [diff] [blame^] | 141 | self.EventLog(1,"FRU ID not found: "+str(iid),1) |
Norman James | 65a295a | 2015-09-26 22:21:10 -0500 | [diff] [blame] | 142 | else: |
| 143 | self.updateFru(self.fru_id_lookup[iid],data) |
| 144 | |
| 145 | |
| 146 | @dbus.service.method(DBUS_NAME, |
| 147 | in_signature='sa{sv}', out_signature='') |
| 148 | def updateFru(self,fru_path,data): |
| 149 | ## translate dbus data into basic data types |
| 150 | clean_data = {} |
| 151 | for k in data.keys(): |
| 152 | d = Openbmc.DbusProperty(k,data[k]) |
| 153 | clean_data[str(k)] = d.getBaseValue() |
| 154 | |
| 155 | if (self.fru_db.has_key(fru_path)): |
| 156 | ## update properties then save to cache |
| 157 | print "Updating FRU: "+fru_path |
| 158 | self.fru_db[fru_path].update(clean_data) |
| 159 | self.fru_db[fru_path].saveToCache() |
| 160 | |
| 161 | |
| 162 | @dbus.service.method(DBUS_NAME, |
| 163 | in_signature='', out_signature='a{sa{sv}}') |
| 164 | def getFrus(self): |
| 165 | return FRUS |
| 166 | |
| 167 | |
| 168 | if __name__ == '__main__': |
| 169 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
| 170 | bus = dbus.SessionBus() |
| 171 | name = dbus.service.BusName(DBUS_NAME,bus) |
| 172 | obj = InventoryManager(bus,OBJ_NAME) |
| 173 | mainloop = gobject.MainLoop() |
| 174 | |
| 175 | print "Running Inventory Manager" |
| 176 | mainloop.run() |
| 177 | |