'Wait until the node is running and its network interface is configured.
This method fails if the node does not reach the expected state until
the predefined timeout expires or if the node goes into an error state
or an unexpected state.
:param node: A libcloud node object representing the compute instance
of interest.
:return: Deferred that fires with a libcloud node object representing
the latest state of the instance in the case of success.'

def _wait_until_running(self, reactor, node):

    action = start_action(action_type=u'flocker:provision:libcloud:wait_until_running', name=node.name, id=node.id)
    with action.context():
        steps = iter(([15] * (600 / 15)))
        d = loop_until(reactor, (lambda : self._async_node_in_state(reactor, node, self.TERMINAL_STATES)), steps=steps)
        d = DeferredContext(d)
        def got_ip_addresses():
            d = self._async_refresh_node(reactor, node)
            d = DeferredContext(d)
            def is_running(updated_node):
                if (updated_node.state is not NodeState.RUNNING):
                    raise Exception('Node    failed    to    run')
                return updated_node
            def check_addresses(updated_node):
                '\n                                                                                Check    if    the    node    has    got    at    least    one    IPv4    public    address\n                                                                                and,    if    requested,    an    IPv4    private    address.        If    yes,    then\n                                                                                return    the    node    object    with    the    addresses,    None    otherwise.\n                                                                                '
                public_ips = _filter_ipv4(updated_node.public_ips)
                if (len(public_ips) > 0):
                    if self._use_private_addresses:
                        private_ips = _filter_ipv4(updated_node.private_ips)
                        if (len(private_ips) == 0):
                            return None
                    return updated_node
                else:
                    return None
            d.addCallback(is_running)
            d.addCallback(check_addresses)
            return d.result
        d.addCallback((lambda _: loop_until(reactor, got_ip_addresses, steps=steps)))
        def failed_to_run(failure):
            d = _retry_exception_async(reactor, node.destroy)
            d.addCallback((lambda _: failure))
            return d
        d.addErrback(failed_to_run)
        return d.addActionFinish()
