in aws-iot-scheduledaudit/src/main/java/com/amazonaws/iot/scheduledaudit/UpdateHandler.java [90:149]
void updateTags(AmazonWebServicesClientProxy proxy,
ResourceHandlerRequest<ResourceModel> request,
String resourceArn,
Logger logger) {
// Note: we're intentionally getting currentTags by calling ListTags rather than getting
// the previous state from CFN. This is in order to overwrite out-of-band changes.
// For example, if we used request.getPreviousResourceTags instead of ListTags, if a user added a new tag
// via TagResource and didn't add it to the template, we wouldn't know about it and wouldn't untag it.
// Yet we should, otherwise the resource wouldn't equate the template.
Set<Tag> currentTags = listTags(proxy, resourceArn, logger);
// Combine all tags in one map that we'll use for the request
Map<String, String> allDesiredTagsMap = new HashMap<>();
if (request.getDesiredResourceTags() != null) {
// DesiredResourceTags includes both model and stack-level tags.
// Reference: https://tinyurl.com/yyxtd7w6
allDesiredTagsMap.putAll(request.getDesiredResourceTags());
}
if (request.getSystemTags() != null) {
// There are also system tags provided separately.
// SystemTags are the default stack-level tags with aws:cloudformation prefix.
allDesiredTagsMap.putAll(request.getSystemTags());
} else {
// System tags should never get updated as they are the stack id, stack name,
// and logical resource id.
logger.log("Unexpectedly, system tags are null in the update request for " + resourceArn);
}
Set<Tag> desiredTags = Translator.translateTagsToSdk(allDesiredTagsMap);
Set<String> desiredTagKeys = desiredTags.stream()
.map(Tag::key)
.collect(Collectors.toSet());
Set<String> tagKeysToDetach = currentTags.stream()
.filter(tag -> !desiredTagKeys.contains(tag.key()))
.map(Tag::key)
.collect(Collectors.toSet());
Set<Tag> tagsToAttach = desiredTags.stream()
.filter(tag -> !currentTags.contains(tag))
.collect(Collectors.toSet());
if (!tagsToAttach.isEmpty()) {
TagResourceRequest tagResourceRequest = TagResourceRequest.builder()
.resourceArn(resourceArn)
.tags(tagsToAttach)
.build();
proxy.injectCredentialsAndInvokeV2(tagResourceRequest, iotClient::tagResource);
logger.log(String.format("Called TagResource for %s.", resourceArn));
}
if (!tagKeysToDetach.isEmpty()) {
UntagResourceRequest untagResourceRequest = UntagResourceRequest.builder()
.resourceArn(resourceArn)
.tagKeys(tagKeysToDetach)
.build();
proxy.injectCredentialsAndInvokeV2(untagResourceRequest, iotClient::untagResource);
logger.log(String.format("Called UntagResource for %s.", resourceArn));
}
}