Set tags for a resource. Normally a VM name or instance_id is passed in,
    but a resource_id may be passed instead. If both are passed in, the
    instance_id will be used.

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a set_tags mymachine tag1=somestuff tag2='Other stuff'
        salt-cloud -a set_tags resource_id=vol-3267ab32 tag=somestuff

def set_tags(name=None,
             tags=None,
             call=None,
             location=None,
             instance_id=None,
             resource_id=None,
             kwargs=None):  # pylint: disable=W0613
    '''
    Set tags for a resource. Normally a VM name or instance_id is passed in,
    but a resource_id may be passed instead. If both are passed in, the
    instance_id will be used.

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a set_tags mymachine tag1=somestuff tag2='Other stuff'
        salt-cloud -a set_tags resource_id=vol-3267ab32 tag=somestuff
    '''
    if kwargs is None:
        kwargs = {}

    if location is None:
        location = get_location()

    if instance_id is None:
        if 'resource_id' in kwargs:
            resource_id = kwargs['resource_id']
            del kwargs['resource_id']

        if 'instance_id' in kwargs:
            instance_id = kwargs['instance_id']
            del kwargs['instance_id']

        if resource_id is None:
            if instance_id is None:
                instance_id = _get_node(name=name, instance_id=None, location=location)['instanceId']
        else:
            instance_id = resource_id

    # This second check is a safety, in case the above still failed to produce
    # a usable ID
    if instance_id is None:
        return {
            'Error': 'A valid instance_id or resource_id was not specified.'
        }

    params = {'Action': 'CreateTags',
              'ResourceId.1': instance_id}

    log.debug('Tags to set for %s: %s', name, tags)

    if kwargs and not tags:
        tags = kwargs

    for idx, (tag_k, tag_v) in enumerate(six.iteritems(tags)):
        params['Tag.{0}.Key'.format(idx)] = tag_k
        params['Tag.{0}.Value'.format(idx)] = tag_v

    attempts = 0
    while attempts < aws.AWS_MAX_RETRIES:
        aws.query(params,
                           setname='tagSet',
                           location=location,
                           provider=get_provider(),
                           opts=__opts__,
                           sigver='4')

        settags = get_tags(
            instance_id=instance_id, call='action', location=location
        )

        log.debug('Setting the tags returned: %s', settags)

        failed_to_set_tags = False
        for tag in settags:
            if tag['key'] not in tags:
                # We were not setting this tag
                continue

            if tag.get('value') is None and tags.get(tag['key']) == '':
                # This is a correctly set tag with no value
                continue

            if six.text_type(tags.get(tag['key'])) != six.text_type(tag['value']):
                # Not set to the proper value!?
                log.debug(
                    'Setting the tag %s returned %s instead of %s',
                    tag['key'], tags.get(tag['key']), tag['value']
                )
                failed_to_set_tags = True
                break

        if failed_to_set_tags:
            log.warning('Failed to set tags. Remaining attempts %s', attempts)
            attempts += 1
            aws.sleep_exponential_backoff(attempts)
            continue

        return settags

    raise SaltCloudSystemExit(
        'Failed to set tags on {0}!'.format(name)
    )