1#!/usr/bin/python -u 2 3import sys 4import subprocess 5import gobject 6import dbus 7import dbus.service 8import dbus.mainloop.glib 9import os 10import time 11import obmc.dbuslib.propertycacher as PropertyCacher 12from obmc.dbuslib.bindings import DbusProperties, DbusObjectManager, get_dbus 13import obmc.enums 14 15if (len(sys.argv) < 2): 16 print "Usage: system_manager.py [system name]" 17 exit(1) 18 19System = __import__(sys.argv[1]) 20 21DBUS_NAME = 'org.openbmc.managers.System' 22OBJ_NAME = '/org/openbmc/managers/System' 23HEARTBEAT_CHECK_INTERVAL = 20000 24STATE_START_TIMEOUT = 10 25INTF_SENSOR = 'org.openbmc.SensorValue' 26INTF_ITEM = 'org.openbmc.InventoryItem' 27INTF_CONTROL = 'org.openbmc.Control' 28 29 30class SystemManager(DbusProperties,DbusObjectManager): 31 def __init__(self,bus,obj_name): 32 DbusProperties.__init__(self) 33 DbusObjectManager.__init__(self) 34 dbus.service.Object.__init__(self,bus,obj_name) 35 36 bus.add_signal_receiver(self.NewObjectHandler, 37 signal_name = "InterfacesAdded", sender_keyword = 'bus_name') 38 bus.add_signal_receiver(self.SystemStateHandler,signal_name = "GotoSystemState") 39 40 self.Set(DBUS_NAME,"current_state","") 41 self.system_states = {} 42 self.bus_name_lookup = {} 43 self.bin_path = os.path.dirname(os.path.realpath(sys.argv[0])) 44 45 for name in System.APPS.keys(): 46 sys_state = System.APPS[name]['system_state'] 47 if (self.system_states.has_key(sys_state) == False): 48 self.system_states[sys_state] = [] 49 self.system_states[sys_state].append(name) 50 51 ## replace symbolic path in ID_LOOKUP 52 for category in System.ID_LOOKUP: 53 for key in System.ID_LOOKUP[category]: 54 val = System.ID_LOOKUP[category][key] 55 new_val = val.replace("<inventory_root>",System.INVENTORY_ROOT) 56 System.ID_LOOKUP[category][key] = new_val 57 58 self.SystemStateHandler(System.SYSTEM_STATES[0]) 59 60 if not os.path.exists(PropertyCacher.CACHE_PATH): 61 print "Creating cache directory: "+PropertyCacher.CACHE_PATH 62 os.makedirs(PropertyCacher.CACHE_PATH) 63 64 self.InterfacesAdded(obj_name,self.properties) 65 print "SystemManager Init Done" 66 67 68 def SystemStateHandler(self,state_name): 69 ## clearing object started flags 70 current_state = self.Get(DBUS_NAME,"current_state") 71 try: 72 for obj_path in System.EXIT_STATE_DEPEND[current_state]: 73 System.EXIT_STATE_DEPEND[current_state][obj_path] = 0 74 except: 75 pass 76 77 print "Running System State: "+state_name 78 if (self.system_states.has_key(state_name)): 79 for name in self.system_states[state_name]: 80 self.start_process(name) 81 82 if (state_name == "BMC_INIT"): 83 ## Add poll for heartbeat 84 gobject.timeout_add(HEARTBEAT_CHECK_INTERVAL, self.heartbeat_check) 85 86 try: 87 cb = System.ENTER_STATE_CALLBACK[state_name] 88 for methd in cb.keys(): 89 obj = bus.get_object(cb[methd]['bus_name'],cb[methd]['obj_name'],introspect=False) 90 method = obj.get_dbus_method(methd,cb[methd]['interface_name']) 91 method() 92 except: 93 pass 94 95 self.Set(DBUS_NAME,"current_state",state_name) 96 97 def gotoNextState(self): 98 s = 0 99 current_state = self.Get(DBUS_NAME,"current_state") 100 for i in range(len(System.SYSTEM_STATES)): 101 if (System.SYSTEM_STATES[i] == current_state): 102 s = i+1 103 104 if (s == len(System.SYSTEM_STATES)): 105 print "ERROR SystemManager: No more system states" 106 else: 107 new_state_name = System.SYSTEM_STATES[s] 108 print "SystemManager Goto System State: "+new_state_name 109 self.SystemStateHandler(new_state_name) 110 111 112 @dbus.service.method(DBUS_NAME, 113 in_signature='', out_signature='s') 114 def getSystemState(self): 115 return self.Get(DBUS_NAME,"current_state") 116 117 def doObjectLookup(self,category,key): 118 bus_name = "" 119 obj_path = "" 120 intf_name = INTF_ITEM 121 try: 122 obj_path = System.ID_LOOKUP[category][key] 123 bus_name = self.bus_name_lookup[obj_path] 124 parts = obj_path.split('/') 125 if (parts[3] == 'sensors'): 126 intf_name = INTF_SENSOR 127 except Exception as e: 128 print "ERROR SystemManager: "+str(e)+" not found in lookup" 129 130 return [bus_name,obj_path,intf_name] 131 132 @dbus.service.method(DBUS_NAME, 133 in_signature='ss', out_signature='(sss)') 134 def getObjectFromId(self,category,key): 135 return self.doObjectLookup(category,key) 136 137 @dbus.service.method(DBUS_NAME, 138 in_signature='sy', out_signature='(sss)') 139 def getObjectFromByteId(self,category,key): 140 byte = int(key) 141 return self.doObjectLookup(category,byte) 142 143 # Get the FRU area names defined in ID_LOOKUP table given a fru_id. 144 # If serval areas are defined for a fru_id, the areas are returned 145 # together as a string with each area name seperated with ','. 146 # If no fru area defined in ID_LOOKUP, an empty string will be returned. 147 @dbus.service.method(DBUS_NAME, 148 in_signature='y', out_signature='s') 149 def getFRUArea(self,fru_id): 150 ret_str = '' 151 fru_id = '_' + str(fru_id) 152 area_list = [area for area in System.ID_LOOKUP['FRU_STR'].keys() \ 153 if area.endswith(fru_id)] 154 for area in area_list: 155 ret_str = area + ',' + ret_str 156 # remove the last ',' 157 return ret_str[:-1] 158 159 def start_process(self,name): 160 if (System.APPS[name]['start_process'] == True): 161 app = System.APPS[name] 162 process_name = self.bin_path+"/"+app['process_name'] 163 cmdline = [ ] 164 cmdline.append(process_name) 165 if (app.has_key('args')): 166 for a in app['args']: 167 cmdline.append(a) 168 try: 169 print "Starting process: "+" ".join(cmdline)+": "+name 170 if (app['monitor_process'] == True): 171 app['popen'] = subprocess.Popen(cmdline) 172 else: 173 subprocess.Popen(cmdline) 174 175 except Exception as e: 176 ## TODO: error 177 print "ERROR: starting process: "+" ".join(cmdline) 178 179 def heartbeat_check(self): 180 for name in System.APPS.keys(): 181 app = System.APPS[name] 182 if (app['start_process'] == True and app.has_key('popen')): 183 ## make sure process is still alive 184 p = app['popen'] 185 p.poll() 186 if (p.returncode != None): 187 print "Process for "+name+" appears to be dead" 188 self.start_process(name) 189 190 return True 191 192 def NewObjectHandler(self, obj_path, iprops, bus_name = None): 193 current_state = self.Get(DBUS_NAME,"current_state") 194 if (self.bus_name_lookup.has_key(obj_path)): 195 if (self.bus_name_lookup[obj_path] == bus_name): 196 return 197 self.bus_name_lookup[obj_path] = bus_name 198 print "New object: "+obj_path+" ("+bus_name+")" 199 try: 200 if (System.EXIT_STATE_DEPEND[current_state].has_key(obj_path) == True): 201 System.EXIT_STATE_DEPEND[current_state][obj_path] = 1 202 ## check if all required objects are started to move to next state 203 state = 1 204 for obj_path in System.EXIT_STATE_DEPEND[current_state]: 205 if (System.EXIT_STATE_DEPEND[current_state][obj_path] == 0): 206 state = 0 207 ## all required objects have started so go to next state 208 if (state == 1): 209 print "All required objects started for "+current_state 210 self.gotoNextState() 211 except: 212 pass 213 214 215 @dbus.service.method(DBUS_NAME, 216 in_signature='s', out_signature='sis') 217 def gpioInit(self,name): 218 gpio_path = '' 219 gpio_num = -1 220 r = ['',gpio_num,''] 221 if (System.GPIO_CONFIG.has_key(name) == False): 222 # TODO: Error handling 223 print "ERROR: "+name+" not found in GPIO config table" 224 else: 225 226 gpio_num = -1 227 gpio = System.GPIO_CONFIG[name] 228 if (System.GPIO_CONFIG[name].has_key('gpio_num')): 229 gpio_num = gpio['gpio_num'] 230 else: 231 if (System.GPIO_CONFIG[name].has_key('gpio_pin')): 232 gpio_num = System.convertGpio(gpio['gpio_pin']) 233 else: 234 print "ERROR: SystemManager - GPIO lookup failed for "+name 235 236 if (gpio_num != -1): 237 r = [obmc.enums.GPIO_DEV, gpio_num, gpio['direction']] 238 return r 239 240 241 242if __name__ == '__main__': 243 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 244 bus = get_dbus() 245 name = dbus.service.BusName(DBUS_NAME,bus) 246 obj = SystemManager(bus,OBJ_NAME) 247 mainloop = gobject.MainLoop() 248 249 print "Running SystemManager" 250 mainloop.run() 251 252