diff --git a/ipmi_command.py b/ipmi_command.py index ac787066..f359c572 100644 --- a/ipmi_command.py +++ b/ipmi_command.py @@ -1,4 +1,3 @@ -# Copyright 2013 IBM Corp. from ipmi_session import ipmi_session, call_with_optional_args def _raiseorcall(callback,response,args=None): if callback is None: @@ -7,14 +6,49 @@ def _raiseorcall(callback,response,args=None): else: call_with_optional_args(callback,args) +boot_devices = { + 'net': 4, + 'network': 4, + 'pxe': 4, + 'hd': 8, + 'cd': 0x14, + 'cdrom': 0x14, + 'dvd': 0x14, + 'floppy': 0x3c, + 'default': 0x0, + 'setup': 0x18, + 'f1': 0x18, + 1: 'network', + 2: 'hd', + 5: 'optical', + 6: 'setup', + 0: 'default' +} + class ipmi_command: def __init__(self,bmc,userid,password,kg=None): self.ipmi_session=ipmi_session(bmc=bmc,userid=userid,password=password,kg=kg) - def set_bootdev(self,bootdev,callback=None,callback_args=None): + def get_bootdev(self,callback=None,callback_args=None): self.commandcallback=callback self.commandcallbackargs=callback_args + self.requestpending=True + self.ipmi_session.raw_command(netfn=0,command=9,data=(5,0,0),callback=self._got_bootdev) + if callback is None: + while self.requestpending: + ipmi_session.wait_for_rsp() + return self.lastresponse + + def set_bootdev(self,bootdev,callback=None,callback_args=None,persist=None,uefiboot=None): + self.commandcallback=callback + self.commandcallbackargs=callback_args + if bootdev not in boot_devices: + _raiseorcall(self.commandcallback,{'error': "Unknown bootdevice %s requested"%bootdev},self.commandcallbackargs) + self.bootdev=boot_devices[bootdev] + self.persistboot=persist + self.uefiboot=uefiboot #first, we disable timer by way of set system boot options, then move on to set chassis capabilities self.requestpending=True + #Set System Boot Options is netfn=0, command=8, data self.ipmi_session.raw_command(netfn=0,command=8,data=(3,8),callback=self._bootdev_timer_disabled) if callback is None: while self.requestpending: @@ -25,8 +59,43 @@ class ipmi_command: self.requestpending=False self.lastresponse=response if 'error' in response: - _raiseorcall(self.commandcallback,response) + _raiseorcall(self.commandcallback,response,self.commandcallbackargs) return + bootflags=0x80 + if self.uefiboot: #frustrating, there is no 'default', and this is generally not honored... + bootflags = bootflags | 1<<5 + if self.persistboot: #another flag that is oft silently ignored + bootflags = bootflags | 1<<6 + if self.bootdev==0: + bootflags=0 + data=(5,bootflags,self.bootdev,0,0,0) + self.ipmi_session.raw_command(netfn=0,command=8,data=data,callback=self.commandcallback,callback_args=self.commandcallbackargs) + + def raw_command(self,netfn,command,data=(),callback=None,callback_args=None): + response=self.ipmi_session.raw_command(netfn=0,command=1,callback=callback,callback_args=callback_args) + if response: #this means there was no callback + if 'error' in response: + raise Exception(response['error']) + return response + def _got_bootdev(self,response): + #interpret response per 'get system boot options' + self.requestpending=False + if 'error' in response: + _raiseorcall(self.commandcallback,response,self.commandcallbackargs) + return + #this should only be invoked for get system boot option complying to ipmi spec and targeting the 'boot flags' parameter + assert (response['command'] == 9 and response['netfn'] == 1 and response['data'][0]==1 and (response['data'][1]&0b1111111)==5) + if (response['data'][1] & 0b10000000 or not response['data'][2] & 0b10000000): + self.lastresponse={ 'bootdev': 'default' } + else: #will consult data2 of the boot flags parameter for the data for now + bootnum = (response['data'][3] & 0b111100) >> 2 + bootdev = boot_devices[bootnum] + if (bootdev): + self.lastresponse={'bootdev': bootdev} + else: + self.lastresponse={'bootdev': bootnum} + if self.commandcallback: + call_with_optional_args(self.commandcallback,self.lastresponse,self.commandcallbackargs) def get_power(self,callback=None,callback_args=None): response=self.ipmi_session.raw_command(netfn=0,command=1,callback=callback,callback_args=callback_args) @@ -42,3 +111,8 @@ if __name__ == "__main__": import os ipmicmd = ipmi_command(bmc=sys.argv[1],userid=sys.argv[2],password=os.environ['IPMIPASS']) print ipmicmd.get_power() + print ipmicmd.get_bootdev() + print ipmicmd.set_bootdev('network') + print ipmicmd.get_bootdev() + print ipmicmd.set_bootdev('default') + print ipmicmd.get_bootdev()