Ensure a given CloudFront Origin Access Identity exists.

    .. note::
        Due to the unavailibity of ANY other way to store stateful idempotency
        information about Origin Access Identities (including resource tags),
        the Comment attribute (as the only user-settable attribute without
        weird self-blocking semantics) is necessarily utilized to store the
        Salt state signifier, which is used to determine resource existence and
        state. That said, to enable SOME usability of this field, only the
        value up to the first colon character is taken as the signifier, while
        anything afterward is free-form and ignored by Salt.

    name (string)
        Name of the state definition.

    Name (string)
        Name of the resource (for purposes of Salt's idempotency). If not provided, the value of
        `name` will be used.

    Comment
        Free-form text description of the origin access identity.

    region (string)
        Region to connect to

    key (string)
        Secret key to use

    keyid (string)
        Access key to use

    profile (dict or string)
        Dict, or pillar key pointing to a dict, containing AWS region/key/keyid.

    Example:

    .. code-block:: yaml

        my_OAI:
          boto_cloudfront.origin_access_identity_present:
          - Comment: Simply ensures an OAI named my_OAI exists

def origin_access_identity_present(name, region=None, key=None, keyid=None, profile=None, **kwargs):
    '''
    Ensure a given CloudFront Origin Access Identity exists.

    .. note::
        Due to the unavailibity of ANY other way to store stateful idempotency
        information about Origin Access Identities (including resource tags),
        the Comment attribute (as the only user-settable attribute without
        weird self-blocking semantics) is necessarily utilized to store the
        Salt state signifier, which is used to determine resource existence and
        state. That said, to enable SOME usability of this field, only the
        value up to the first colon character is taken as the signifier, while
        anything afterward is free-form and ignored by Salt.

    name (string)
        Name of the state definition.

    Name (string)
        Name of the resource (for purposes of Salt's idempotency). If not provided, the value of
        `name` will be used.

    Comment
        Free-form text description of the origin access identity.

    region (string)
        Region to connect to

    key (string)
        Secret key to use

    keyid (string)
        Access key to use

    profile (dict or string)
        Dict, or pillar key pointing to a dict, containing AWS region/key/keyid.

    Example:

    .. code-block:: yaml

        my_OAI:
          boto_cloudfront.origin_access_identity_present:
          - Comment: Simply ensures an OAI named my_OAI exists

    '''
    ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}
    kwargs = {k: v for k, v in kwargs.items() if not k.startswith('_')}
    authargs = {'region': region, 'key': key, 'keyid': keyid, 'profile': profile}
    Name = kwargs.get('Name', name)
    # Munge Name into the Comment field...
    Comment = '{}:{}'.format(Name, kwargs['Comment']) if kwargs.get('Comment') else Name

    # Current state of the thing?
    res = __salt__['boto_cloudfront.get_cloud_front_origin_access_identities_by_comment'](
            Comment=Name, region=region, key=key, keyid=keyid, profile=profile)
    if res is None:
        msg = 'Error determining current state of origin access identity `{}`.'.format(Name)
        log.error(msg)
        ret['comment'] = msg
        ret['result'] = False
        return ret
    if len(res) > 1:
        msg = 'Multiple CloudFront origin access identities matched `{}`.'.format(Name)
        log.error(msg)
        ret['comment'] = msg
        ret['result'] = False
        return ret

    exists = bool(res)
    if not exists:
        CloudFrontOriginAccessIdentityConfig = {'Comment': Comment,
                                                'CallerReference': str(uuid.uuid4())}
        if __opts__['test']:
            ret['result'] = None
            ret['comment'] = 'CloudFront origin access identity `{}` would be created.'.format(Name)
            new = {'CloudFrontOriginAccessIdentityConfig': CloudFrontOriginAccessIdentityConfig}
            ret['pchanges'] = {'old': None, 'new': new}
            return ret
        kwargs = {'CloudFrontOriginAccessIdentityConfig': CloudFrontOriginAccessIdentityConfig}
        kwargs.update(authargs)
        res = __salt__['boto_cloudfront.create_cloud_front_origin_access_identity'](**kwargs)
        if res is None:
            ret['result'] = False
            msg = 'Failed to create CloudFront origin access identity `{}`.'.format(Name)
            log.error(msg)
            ret['comment'] = msg
            return ret
        ret['comment'] = 'Created CloudFrong origin access identity`{}`.'.format(Name)
        ret['changes'] = {'old': None, 'new': res}
        return ret
    else:
        currentId = res[0]['Id']
        current = __salt__['boto_cloudfront.get_cloud_front_origin_access_identity'](Id=currentId,
                **authargs)
        currentETag = current['ETag']
        currentOAIC = current['CloudFrontOriginAccessIdentity']['CloudFrontOriginAccessIdentityConfig']
        new = copy.deepcopy(currentOAIC)
        new.update({'Comment': Comment})  # Currently the only updatable element :-/
        if currentOAIC == new:
            msg = 'CloudFront origin access identity `{}` is in the correct state.'.format(Name)
            log.info(msg)
            ret['comment'] = msg
            return ret
        if __opts__['test']:
            ret['result'] = None
            ret['comment'] = 'CloudFront origin access identity `{}` would be updated.'.format(Name)
            ret['pchanges'] = {'old': currentOAIC, 'new': new}
            return ret
        kwargs = {'CloudFrontOriginAccessIdentityConfig': new,
                  'Id': currentId, 'IfMatch': currentETag}
        kwargs.update(authargs)
        res = __salt__['boto_cloudfront.update_cloud_front_origin_access_identity'](**kwargs)
        if res is None:
            ret['result'] = False
            msg = 'Error occurred while updating origin access identity `{}`.'.format(Name)
            log.error(msg)
            ret['comment'] = msg
            return ret
        ret['comment'] = 'CloudFront origin access identity `{}` config updated.'.format(Name)
        ret['changes'] = {'old': currentOAIC, 'new': new}
        return ret