diff --git a/pyghmi/ipmi/command.py b/pyghmi/ipmi/command.py index 2ee1045b..0bebaa7b 100644 --- a/pyghmi/ipmi/command.py +++ b/pyghmi/ipmi/command.py @@ -322,7 +322,7 @@ class Command(object): return {'bootdev': bootdev} def xraw_command(self, netfn, command, bridge_request=(), data=(), - delay_xmit=None): + delay_xmit=None, retry=True, timeout=None): """Send raw ipmi command to BMC, raising exception on error This is identical to raw_command, except it raises exceptions @@ -336,18 +336,23 @@ class Command(object): :param bridge_request: The target slave address and channel number for the bridge request. :param data: Command data as a tuple or list + :param retry: Whether to retry this particular payload or not, defaults + to true. + :param timeout: A custom time to wait for initial reply, useful for + a slow command. This may interfere with retry logic. :returns: dict -- The response from IPMI device """ rsp = self.ipmi_session.raw_command(netfn=netfn, command=command, bridge_request=bridge_request, - data=data, delay_xmit=delay_xmit) + data=data, delay_xmit=delay_xmit, + retry=retry, timeout=timeout) if 'error' in rsp: raise exc.IpmiException(rsp['error'], rsp['code']) rsp['data'] = buffer(bytearray(rsp['data'])) return rsp def raw_command(self, netfn, command, bridge_request=(), data=(), - delay_xmit=None): + delay_xmit=None, retry=True, timeout=None): """Send raw ipmi command to BMC This allows arbitrary IPMI bytes to be issued. This is commonly used @@ -360,11 +365,15 @@ class Command(object): :param bridge_request: The target slave address and channel number for the bridge request. :param data: Command data as a tuple or list + :param retry: Whether or not to retry command if no response received. + Defaults to True + :param timeout: A custom amount of time to wait for initial reply :returns: dict -- The response from IPMI device """ return self.ipmi_session.raw_command(netfn=netfn, command=command, bridge_request=bridge_request, - data=data, delay_xmit=delay_xmit) + data=data, delay_xmit=delay_xmit, + retry=retry, timeout=timeout) def get_power(self): """Get current power state of the managed system diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index 418cd91e..20f94a5e 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -209,10 +209,10 @@ class OEMHandler(generic.OEMHandler): if self.has_tsm: if enabled: self.ipmicmd.xraw_command( - netfn=0x32, command=0xa8, data=(3, 1)) + netfn=0x32, command=0xa8, data=(3, 1), timeout=15) else: self.ipmicmd.xraw_command( - netfn=0x32, command=0xa8, data=(3, 0)) + netfn=0x32, command=0xa8, data=(3, 0), timeout=15) return True return None diff --git a/pyghmi/ipmi/private/session.py b/pyghmi/ipmi/private/session.py index d7c396e4..22193469 100644 --- a/pyghmi/ipmi/private/session.py +++ b/pyghmi/ipmi/private/session.py @@ -600,7 +600,8 @@ class Session(object): bridge_request=None, data=(), retry=True, - delay_xmit=None): + delay_xmit=None, + timeout=None): if not self.logged: raise exc.IpmiException('Session no longer connected') while self._isincommand(): @@ -612,7 +613,8 @@ class Session(object): self.ipmicallback = self._generic_callback self._send_ipmi_net_payload(netfn, command, data, bridge_request=bridge_request, - retry=retry, delay_xmit=delay_xmit) + retry=retry, delay_xmit=delay_xmit, + timeout=timeout) if retry: # in retry case, let the retry timers indicate wait time timeout = None @@ -632,7 +634,7 @@ class Session(object): def _send_ipmi_net_payload(self, netfn=None, command=None, data=[], code=0, bridge_request=None, - retry=None, delay_xmit=None): + retry=None, delay_xmit=None, timeout=None): if retry is None: retry = not self.servermode if self.servermode: @@ -645,10 +647,10 @@ class Session(object): data) payload_type = constants.payload_types['ipmi'] self.send_payload(payload=ipmipayload, payload_type=payload_type, - retry=retry, delay_xmit=delay_xmit) + retry=retry, delay_xmit=delay_xmit, timeout=timeout) def send_payload(self, payload=(), payload_type=None, retry=True, - delay_xmit=None, needskeepalive=False): + delay_xmit=None, needskeepalive=False, timeout=None): """Send payload over the IPMI Session :param needskeepalive: If the payload is expected not to count as @@ -657,6 +659,7 @@ class Session(object): job done because of this payload. Notably, 0-length SOL packets are prone to confusion. + :param timeout: Specify a custom timeout for long-running request """ if payload and self.lastpayload: # we already have a packet outgoing, make this @@ -754,7 +757,7 @@ class Session(object): not self._customkeepalives): Session.keepalive_sessions[self]['timeout'] = _monotonic_time() + \ 25 + (random.random() * 4.9) - self._xmit_packet(retry, delay_xmit=delay_xmit) + self._xmit_packet(retry, delay_xmit=delay_xmit, timeout=timeout) def _ipmi15authcode(self, payload, checkremotecode=False): #checkremotecode is used to verify remote code, @@ -1475,7 +1478,7 @@ class Session(object): self.send_payload() self.nowait = False - def _xmit_packet(self, retry=True, delay_xmit=None): + def _xmit_packet(self, retry=True, delay_xmit=None, timeout=None): if self.sequencenumber: # seq number of zero will be left alone, it is # special, otherwise increment self.sequencenumber += 1 @@ -1509,8 +1512,12 @@ class Session(object): if retry: Session.waiting_sessions[self] = {} Session.waiting_sessions[self]['ipmisession'] = self - Session.waiting_sessions[self]['timeout'] = self.timeout + \ - _monotonic_time() + if timeout is not None: + Session.waiting_sessions[self]['timeout'] = timeout + \ + _monotonic_time() + else: + Session.waiting_sessions[self]['timeout'] = self.timeout + \ + _monotonic_time() def logout(self): if not self.logged: