def _set_and_wait(target_state, driver_info): """Helper function for DynamicLoopingCall. This method changes the power state and polls the BMCuntil the desired power state is reached, or CONF.ipmi.retry_timeout would be exceeded by the next iteration. This method assumes the caller knows the current power state and does not check it prior to changing the power state. Most BMCs should be fine, but if a driver is concerned, the state should be checked prior to calling this method. :param target_state: desired power state :param driver_info: the ipmitool parameters for accessing a node. :returns: one of ironic.common.states :raises: IPMIFailure on an error from ipmitool (from _power_status call). """ if target_state == states.POWER_ON: state_name = "on" elif target_state == states.POWER_OFF: state_name = "off" def _wait(mutable): try: # Only issue power change command once if mutable['iter'] < 0: xcat_util.exec_xcatcmd(driver_info,'rpower',state_name) else: mutable['power'] = _power_status(driver_info) except Exception: # Log failures but keep trying LOG.warning(_("xcat rpower %(state)s failed for node %(node)s."), {'state': state_name, 'node': driver_info['uuid']}) finally: mutable['iter'] += 1 if mutable['power'] == target_state: raise loopingcall.LoopingCallDone() sleep_time = _sleep_time(mutable['iter']) if (sleep_time + mutable['total_time']) > CONF.ipmi.retry_timeout: # Stop if the next loop would exceed maximum retry_timeout LOG.error(_('xcat rpower %(state)s timed out after ' '%(tries)s retries on node %(node_id)s.'), {'state': state_name, 'tries': mutable['iter'], 'node_id': driver_info['uuid']}) mutable['power'] = states.ERROR raise loopingcall.LoopingCallDone() else: mutable['total_time'] += sleep_time return sleep_time # Use mutable objects so the looped method can change them. # Start 'iter' from -1 so that the first two checks are one second apart. status = {'power': None, 'iter': -1, 'total_time': 0} timer = loopingcall.DynamicLoopingCall(_wait, status) timer.start().wait() return status['power']
def add_dynamic_timer(self, callback, initial_delay=None, periodic_interval_max=None, *args, **kwargs): timer = loopingcall.DynamicLoopingCall(callback, *args, **kwargs) timer.start(initial_delay=initial_delay, periodic_interval_max=periodic_interval_max) self.timers.append(timer)