Source code for googleapiclienthelpers.waiter

import time

__all__ = ['Waiter', 'WaiterException']

# Extend ValueError so we can provide the response when we fail to reach a desired state
[docs]class WaiterException(ValueError): def __init__(self, *args, response=None): super().__init__(*args) self.response = response
[docs]class Waiter(object): '''Wait for a resource to reach a desired state. This class implements a generic way to wait for an operation to reach a desired state. To use: create a new instance by providing a callable and the arguments that it requires. Then, call wait() and the Waiter will poll the callable until the desired status is reached. The callable you pass must have a .execute() method, like the Resource objects returned by googleapiclient. For example, you might start an instance and wait until it reaches the RUNNING status: >>> instances = build_subresource('compute.instances', 'v1') >>> instances.insert(...) >>> waiter = Waiter(instances.get, project=..., zone=..., instance=...) >>> waiter.wait('status', 'RUNNING') ''' def __init__(self, func, *args, **kargs): '''Construct a new Waiter Args: func: callable, the callable that returns the status. Most of the time this will be a googleapiclient Resource method. *args: positional arguments to be passed to func. **kargs: keyword arguments to be passed to func. ''' self.func = func self.args = args self.kargs = kargs
[docs] def wait(self, field, value, retries=60, interval=2, terminal_values=[]): '''Wait until an object reached the desired status When called, the Waiter will invoke the callable provided at construction and capture its return. The Waiter extracts field, and checks if it's equal to value. If it is, the full response from the callable is returned. wait() handles three kinds of field parameter: * dict-like return where field is a string that specified a key. * object-like return where field is a string naming an attribute. * any kind of return where field is a one-place callable that extracts the needed data to compare. Args: field: string or callable, the data to extract. value: varies, the value indicating the desired state. retries: int, maximum number of times to poll. interval: float, time to sleep between polls. terminal_values: list<string> of values that indicate an unrecoverable state. If encountered an exception is raised. ''' count = 0 while count < retries: response = self.func(*self.args, **self.kargs).execute() # field might be a dict key try: field_val = response[field] if field_val == value: return response if field_val in terminal_values: raise WaiterException( 'Received one of the terminal states: %s' % field_val, response=response, ) except KeyError: pass # field might be an object attribute try: field_val = getattr(response, field) if field_val == value: return response if field_val in terminal_values: raise WaiterException( 'Received one of the terminal states: %s' % field_val, response=response, ) except (AttributeError, TypeError): pass # field might be a callable that finds the right thing try: field_val = field(response) if field_val == value: return response if field_val in terminal_values: raise WaiterException( 'Received one of the terminal states: %s' % field_val, response=response, ) except TypeError: pass # either the desired status hasn't been reached, or the # user passed something nonsensical as field/value time.sleep(interval) count += 1 raise ValueError('Never received desired value %s' % value)