Private function that returns an iterator over all CloudFront distributions.
    The caller is responsible for all boto-related error handling.

    name
        (Optional) Only yield the distribution with the given name

def _list_distributions(
    conn,
    name=None,
    region=None,
    key=None,
    keyid=None,
    profile=None,
):
    '''
    Private function that returns an iterator over all CloudFront distributions.
    The caller is responsible for all boto-related error handling.

    name
        (Optional) Only yield the distribution with the given name
    '''
    for dl_ in conn.get_paginator('list_distributions').paginate():
        distribution_list = dl_['DistributionList']
        if 'Items' not in distribution_list:
            # If there are no items, AWS omits the `Items` key for some reason
            continue
        for partial_dist in distribution_list['Items']:
            tags = conn.list_tags_for_resource(Resource=partial_dist['ARN'])
            tags = dict(
                (kv['Key'], kv['Value']) for kv in tags['Tags']['Items']
            )

            id_ = partial_dist['Id']
            if 'Name' not in tags:
                log.warning('CloudFront distribution %s has no Name tag.', id_)
                continue
            distribution_name = tags.pop('Name', None)
            if name is not None and distribution_name != name:
                continue

            # NOTE: list_distributions() returns a DistributionList,
            # which nominally contains a list of Distribution objects.
            # However, they are mangled in that they are missing values
            # (`Logging`, `ActiveTrustedSigners`, and `ETag` keys)
            # and moreover flatten the normally nested DistributionConfig
            # attributes to the top level.
            # Hence, we must call get_distribution() to get the full object,
            # and we cache these objects to help lessen API calls.
            distribution = _cache_id(
                'cloudfront',
                sub_resource=distribution_name,
                region=region,
                key=key,
                keyid=keyid,
                profile=profile,
            )
            if distribution:
                yield (distribution_name, distribution)
                continue

            dist_with_etag = conn.get_distribution(Id=id_)
            distribution = {
                'distribution': dist_with_etag['Distribution'],
                'etag': dist_with_etag['ETag'],
                'tags': tags,
            }
            _cache_id(
                'cloudfront',
                sub_resource=distribution_name,
                resource_id=distribution,
                region=region,
                key=key,
                keyid=keyid,
                profile=profile,
            )
            yield (distribution_name, distribution)