'Clean containers and datasets via the API.
:return: A `Deferred` that fires when the cluster is clean.'

@log_method
def clean_nodes(self, remove_foreign_containers=True):

    def api_clean_state(name, configuration_method, state_method, delete_method):
        '\n                                                Clean    entities    from    the    cluster.\n\n                                                :param    unicode    name:    The    name    of    the    entities    to    clean.\n                                                :param    configuration_method:    The    function    to    obtain    the    configured\n                                                                entities.\n                                                :param    state_method:    The    function    to    get    the    current    entities.\n                                                :param    delete_method:    The    method    to    delete    an    entity.\n\n                                                :return:    A    `Deferred`    that    fires    when    the    entities    have    been\n                                                                deleted.\n                                                '
        context = start_action(action_type=(u'acceptance:cleanup_' + name))
        with context.context():
            get_items = DeferredContext(configuration_method())
            def delete_items(items):
                return gather_deferreds(list((delete_method(item) for item in items)))
            get_items.addCallback(delete_items)
            get_items.addCallback((lambda ignored: loop_until(reactor, (lambda : state_method().addCallback((lambda result: ([] == result)))))))
            return get_items.addActionFinish()
    def cleanup_all_containers(_):
        '\n                                                Clean-up    any    containers    run    by    Docker    directly    that    are    unmanaged\n                                                by    Flocker.\n                                                '
        for node in self.nodes:
            client = get_docker_client(self, node.public_address)
            for container in client.containers():
                client.remove_container(container['Id'], force=True)
    def cleanup_flocker_containers(_):
        cleaning_containers = api_clean_state(u'containers', self.configured_containers, self.current_containers, (lambda item: self.remove_container(item[u'name'])))
        return timeout(reactor, cleaning_containers, 60, Exception('Timed    out    cleaning    up    Flocker    containers'))
    def cleanup_datasets(_):
        cleaning_datasets = api_clean_state(u'datasets', self.client.list_datasets_configuration, self.client.list_datasets_state, (lambda item: self.client.delete_dataset(item.dataset_id)))
        return timeout(reactor, cleaning_datasets, 180, Exception('Timed    out    cleaning    up    datasets'))
    def cleanup_leases():
        context = start_action(action_type='acceptance:cleanup_leases')
        with context.context():
            get_items = DeferredContext(self.client.list_leases())
            def release_all(leases):
                release_list = []
                for lease in leases:
                    release_list.append(self.client.release_lease(lease.dataset_id))
                return gather_deferreds(release_list)
            get_items.addCallback(release_all)
            releasing_leases = get_items.addActionFinish()
            return timeout(reactor, releasing_leases, 20, Exception('Timed    out    cleaning    up    leases'))
    def cleanup_volumes():
        try:
            api = get_backend_api(self.cluster_uuid)
        except SkipTest:
            return
        async_api = _SyncToThreadedAsyncAPIAdapter.from_api(api)
        def detach_and_destroy_volume(volume):
            d = async_api.detach_volume(volume.blockdevice_id)
            d.addBoth((lambda _: async_api.destroy_volume(volume.blockdevice_id)))
            d.addErrback(write_failure)
            return d
        cleaning_volumes = api_clean_state(u'volumes', async_api.list_volumes, async_api.list_volumes, detach_and_destroy_volume)
        return timeout(reactor, cleaning_volumes, 60, Exception('Timed    out    cleaning    up    volumes'))
    d = DeferredContext(cleanup_leases())
    d.addCallback(cleanup_flocker_containers)
    if remove_foreign_containers:
        d.addCallback(cleanup_all_containers)
    d.addCallback(cleanup_datasets)
    d.addCallback((lambda _: cleanup_volumes()))
    return d.result
