code: func (t *awsTagging) createTags(client EC2, resourceID string, lifecycle ResourceLifecycle, additionalTags map[string]string) error {
  	tags := t.buildTags(lifecycle, additionalTags)
  
  	if tags == nil || len(tags) == 0 {
  		return nil
  	}
  
  	var awsTags []*ec2.Tag
  	for k, v := range tags {
  		tag := &ec2.Tag{
  			Key:   aws.String(k),
  			Value: aws.String(v),
  		}
  		awsTags = append(awsTags, tag)
  	}
  
  	backoff := wait.Backoff{
  		Duration: createTagInitialDelay,
  		Factor:   createTagFactor,
  		Steps:    createTagSteps,
  	}
  	request := &ec2.CreateTagsInput{}
  	request.Resources = []*string{&resourceID}
  	request.Tags = awsTags
  
  	var lastErr error
  	err := wait.ExponentialBackoff(backoff, func() (bool, error) {
  		_, err := client.CreateTags(request)
  		if err == nil {
  			return true, nil
  		}
  
  		// We could check that the error is retryable, but the error code changes based on what we are tagging
  		// SecurityGroup: InvalidGroup.NotFound
  		klog.V(2).Infof("Failed to create tags; will retry.  Error was %q", err)
  		lastErr = err
  		return false, nil
  	})
  	if err == wait.ErrWaitTimeout {
  		// return real CreateTags error instead of timeout
  		err = lastErr
  	}
  	return err
  }
docs: // createTags calls EC2 CreateTags, but adds retry-on-failure logic
  // We retry mainly because if we create an object, we cannot tag it until it is "fully created" (eventual consistency)
  // The error code varies though (depending on what we are tagging), so we simply retry on all errors