From 72bd7ace0e76eca94f2a4a1aa2d7c0fae6c3c958 Mon Sep 17 00:00:00 2001 From: Moataz Mohamed Date: Thu, 9 Nov 2023 14:55:00 +0000 Subject: [PATCH] [Common][All] Remove silent failure mechanism and throw unauthorized tagging exception. --- .../amazon/rds/common/handler/Tagging.java | 68 ++++---- .../rds/common/handler/TaggingContext.java | 1 - .../rds/common/handler/TaggingTest.java | 52 ++---- .../customdbengineversion/BaseHandlerStd.java | 6 +- .../customdbengineversion/CreateHandler.java | 2 +- .../CreateHandlerTest.java | 71 ++------ .../UpdateHandlerTest.java | 22 ++- aws-rds-dbcluster/docs/README.md | 12 ++ .../amazon/rds/dbcluster/BaseHandlerStd.java | 2 +- .../amazon/rds/dbcluster/CreateHandler.java | 6 +- .../rds/dbcluster/CreateHandlerTest.java | 96 +++-------- .../rds/dbclusterendpoint/BaseHandlerStd.java | 2 +- .../rds/dbclusterendpoint/CreateHandler.java | 2 +- .../rds/dbclusterendpoint/ReadHandler.java | 2 +- .../dbclusterendpoint/CreateHandlerTest.java | 68 ++------ .../dbclusterendpoint/UpdateHandlerTest.java | 4 +- .../BaseHandlerStd.java | 6 +- .../CreateHandler.java | 2 +- .../dbclusterparametergroup/ReadHandler.java | 2 +- .../CreateHandlerTest.java | 44 ++--- .../amazon/rds/dbinstance/BaseHandlerStd.java | 2 +- .../amazon/rds/dbinstance/CreateHandler.java | 2 +- .../rds/dbinstance/CreateHandlerTest.java | 163 ++++-------------- .../rds/dbparametergroup/BaseHandlerStd.java | 8 +- .../rds/dbparametergroup/CreateHandler.java | 2 +- .../rds/dbparametergroup/ReadHandler.java | 2 +- .../rds/dbsubnetgroup/BaseHandlerStd.java | 6 +- .../rds/dbsubnetgroup/CreateHandler.java | 2 +- .../amazon/rds/dbsubnetgroup/ReadHandler.java | 2 +- .../rds/eventsubscription/BaseHandlerStd.java | 6 +- .../rds/eventsubscription/CreateHandler.java | 2 +- .../rds/eventsubscription/ReadHandler.java | 2 +- .../rds/optiongroup/BaseHandlerStd.java | 6 +- .../amazon/rds/optiongroup/CreateHandler.java | 2 +- .../amazon/rds/optiongroup/ReadHandler.java | 2 +- .../rds/optiongroup/CreateHandlerTest.java | 80 ++------- .../rds/optiongroup/UpdateHandlerTest.java | 11 +- 37 files changed, 224 insertions(+), 546 deletions(-) diff --git a/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/Tagging.java b/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/Tagging.java index 1aa97e351..f45581b8f 100644 --- a/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/Tagging.java +++ b/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/Tagging.java @@ -22,7 +22,6 @@ import software.amazon.awssdk.services.rds.model.Tag; import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; import software.amazon.cloudformation.proxy.HandlerErrorCode; -import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.rds.common.error.ErrorCode; @@ -30,26 +29,27 @@ import software.amazon.rds.common.error.ErrorStatus; public final class Tagging { - public static final ErrorRuleSet SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET = ErrorRuleSet + public static final ErrorRuleSet IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET = ErrorRuleSet .extend(ErrorRuleSet.EMPTY_RULE_SET) - .withErrorCodes(ErrorStatus.ignore(OperationStatus.IN_PROGRESS), + .withErrorCodes(ErrorStatus.ignore(), ErrorCode.AccessDenied, ErrorCode.AccessDeniedException) .build(); - public static final ErrorRuleSet SOFT_FAIL_TAG_ERROR_RULE_SET = ErrorRuleSet + public static final ErrorRuleSet STACK_TAGS_ERROR_RULE_SET = ErrorRuleSet .extend(ErrorRuleSet.EMPTY_RULE_SET) - .withErrorCodes(ErrorStatus.ignore(), + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.UnauthorizedTaggingOperation), ErrorCode.AccessDenied, ErrorCode.AccessDeniedException ).build(); - public static final ErrorRuleSet HARD_FAIL_TAG_ERROR_RULE_SET = ErrorRuleSet + public static final ErrorRuleSet RESOURCE_TAG_ERROR_RULE_SET = ErrorRuleSet .extend(ErrorRuleSet.EMPTY_RULE_SET) .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AccessDenied), ErrorCode.AccessDenied, ErrorCode.AccessDeniedException ).build(); + public static final String RDS_ADD_TAGS_TO_RESOURCE_ACTION = "rds:AddTagsToResource"; public static TagSet exclude(final TagSet from, final TagSet what) { final Set systemTags = new LinkedHashSet<>(from.getSystemTags()); @@ -194,56 +194,52 @@ private static RemoveTagsFromResourceRequest removeTagsFromResourceRequest( .build(); } - public static ErrorRuleSet bestEffortErrorRuleSet( + public static ErrorRuleSet getUpdateTagsAccessDeniedRuleSet( final TagSet tagsToAdd, final TagSet tagsToRemove ) { - return bestEffortErrorRuleSet(tagsToAdd, tagsToRemove, SOFT_FAIL_TAG_ERROR_RULE_SET, HARD_FAIL_TAG_ERROR_RULE_SET); + return getUpdateTagsAccessDeniedRuleSet(tagsToAdd, tagsToRemove, STACK_TAGS_ERROR_RULE_SET, RESOURCE_TAG_ERROR_RULE_SET); } - public static ErrorRuleSet bestEffortErrorRuleSet( + public static ErrorRuleSet getUpdateTagsAccessDeniedRuleSet( final TagSet tagsToAdd, final TagSet tagsToRemove, - final ErrorRuleSet softFailErrorRuleSet, - final ErrorRuleSet hardFailErrorRuleSet + final ErrorRuleSet stackTagsErrorRuleSet, + final ErrorRuleSet resourceTagsErrorRuleSet ) { - // Only soft fail if the customer provided no resource-level tags + /* If the tagging operation comes across an AccessDenied error, we will throw an UnauthorizedTaggingOperation + errorCode for stack level tags. For Resource tags, if they are included, we will throw an AccessDenied error. + This is done to ensure backward compatibility. */ if (tagsToAdd.getResourceTags().isEmpty() && tagsToRemove.getResourceTags().isEmpty()) { - return softFailErrorRuleSet; + return stackTagsErrorRuleSet; } - return hardFailErrorRuleSet; + return resourceTagsErrorRuleSet; } - public static ProgressEvent safeCreate( + public static ProgressEvent createWithTaggingFallback( final AmazonWebServicesClientProxy proxy, final ProxyClient rdsProxyClient, final HandlerMethod handlerMethod, final ProgressEvent progress, final Tagging.TagSet allTags ) { - return progress.then(p -> { - final C context = p.getCallbackContext(); - if (context.getTaggingContext().isSoftFailTags()) { - return p; + final ProgressEvent allTagsResult = handlerMethod.invoke(proxy, rdsProxyClient, progress, allTags); + if (allTagsResult.isFailed()) { + if (isUnauthorizedTaggingFailure(allTagsResult, allTags)) { + allTagsResult.setErrorCode(HandlerErrorCode.UnauthorizedTaggingOperation); } - final ProgressEvent allTagsResult = handlerMethod.invoke(proxy, rdsProxyClient, p, allTags); - if (allTagsResult.isFailed()) { - if (HandlerErrorCode.AccessDenied.equals(allTagsResult.getErrorCode())) { - context.getTaggingContext().setSoftFailTags(true); - return ProgressEvent.progress(allTagsResult.getResourceModel(), context); - } - return allTagsResult; - } - allTagsResult.getCallbackContext().getTaggingContext().setAddTagsComplete(true); return allTagsResult; - }).then(p -> { - final C context = p.getCallbackContext(); - if (!context.getTaggingContext().isSoftFailTags()) { - return p; - } - final Tagging.TagSet systemTags = Tagging.TagSet.builder().systemTags(allTags.getSystemTags()).build(); - return handlerMethod.invoke(proxy, rdsProxyClient, p, systemTags); - }); + } + allTagsResult.getCallbackContext().getTaggingContext().setAddTagsComplete(true); + return allTagsResult; + } + + private static boolean isUnauthorizedTaggingFailure(final ProgressEvent allTagsResult, + final TagSet allTags) { + return HandlerErrorCode.AccessDenied.equals(allTagsResult.getErrorCode()) && + allTags.getResourceTags().isEmpty() && + allTagsResult.getMessage() != null && + allTagsResult.getMessage().contains(RDS_ADD_TAGS_TO_RESOURCE_ACTION); } private static void addToMapIfAbsent(Map allTags, Collection tags) { diff --git a/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/TaggingContext.java b/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/TaggingContext.java index 029d12daa..efc0188fe 100644 --- a/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/TaggingContext.java +++ b/aws-rds-cfn-common/src/main/java/software/amazon/rds/common/handler/TaggingContext.java @@ -5,7 +5,6 @@ @lombok.ToString @lombok.EqualsAndHashCode public class TaggingContext { - private boolean softFailTags; private boolean addTagsComplete; public interface Provider { diff --git a/aws-rds-cfn-common/src/test/java/software/amazon/rds/common/handler/TaggingTest.java b/aws-rds-cfn-common/src/test/java/software/amazon/rds/common/handler/TaggingTest.java index 78ef94189..e4bc2c674 100644 --- a/aws-rds-cfn-common/src/test/java/software/amazon/rds/common/handler/TaggingTest.java +++ b/aws-rds-cfn-common/src/test/java/software/amazon/rds/common/handler/TaggingTest.java @@ -18,7 +18,6 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; @@ -40,7 +39,6 @@ import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import software.amazon.rds.common.error.ErrorRuleSet; import software.amazon.rds.common.error.ErrorStatus; -import software.amazon.rds.common.error.IgnoreErrorStatus; import software.amazon.rds.common.error.UnexpectedErrorStatus; import software.amazon.rds.common.logging.LoggingProxyClient; import software.amazon.rds.common.logging.RequestLogger; @@ -48,7 +46,7 @@ public class TaggingTest extends ProxyClientTestBase { - private final static String FAILED_MSG = "Test message: failed"; + private final static String FAILED_MSG = "User is not authorized to do rds:AddTagsToResource action"; final Set SYSTEM_TAGS = Stream.of( Tag.builder().key("system-tag-key-1").value("system-tag-value-1").build(), @@ -145,9 +143,9 @@ void test_SoftFailErrorRuleSet_AwsServiceException_AccessDenied() { .errorCode("AccessDenied") .build()) .build(); - final ErrorRuleSet ruleSet = Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET; + final ErrorRuleSet ruleSet = Tagging.STACK_TAGS_ERROR_RULE_SET; final ErrorStatus status = ruleSet.handle(exception); - assertThat(status).isInstanceOf(IgnoreErrorStatus.class); + assertThat(status).isInstanceOf(ErrorStatus.class); } @Test @@ -157,7 +155,7 @@ void test_SoftFailErrorRuleSet_AwsServiceException_OtherCode() { .errorCode("InternalFailure") .build()) .build(); - final ErrorRuleSet ruleSet = Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET; + final ErrorRuleSet ruleSet = Tagging.STACK_TAGS_ERROR_RULE_SET; final ErrorStatus status = ruleSet.handle(exception); assertThat(status).isInstanceOf(UnexpectedErrorStatus.class); } @@ -165,7 +163,7 @@ void test_SoftFailErrorRuleSet_AwsServiceException_OtherCode() { @Test void test_SoftFailErrorRuleSet_OtherException() { final Exception exception = new RuntimeException("test exception"); - final ErrorRuleSet ruleSet = Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET; + final ErrorRuleSet ruleSet = Tagging.STACK_TAGS_ERROR_RULE_SET; final ErrorStatus status = ruleSet.handle(exception); assertThat(status).isInstanceOf(UnexpectedErrorStatus.class); } @@ -272,7 +270,7 @@ void test_exclude() { @Test void test_bestEffortErrorRuleSet_emptyResourceTags() { - final ErrorRuleSet errorRuleSet = Tagging.bestEffortErrorRuleSet( + final ErrorRuleSet errorRuleSet = Tagging.getUpdateTagsAccessDeniedRuleSet( Tagging.TagSet.builder() .stackTags(Collections.singleton(Tag.builder().build())) .stackTags(Collections.singleton(Tag.builder().build())) @@ -283,12 +281,12 @@ void test_bestEffortErrorRuleSet_emptyResourceTags() { .build() ); - assertThat(errorRuleSet).isEqualTo(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET); + assertThat(errorRuleSet).isEqualTo(Tagging.STACK_TAGS_ERROR_RULE_SET); } @Test void test_bestEffortErrorRuleSet_nonEmptyResourceTags() { - assertThat(Tagging.bestEffortErrorRuleSet( + assertThat(Tagging.getUpdateTagsAccessDeniedRuleSet( Tagging.TagSet.builder() .stackTags(Collections.singleton(Tag.builder().build())) .stackTags(Collections.singleton(Tag.builder().build())) @@ -299,9 +297,9 @@ void test_bestEffortErrorRuleSet_nonEmptyResourceTags() { .stackTags(Collections.singleton(Tag.builder().build())) .resourceTags(Collections.singleton(Tag.builder().build())) .build() - )).isEqualTo(Tagging.HARD_FAIL_TAG_ERROR_RULE_SET); + )).isEqualTo(Tagging.RESOURCE_TAG_ERROR_RULE_SET); - assertThat(Tagging.bestEffortErrorRuleSet( + assertThat(Tagging.getUpdateTagsAccessDeniedRuleSet( Tagging.TagSet.builder() .stackTags(Collections.singleton(Tag.builder().build())) .stackTags(Collections.singleton(Tag.builder().build())) @@ -312,9 +310,9 @@ void test_bestEffortErrorRuleSet_nonEmptyResourceTags() { .stackTags(Collections.singleton(Tag.builder().build())) .resourceTags(Collections.singleton(Tag.builder().build())) .build() - )).isEqualTo(Tagging.HARD_FAIL_TAG_ERROR_RULE_SET); + )).isEqualTo(Tagging.RESOURCE_TAG_ERROR_RULE_SET); - assertThat(Tagging.bestEffortErrorRuleSet( + assertThat(Tagging.getUpdateTagsAccessDeniedRuleSet( Tagging.TagSet.builder() .stackTags(Collections.singleton(Tag.builder().build())) .stackTags(Collections.singleton(Tag.builder().build())) @@ -325,7 +323,7 @@ void test_bestEffortErrorRuleSet_nonEmptyResourceTags() { .stackTags(Collections.singleton(Tag.builder().build())) .resourceTags(Collections.emptySet()) .build() - )).isEqualTo(Tagging.HARD_FAIL_TAG_ERROR_RULE_SET); + )).isEqualTo(Tagging.RESOURCE_TAG_ERROR_RULE_SET); } @Test @@ -343,7 +341,7 @@ public void safeCreate_allTagsSuccess() { Mockito.when(handlerMethod.invoke(Mockito.any(), Mockito.any(), Mockito.any(ProgressEvent.class), Mockito.any(Tagging.TagSet.class))) .thenReturn(ProgressEvent.success(null, progress.getCallbackContext())); - final ProgressEvent result = Tagging.safeCreate(null, null, handlerMethod, progress, allTags); + final ProgressEvent result = Tagging.createWithTaggingFallback(null, null, handlerMethod, progress, allTags); Assertions.assertThat(result.isSuccess()).isTrue(); Assertions.assertThat(result.getCallbackContext().getTaggingContext().isAddTagsComplete()).isTrue(); @@ -359,29 +357,18 @@ public void safeCreate_allTagsFailAccessDenied() { final Tagging.TagSet allTags = Tagging.TagSet.builder() .systemTags(SYSTEM_TAGS) .stackTags(STACK_TAGS) - .resourceTags(RESOURCE_TAGS) .build(); final HandlerMethod handlerMethod = Mockito.mock(HandlerMethod.class); Mockito.when(handlerMethod.invoke(Mockito.any(), Mockito.any(), Mockito.any(ProgressEvent.class), Mockito.any(Tagging.TagSet.class))) - .thenReturn(ProgressEvent.failed(null, progress.getCallbackContext(), HandlerErrorCode.AccessDenied, FAILED_MSG)) - .thenReturn(ProgressEvent.success(null, progress.getCallbackContext())); + .thenReturn(ProgressEvent.failed(null, progress.getCallbackContext(), HandlerErrorCode.AccessDenied, FAILED_MSG)); - final ProgressEvent result = Tagging.safeCreate(null, null, handlerMethod, progress, allTags); + final ProgressEvent result = Tagging.createWithTaggingFallback(null, null, handlerMethod, progress, allTags); - Assertions.assertThat(result.isSuccess()).isTrue(); - Assertions.assertThat(result.getCallbackContext().getTaggingContext().isSoftFailTags()).isTrue(); + Assertions.assertThat(result.isFailed()).isTrue(); + Assertions.assertThat(result.getErrorCode()).isEqualTo(HandlerErrorCode.UnauthorizedTaggingOperation); Assertions.assertThat(result.getCallbackContext().getTaggingContext().isAddTagsComplete()).isFalse(); - - ArgumentCaptor captor = ArgumentCaptor.forClass(Tagging.TagSet.class); - Mockito.verify(handlerMethod, Mockito.times(2)).invoke(Mockito.any(), Mockito.any(), Mockito.any(ProgressEvent.class), captor.capture()); - - final Tagging.TagSet tagSetInvoke1 = captor.getAllValues().get(0); - final Tagging.TagSet tagSetInvoke2 = captor.getAllValues().get(1); - - Assertions.assertThat(tagSetInvoke1).isEqualTo(allTags); - Assertions.assertThat(tagSetInvoke2).isEqualTo(Tagging.TagSet.builder().systemTags(SYSTEM_TAGS).build()); } @Test @@ -399,11 +386,10 @@ public void safeCreate_allTagsFailGeneric() { Mockito.when(handlerMethod.invoke(Mockito.any(), Mockito.any(), Mockito.any(ProgressEvent.class), Mockito.any(Tagging.TagSet.class))) .thenReturn(ProgressEvent.failed(null, progress.getCallbackContext(), HandlerErrorCode.InternalFailure, FAILED_MSG)); - final ProgressEvent result = Tagging.safeCreate(null, null, handlerMethod, progress, allTags); + final ProgressEvent result = Tagging.createWithTaggingFallback(null, null, handlerMethod, progress, allTags); Assertions.assertThat(result.isFailed()).isTrue(); Assertions.assertThat(result.getCallbackContext().getTaggingContext().isAddTagsComplete()).isFalse(); - Assertions.assertThat(result.getCallbackContext().getTaggingContext().isSoftFailTags()).isFalse(); Mockito.verify(handlerMethod, Mockito.times(1)) .invoke(Mockito.any(), Mockito.any(), Mockito.any(ProgressEvent.class), Mockito.any(Tagging.TagSet.class)); diff --git a/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/BaseHandlerStd.java b/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/BaseHandlerStd.java index 7dcd3d39c..7ba8177d7 100644 --- a/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/BaseHandlerStd.java +++ b/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/BaseHandlerStd.java @@ -185,11 +185,9 @@ private ProgressEvent getTaggingErrorRuleSet(fin progress, exception, DEFAULT_CUSTOM_DB_ENGINE_VERSION_ERROR_RULE_SET.extendWith( - Tagging.bestEffortErrorRuleSet( + Tagging.getUpdateTagsAccessDeniedRuleSet( tagsToAdd, - tagsToRemove, - Tagging.SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET, - Tagging.HARD_FAIL_TAG_ERROR_RULE_SET + tagsToRemove ) ) ); diff --git a/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/CreateHandler.java b/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/CreateHandler.java index 5ef741918..497ac20ab 100644 --- a/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/CreateHandler.java +++ b/aws-rds-customdbengineversion/src/main/java/software/amazon/rds/customdbengineversion/CreateHandler.java @@ -74,7 +74,7 @@ private ProgressEvent safeCreateCustomEngineVers final ProxyClient proxyClient, final ProgressEvent progress, final Tagging.TagSet allTags) { - return Tagging.safeCreate(proxy, proxyClient, this::createCustomEngineVersion, progress, allTags) + return Tagging.createWithTaggingFallback(proxy, proxyClient, this::createCustomEngineVersion, progress, allTags) .then(p -> Commons.execOnce(p, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(allTags.getStackTags()) diff --git a/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/CreateHandlerTest.java b/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/CreateHandlerTest.java index 55db057b6..ddd31a482 100644 --- a/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/CreateHandlerTest.java +++ b/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/CreateHandlerTest.java @@ -1,6 +1,7 @@ package software.amazon.rds.customdbengineversion; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -9,6 +10,7 @@ import static org.mockito.Mockito.when; import java.time.Duration; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import org.assertj.core.api.Assertions; @@ -16,6 +18,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.platform.commons.util.StringUtils; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -177,47 +180,26 @@ public void handleRequest_AccessDeniedTagging() { .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(CreateCustomDbEngineVersionResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); + ).build()); final ProgressEvent progress = test_handleRequest_base( new CallbackContext(), ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_ENGINE_VERSION_AVAILABLE, + null, null, () -> RESOURCE_MODEL.toBuilder() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.AccessDenied) ); - Assertions.assertThat(progress.getCallbackContext().isAddTagsComplete()).isTrue(); - Assertions.assertThat(progress.getCallbackContext().getTaggingContext().isSoftFailTags()).isTrue(); - ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateCustomDbEngineVersionRequest.class); - verify(rdsProxy.client(), times(2)).createCustomDBEngineVersion(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).createCustomDBEngineVersion(createCaptor.capture()); final CreateCustomDbEngineVersionRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final CreateCustomDbEngineVersionRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(3)).describeDBEngineVersions(any(DescribeDbEngineVersionsRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); } @@ -226,52 +208,33 @@ public void handleRequest_HardFailTagging() { when(rdsProxy.client().createCustomDBEngineVersion(any(CreateCustomDbEngineVersionRequest.class))) .thenThrow( RdsException.builder() - .awsErrorDetails(AwsErrorDetails.builder() - .errorCode(ErrorCode.AccessDeniedException.toString()) - .build() - ).build()) - .thenReturn(CreateCustomDbEngineVersionResponse.builder().build()); - - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenThrow( - RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() ).build()); - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); - test_handleRequest_base( new CallbackContext(), ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_ENGINE_VERSION_AVAILABLE, + null, null, () -> RESOURCE_MODEL.toBuilder() - .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) + .tags(null) .build(), - expectFailed(HandlerErrorCode.AccessDenied) + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); + final Tagging.TagSet expectedRequestTags = Tagging.TagSet.builder() + .stackTags(TAG_SET.getStackTags()) + .systemTags(TAG_SET.getSystemTags()) + .build(); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateCustomDbEngineVersionRequest.class); - verify(rdsProxy.client(), times(2)).createCustomDBEngineVersion(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).createCustomDBEngineVersion(createCaptor.capture()); final CreateCustomDbEngineVersionRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final CreateCustomDbEngineVersionRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(2)).describeDBEngineVersions(any(DescribeDbEngineVersionsRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); + Iterables.toArray(Tagging.translateTagsToSdk(expectedRequestTags), software.amazon.awssdk.services.rds.model.Tag.class)); } } diff --git a/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/UpdateHandlerTest.java b/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/UpdateHandlerTest.java index abb42add4..3395b3e70 100644 --- a/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/UpdateHandlerTest.java +++ b/aws-rds-customdbengineversion/src/test/java/software/amazon/rds/customdbengineversion/UpdateHandlerTest.java @@ -215,7 +215,9 @@ public void handleRequest_HardFailingTaggingOnAddTags() { } @Test - public void handleRequest_SoftFailingTaggingOnRemoveTags() { + public void handleRequest_HardFailWithUnauthorizedTagsOnRemove() { + when(rdsProxy.client().modifyCustomDBEngineVersion(any(ModifyCustomDbEngineVersionRequest.class))) + .thenReturn(ModifyCustomDbEngineVersionResponse.builder().build()); when(rdsProxy.client().removeTagsFromResource(any(RemoveTagsFromResourceRequest.class))) .thenThrow( RdsException.builder().awsErrorDetails(AwsErrorDetails.builder() @@ -226,19 +228,22 @@ public void handleRequest_SoftFailingTaggingOnRemoveTags() { test_handleRequest_base( context, ResourceHandlerRequest.builder() - .previousSystemTags(Translator.translateTagsToRequest(TAG_LIST)) - .systemTags(Translator.translateTagsToRequest(TAG_LIST_EMPTY)), + .previousResourceTags(Translator.translateTagsToRequest(TAG_LIST)) + .desiredResourceTags(Translator.translateTagsToRequest(TAG_LIST_EMPTY)), () -> DB_ENGINE_VERSION_AVAILABLE, () -> RESOURCE_MODEL_BUILDER().build(), - () -> RESOURCE_MODEL_BUILDER().build(), - expectSuccess() + () -> RESOURCE_MODEL_BUILDER().status("inactive").build(), + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); + verify(rdsProxy.client(), times(1)).modifyCustomDBEngineVersion(any(ModifyCustomDbEngineVersionRequest.class)); verify(rdsProxy.client(), times(1)).removeTagsFromResource(any(RemoveTagsFromResourceRequest.class)); } @Test - public void handleRequest_SoftFailingTaggingOnAddTags() { + public void handleRequest_HardFailWithUnauthorizedTagsOnAdd() { + when(rdsProxy.client().modifyCustomDBEngineVersion(any(ModifyCustomDbEngineVersionRequest.class))) + .thenReturn(ModifyCustomDbEngineVersionResponse.builder().build()); when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) .thenThrow( RdsException.builder().awsErrorDetails(AwsErrorDetails.builder() @@ -253,10 +258,11 @@ public void handleRequest_SoftFailingTaggingOnAddTags() { .systemTags(Translator.translateTagsToRequest(TAG_LIST)), () -> DB_ENGINE_VERSION_AVAILABLE, () -> RESOURCE_MODEL_BUILDER().build(), - () -> RESOURCE_MODEL_BUILDER().build(), - expectSuccess() + () -> RESOURCE_MODEL_BUILDER().status("inactive").build(), + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); + verify(rdsProxy.client(), times(1)).modifyCustomDBEngineVersion(any(ModifyCustomDbEngineVersionRequest.class)); verify(rdsProxy.client(), times(1)).addTagsToResource(any(AddTagsToResourceRequest.class)); } } diff --git a/aws-rds-dbcluster/docs/README.md b/aws-rds-dbcluster/docs/README.md index 14e219207..c5360ab99 100644 --- a/aws-rds-dbcluster/docs/README.md +++ b/aws-rds-dbcluster/docs/README.md @@ -32,6 +32,7 @@ To declare this entity in your AWS CloudFormation template, use the following sy "Domain" : String, "DomainIAMRoleName" : String, "EnableCloudwatchLogsExports" : [ String, ... ], + "EnableGlobalWriteForwarding" : Boolean, "EnableHttpEndpoint" : Boolean, "EnableIAMDatabaseAuthentication" : Boolean, "Engine" : String, @@ -98,6 +99,7 @@ Properties: DomainIAMRoleName: String EnableCloudwatchLogsExports: - String + EnableGlobalWriteForwarding: Boolean EnableHttpEndpoint: Boolean EnableIAMDatabaseAuthentication: Boolean Engine: String @@ -348,6 +350,16 @@ _Type_: List of String _Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt) +#### EnableGlobalWriteForwarding + +Specifies whether to enable this DB cluster to forward write operations to the primary cluster of a global cluster (Aurora global database). By default, write operations are not allowed on Aurora DB clusters that are secondary clusters in an Aurora global database. + +_Required_: No + +_Type_: Boolean + +_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt) + #### EnableHttpEndpoint A value that indicates whether to enable the HTTP endpoint for an Aurora Serverless DB cluster. By default, the HTTP endpoint is disabled. diff --git a/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/BaseHandlerStd.java b/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/BaseHandlerStd.java index 286d94d04..b534c89c9 100644 --- a/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/BaseHandlerStd.java +++ b/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/BaseHandlerStd.java @@ -518,7 +518,7 @@ protected ProgressEvent updateTags( return Commons.handleException( progress, exception, - DEFAULT_DB_CLUSTER_ERROR_RULE_SET.extendWith(Tagging.bestEffortErrorRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)) + DEFAULT_DB_CLUSTER_ERROR_RULE_SET.extendWith(Tagging.getUpdateTagsAccessDeniedRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)) ); } diff --git a/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/CreateHandler.java b/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/CreateHandler.java index b8bee7c1d..196149fc8 100644 --- a/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/CreateHandler.java +++ b/aws-rds-dbcluster/src/main/java/software/amazon/rds/dbcluster/CreateHandler.java @@ -71,11 +71,11 @@ protected ProgressEvent handleRequest( return ProgressEvent.progress(model, callbackContext) .then(progress -> { if (isRestoreToPointInTime(model)) { - return Tagging.safeCreate(proxy, rdsProxyClient, this::restoreDbClusterToPointInTime, progress, allTags); + return Tagging.createWithTaggingFallback(proxy, rdsProxyClient, this::restoreDbClusterToPointInTime, progress, allTags); } else if (isRestoreFromSnapshot(model)) { - return Tagging.safeCreate(proxy, rdsProxyClient, this::restoreDbClusterFromSnapshot, progress, allTags); + return Tagging.createWithTaggingFallback(proxy, rdsProxyClient, this::restoreDbClusterFromSnapshot, progress, allTags); } - return Tagging.safeCreate(proxy, rdsProxyClient, this::createDbCluster, progress, allTags); + return Tagging.createWithTaggingFallback(proxy, rdsProxyClient, this::createDbCluster, progress, allTags); }) .then(progress -> Commons.execOnce(progress, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() diff --git a/aws-rds-dbcluster/src/test/java/software/amazon/rds/dbcluster/CreateHandlerTest.java b/aws-rds-dbcluster/src/test/java/software/amazon/rds/dbcluster/CreateHandlerTest.java index d4ca05958..947e6b053 100644 --- a/aws-rds-dbcluster/src/test/java/software/amazon/rds/dbcluster/CreateHandlerTest.java +++ b/aws-rds-dbcluster/src/test/java/software/amazon/rds/dbcluster/CreateHandlerTest.java @@ -169,55 +169,39 @@ public void handleRequest_CreateDbCluster_ServerlessV2ScalingConfiguration() { } @Test - public void handleRequest_CreateDbCluster_AccessDeniedTagging() { + public void handleRequest_CreateDbCluster_UnauthorizedTaggingOperation() { when(rdsProxy.client().createDBCluster(any(CreateDbClusterRequest.class))) .thenThrow( RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(CreateDbClusterResponse.builder().build()); - when(rdsProxy.client().addRoleToDBCluster(any(AddRoleToDbClusterRequest.class))) - .thenReturn(AddRoleToDbClusterResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); + ).build()); test_handleRequest_base( new CallbackContext(), ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DBCLUSTER_ACTIVE, + null, null, () -> RESOURCE_MODEL.toBuilder() .associatedRoles(ImmutableList.of(ROLE)) - .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) + .tags(null) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); + final Tagging.TagSet expectedRequestTags = Tagging.TagSet.builder() + .stackTags(TAG_SET.getStackTags()) + .systemTags(TAG_SET.getSystemTags()) + .build(); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbClusterRequest.class); - verify(rdsProxy.client(), times(2)).createDBCluster(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).createDBCluster(createCaptor.capture()); final CreateDbClusterRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final CreateDbClusterRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(1)).addRoleToDBCluster(any(AddRoleToDbClusterRequest.class)); - verify(rdsProxy.client(), times(4)).describeDBClusters(any(DescribeDbClustersRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); + Iterables.toArray(Tagging.translateTagsToSdk(expectedRequestTags), software.amazon.awssdk.services.rds.model.Tag.class)); } @Test @@ -352,51 +336,28 @@ public void handleRequest_RestoreDbClusterFromSnapshot_AccessDeniedTagging() { .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(RestoreDbClusterFromSnapshotResponse.builder().build()); - when(rdsProxy.client().modifyDBCluster(any(ModifyDbClusterRequest.class))) - .thenReturn(ModifyDbClusterResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - when(rdsProxy.client().describeEvents(any(DescribeEventsRequest.class))) - .thenReturn(DescribeEventsResponse.builder().build()); - - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); + ).build()); test_handleRequest_base( new CallbackContext(), ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DBCLUSTER_ACTIVE, + null, null, () -> RESOURCE_MODEL_ON_RESTORE.toBuilder() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.AccessDenied) ); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(RestoreDbClusterFromSnapshotRequest.class); - verify(rdsProxy.client(), times(2)).restoreDBClusterFromSnapshot(createCaptor.capture()); - verify(rdsProxy.client(), times(1)).describeEvents(any(DescribeEventsRequest.class)); + verify(rdsProxy.client(), times(1)).restoreDBClusterFromSnapshot(createCaptor.capture()); final RestoreDbClusterFromSnapshotRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final RestoreDbClusterFromSnapshotRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(4)).describeDBClusters(any(DescribeDbClustersRequest.class)); - verify(rdsProxy.client(), times(1)).modifyDBCluster(any(ModifyDbClusterRequest.class)); - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); } @Test @@ -567,14 +528,7 @@ public void handleRequest_RestoreDbClusterToPointInTime_AccessDeniedTagging() { .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(RestoreDbClusterToPointInTimeResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - when(rdsProxy.client().modifyDBCluster(any(ModifyDbClusterRequest.class))) - .thenReturn(ModifyDbClusterResponse.builder().build()); - when(rdsProxy.client().describeEvents(any(DescribeEventsRequest.class))) - .thenReturn(DescribeEventsResponse.builder().build()); + ).build()); final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(TAG_SET.getStackTags()) @@ -586,30 +540,20 @@ public void handleRequest_RestoreDbClusterToPointInTime_AccessDeniedTagging() { ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DBCLUSTER_ACTIVE, + null, null, () -> RESOURCE_MODEL_ON_RESTORE_IN_TIME.toBuilder() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.AccessDenied) ); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(RestoreDbClusterToPointInTimeRequest.class); - verify(rdsProxy.client(), times(2)).restoreDBClusterToPointInTime(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).restoreDBClusterToPointInTime(createCaptor.capture()); final RestoreDbClusterToPointInTimeRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final RestoreDbClusterToPointInTimeRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(4)).describeDBClusters(any(DescribeDbClustersRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); } @Test diff --git a/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/BaseHandlerStd.java b/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/BaseHandlerStd.java index 29562e074..a242031b5 100644 --- a/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/BaseHandlerStd.java +++ b/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/BaseHandlerStd.java @@ -119,7 +119,7 @@ protected ProgressEvent updateTags( return Commons.handleException( progress, exception, - DEFAULT_DB_CLUSTER_ENDPOINT_ERROR_RULE_SET.extendWith(Tagging.bestEffortErrorRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)) + DEFAULT_DB_CLUSTER_ENDPOINT_ERROR_RULE_SET.extendWith(Tagging.getUpdateTagsAccessDeniedRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)) ); } return progress; diff --git a/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/CreateHandler.java b/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/CreateHandler.java index c0be00f66..b4e3a9293 100644 --- a/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/CreateHandler.java +++ b/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/CreateHandler.java @@ -54,7 +54,7 @@ protected ProgressEvent handleRequest( .toString()); } return ProgressEvent.progress(model, callbackContext) - .then(progress -> Tagging.safeCreate(proxy, proxyClient, this::createDbClusterEndpoint, progress, allTags)) + .then(progress -> Tagging.createWithTaggingFallback(proxy, proxyClient, this::createDbClusterEndpoint, progress, allTags)) .then(progress -> Commons.execOnce(progress, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(Tagging.translateTagsToSdk(request.getDesiredResourceTags())) diff --git a/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/ReadHandler.java b/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/ReadHandler.java index bc983ab59..9babbde4c 100644 --- a/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/ReadHandler.java +++ b/aws-rds-dbclusterendpoint/src/main/java/software/amazon/rds/dbclusterendpoint/ReadHandler.java @@ -73,7 +73,7 @@ protected ProgressEvent readTags( return Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_DB_CLUSTER_ENDPOINT_ERROR_RULE_SET.extendWith(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET) + DEFAULT_DB_CLUSTER_ENDPOINT_ERROR_RULE_SET.extendWith(Tagging.IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET) ); } return ProgressEvent.success(model, context); diff --git a/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/CreateHandlerTest.java b/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/CreateHandlerTest.java index e4f0614c7..e227eac8b 100644 --- a/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/CreateHandlerTest.java +++ b/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/CreateHandlerTest.java @@ -26,8 +26,6 @@ import lombok.Getter; import software.amazon.awssdk.awscore.exception.AwsErrorDetails; import software.amazon.awssdk.services.rds.RdsClient; -import software.amazon.awssdk.services.rds.model.AddTagsToResourceRequest; -import software.amazon.awssdk.services.rds.model.AddTagsToResourceResponse; import software.amazon.awssdk.services.rds.model.CreateDbClusterEndpointRequest; import software.amazon.awssdk.services.rds.model.CreateDbClusterEndpointResponse; import software.amazon.awssdk.services.rds.model.DescribeDbClusterEndpointsRequest; @@ -180,13 +178,7 @@ public void handleRequest_AccessDeniedTagging() { .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(CreateDbClusterEndpointResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - - when(rdsProxy.client().listTagsForResource(any(ListTagsForResourceRequest.class))) - .thenReturn(ListTagsForResourceResponse.builder().build()); + ).build()); final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(TAG_SET.getStackTags()) @@ -198,32 +190,19 @@ public void handleRequest_AccessDeniedTagging() { ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_CLUSTER_ENDPOINT_AVAILABLE, + null, null, () -> RESOURCE_MODEL.toBuilder() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.AccessDenied) ); - Assertions.assertThat(progress.getCallbackContext().isAddTagsComplete()).isTrue(); - Assertions.assertThat(progress.getCallbackContext().getTaggingContext().isSoftFailTags()).isTrue(); - ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbClusterEndpointRequest.class); - verify(rdsProxy.client(), times(2)).createDBClusterEndpoint(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).createDBClusterEndpoint(createCaptor.capture()); final CreateDbClusterEndpointRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final CreateDbClusterEndpointRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(2)).describeDBClusterEndpoints(any(DescribeDbClusterEndpointsRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); } @@ -232,52 +211,35 @@ public void handleRequest_HardFailTagging() { when(rdsProxy.client().createDBClusterEndpoint(any(CreateDbClusterEndpointRequest.class))) .thenThrow( RdsException.builder() - .awsErrorDetails(AwsErrorDetails.builder() - .errorCode(ErrorCode.AccessDeniedException.toString()) - .build() - ).build()) - .thenReturn(CreateDbClusterEndpointResponse.builder().build()); - - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenThrow( - RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() ).build()); - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); + test_handleRequest_base( new CallbackContext(), ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_CLUSTER_ENDPOINT_AVAILABLE, + null, null, () -> RESOURCE_MODEL.toBuilder() - .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) + .tags(null) .build(), - expectFailed(HandlerErrorCode.AccessDenied) + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); + final Tagging.TagSet expectedRequestTags = Tagging.TagSet.builder() + .stackTags(TAG_SET.getStackTags()) + .systemTags(TAG_SET.getSystemTags()) + .build(); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbClusterEndpointRequest.class); - verify(rdsProxy.client(), times(2)).createDBClusterEndpoint(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).createDBClusterEndpoint(createCaptor.capture()); final CreateDbClusterEndpointRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final CreateDbClusterEndpointRequest requestWithSystemTags = createCaptor.getAllValues().get(1); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class)); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class)); - - verify(rdsProxy.client(), times(1)).describeDBClusterEndpoints(any(DescribeDbClusterEndpointsRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - Assertions.assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class)); + Iterables.toArray(Tagging.translateTagsToSdk(expectedRequestTags), software.amazon.awssdk.services.rds.model.Tag.class)); } } diff --git a/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/UpdateHandlerTest.java b/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/UpdateHandlerTest.java index f7c2125da..512060277 100644 --- a/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/UpdateHandlerTest.java +++ b/aws-rds-dbclusterendpoint/src/test/java/software/amazon/rds/dbclusterendpoint/UpdateHandlerTest.java @@ -265,7 +265,7 @@ public void handleRequest_SoftFailingTaggingOnRemoveTags() { () -> DB_CLUSTER_ENDPOINT_AVAILABLE, () -> RESOURCE_MODEL_BUILDER().build(), () -> RESOURCE_MODEL_BUILDER().build(), - expectSuccess() + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); verify(rdsProxy.client(), times(1)).modifyDBClusterEndpoint(any(ModifyDbClusterEndpointRequest.class)); @@ -292,7 +292,7 @@ public void handleRequest_SoftFailingTaggingOnAddTags() { () -> DB_CLUSTER_ENDPOINT_AVAILABLE, () -> RESOURCE_MODEL_BUILDER().build(), () -> RESOURCE_MODEL_BUILDER().build(), - expectSuccess() + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); verify(rdsProxy.client(), times(1)).modifyDBClusterEndpoint(any(ModifyDbClusterEndpointRequest.class)); diff --git a/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/BaseHandlerStd.java b/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/BaseHandlerStd.java index 276d187f3..1c9e0fbda 100644 --- a/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/BaseHandlerStd.java +++ b/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/BaseHandlerStd.java @@ -182,11 +182,9 @@ protected ProgressEvent updateTags( progress, exception, DEFAULT_DB_CLUSTER_PARAMETER_GROUP_ERROR_RULE_SET.extendWith( - Tagging.bestEffortErrorRuleSet( + Tagging.getUpdateTagsAccessDeniedRuleSet( rulesetTagsToAdd, - rulesetTagsToRemove, - Tagging.SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET, - Tagging.HARD_FAIL_TAG_ERROR_RULE_SET + rulesetTagsToRemove ) ) ); diff --git a/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/CreateHandler.java b/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/CreateHandler.java index f8cc9af1f..f12330795 100644 --- a/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/CreateHandler.java +++ b/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/CreateHandler.java @@ -52,7 +52,7 @@ protected ProgressEvent handleRequest( return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext) .then(progress -> setDbClusterParameterGroupNameIfMissing(request, progress)) - .then(progress -> Tagging.safeCreate(proxy, proxyClient, this::createDbClusterParameterGroup, progress, allTags)) + .then(progress -> Tagging.createWithTaggingFallback(proxy, proxyClient, this::createDbClusterParameterGroup, progress, allTags)) .then(progress -> Commons.execOnce(progress, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(allTags.getStackTags()) diff --git a/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/ReadHandler.java b/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/ReadHandler.java index 6a6e6fe82..ae88ca519 100644 --- a/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/ReadHandler.java +++ b/aws-rds-dbclusterparametergroup/src/main/java/software/amazon/rds/dbclusterparametergroup/ReadHandler.java @@ -89,7 +89,7 @@ private ProgressEvent readTags( return Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_DB_CLUSTER_PARAMETER_GROUP_ERROR_RULE_SET.extendWith(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET) + DEFAULT_DB_CLUSTER_PARAMETER_GROUP_ERROR_RULE_SET.extendWith(Tagging.IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET) ); } return ProgressEvent.success(model, context); diff --git a/aws-rds-dbclusterparametergroup/src/test/java/software/amazon/rds/dbclusterparametergroup/CreateHandlerTest.java b/aws-rds-dbclusterparametergroup/src/test/java/software/amazon/rds/dbclusterparametergroup/CreateHandlerTest.java index 6fd17977c..e2ac240e1 100644 --- a/aws-rds-dbclusterparametergroup/src/test/java/software/amazon/rds/dbclusterparametergroup/CreateHandlerTest.java +++ b/aws-rds-dbclusterparametergroup/src/test/java/software/amazon/rds/dbclusterparametergroup/CreateHandlerTest.java @@ -153,29 +153,20 @@ public void handleRequest_Success() { } @Test - public void handleRequest_SuccessOnSoftCreate() { + public void handleRequest_UnauthorizedTaggingOperationOnCreate() { when(rdsProxy.client().createDBClusterParameterGroup(any(CreateDbClusterParameterGroupRequest.class))) .thenThrow(RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(CreateDbClusterParameterGroupResponse.builder() - .dbClusterParameterGroup(DB_CLUSTER_PARAMETER_GROUP) - .build()); + ).build()); - when(rdsProxy.client().listTagsForResource(any(ListTagsForResourceRequest.class))) - .thenReturn(ListTagsForResourceResponse.builder() - .tagList(Tag.builder().key(TAG_KEY).value(TAG_VALUE).build()) - .build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - - Map resourceTags = ImmutableMap.of(TAG_KEY, TAG_VALUE); + Map stackTags = ImmutableMap.of(TAG_KEY, TAG_VALUE); Map systemTags = ImmutableMap.of("systemTag1", "value2", "systemTag2", "value3"); Map allTags = ImmutableMap.builder() - .putAll(resourceTags) + .putAll(stackTags) .putAll(systemTags) .build(); @@ -186,29 +177,20 @@ public void handleRequest_SuccessOnSoftCreate() { callbackContext, ResourceHandlerRequest.builder() .systemTags(systemTags) - .desiredResourceTags(resourceTags), - () -> DBClusterParameterGroup.builder().build(), + .desiredResourceTags(stackTags), null, - () -> RESOURCE_MODEL, - expectSuccess() + null, + () -> RESOURCE_MODEL.toBuilder() + .tags(null) + .build(), + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); - assertThat(response.getCallbackContext().isAddTagsComplete()).isTrue(); - assertThat(response.getCallbackContext().getTaggingContext().isSoftFailTags()).isTrue(); - ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbClusterParameterGroupRequest.class); - verify(rdsProxy.client(), times(2)).createDBClusterParameterGroup(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).createDBClusterParameterGroup(createCaptor.capture()); final CreateDbClusterParameterGroupRequest requestWithAllTags = createCaptor.getAllValues().get(0); - final CreateDbClusterParameterGroupRequest requestWithSystemTags = createCaptor.getAllValues().get(1); assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder(asSdkTagArray(allTags)); - assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder(asSdkTagArray(systemTags)); - - verify(rdsProxy.client(), times(1)).describeDBClusterParameterGroups(any(DescribeDbClusterParameterGroupsRequest.class)); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - assertThat(addTagsCaptor.getValue().tags()).containsExactlyInAnyOrder(asSdkTagArray(resourceTags)); } @Test @@ -231,7 +213,7 @@ public void handleRequest_FailWithAccessDenied() { expectFailed(HandlerErrorCode.AccessDenied) ); - verify(rdsProxy.client(), times(2)).createDBClusterParameterGroup(any(CreateDbClusterParameterGroupRequest.class)); + verify(rdsProxy.client(), times(1)).createDBClusterParameterGroup(any(CreateDbClusterParameterGroupRequest.class)); } @Test diff --git a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/BaseHandlerStd.java b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/BaseHandlerStd.java index 985b0de6a..1b91764d0 100644 --- a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/BaseHandlerStd.java +++ b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/BaseHandlerStd.java @@ -1071,7 +1071,7 @@ protected ProgressEvent updateTags( return Commons.handleException( progress, exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET.extendWith(Tagging.bestEffortErrorRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)) + DEFAULT_DB_INSTANCE_ERROR_RULE_SET.extendWith(Tagging.getUpdateTagsAccessDeniedRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)) ); } diff --git a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/CreateHandler.java b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/CreateHandler.java index ffb6a0ce6..52f7f80d5 100644 --- a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/CreateHandler.java +++ b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/CreateHandler.java @@ -201,7 +201,7 @@ ApiVersion.DEFAULT, safeAddTags(this::createDbInstance) } private HandlerMethod safeAddTags(final HandlerMethod handlerMethod) { - return (proxy, rdsProxyClient, progress, tagSet) -> progress.then(p -> Tagging.safeCreate(proxy, rdsProxyClient, handlerMethod, progress, tagSet)); + return (proxy, rdsProxyClient, progress, tagSet) -> progress.then(p -> Tagging.createWithTaggingFallback(proxy, rdsProxyClient, handlerMethod, progress, tagSet)); } private String fetchEngine(final ProxyClient client, diff --git a/aws-rds-dbinstance/src/test/java/software/amazon/rds/dbinstance/CreateHandlerTest.java b/aws-rds-dbinstance/src/test/java/software/amazon/rds/dbinstance/CreateHandlerTest.java index 221e87850..b133f1ccd 100644 --- a/aws-rds-dbinstance/src/test/java/software/amazon/rds/dbinstance/CreateHandlerTest.java +++ b/aws-rds-dbinstance/src/test/java/software/amazon/rds/dbinstance/CreateHandlerTest.java @@ -254,15 +254,13 @@ public void handleRequest_RestoreDBInstanceFromSnapshot_AccessDeniedTagging() { when(rdsProxy.client().restoreDBInstanceFromDBSnapshot(any(RestoreDbInstanceFromDbSnapshotRequest.class))) .thenThrow( RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() ).build()) .thenReturn(RestoreDbInstanceFromDbSnapshotResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); - when(rdsProxy.client().describeDBSnapshots(any(DescribeDbSnapshotsRequest.class))) .thenReturn(DescribeDbSnapshotsResponse.builder() .dbSnapshots(DBSnapshot.builder() @@ -276,9 +274,9 @@ public void handleRequest_RestoreDBInstanceFromSnapshot_AccessDeniedTagging() { context.setRebooted(true); context.setUpdatedRoles(true); - final Tagging.TagSet extraTags = Tagging.TagSet.builder() + final Tagging.TagSet expectedRequestTags = Tagging.TagSet.builder() .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) + .systemTags(TAG_SET.getSystemTags()) .build(); test_handleRequest_base( @@ -286,35 +284,22 @@ public void handleRequest_RestoreDBInstanceFromSnapshot_AccessDeniedTagging() { ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_INSTANCE_ACTIVE, + null, null, () -> RESOURCE_MODEL_RESTORING_FROM_SNAPSHOT.toBuilder() - .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) + .tags(null) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(RestoreDbInstanceFromDbSnapshotRequest.class); - verify(rdsProxy.client(), times(2)).restoreDBInstanceFromDBSnapshot(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).restoreDBInstanceFromDBSnapshot(createCaptor.capture()); + final RestoreDbInstanceFromDbSnapshotRequest requestWithAllTags = createCaptor.getAllValues().get(0); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class) + Iterables.toArray(Tagging.translateTagsToSdk(expectedRequestTags), software.amazon.awssdk.services.rds.model.Tag.class) ); - final RestoreDbInstanceFromDbSnapshotRequest requestWithSystemTags = createCaptor.getAllValues().get(1); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - verify(rdsProxy.client(), times(3)).describeDBInstances(any(DescribeDbInstancesRequest.class)); - - ArgumentCaptor addTagCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagCaptor.capture()); - Assertions.assertThat(addTagCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - verify(rdsProxy.client(), times(1)).describeDBSnapshots(any(DescribeDbSnapshotsRequest.class)); } @Test @@ -439,10 +424,7 @@ public void handleRequest_CreateReadReplica_AccessDeniedTagging() { .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(CreateDbInstanceReadReplicaResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); + ).build()); final CallbackContext context = new CallbackContext(); context.setCreated(false); @@ -457,36 +439,15 @@ public void handleRequest_CreateReadReplica_AccessDeniedTagging() { test_handleRequest_base( context, - ResourceHandlerRequest.builder() - .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) - .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_INSTANCE_ACTIVE, null, () -> RESOURCE_MODEL_READ_REPLICA.toBuilder() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.AccessDenied) ); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbInstanceReadReplicaRequest.class); - verify(rdsProxy.client(), times(2)).createDBInstanceReadReplica(createCaptor.capture()); - - final CreateDbInstanceReadReplicaRequest requestWithAllTags = createCaptor.getAllValues().get(0); - Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class) - ); - final CreateDbInstanceReadReplicaRequest requestWithSystemTags = createCaptor.getAllValues().get(1); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - verify(rdsProxy.client(), times(3)).describeDBInstances(any(DescribeDbInstancesRequest.class)); - - ArgumentCaptor addTagCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagCaptor.capture()); - Assertions.assertThat(addTagCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class) - ); + verify(rdsProxy.client(), times(1)).createDBInstanceReadReplica(createCaptor.capture()); } @Test @@ -583,7 +544,7 @@ public void handleRequest_CreateNewInstance_AccessDeniedException() { expectFailed(HandlerErrorCode.AccessDenied) ); - verify(rdsProxy.client(), times(2)).createDBInstance(any(CreateDbInstanceRequest.class)); + verify(rdsProxy.client(), times(1)).createDBInstance(any(CreateDbInstanceRequest.class)); } @Test @@ -651,86 +612,49 @@ public void handleRequest_CreateNewInstance_AccessDeniedTagging() { .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() - ).build()) - .thenReturn(CreateDbInstanceResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); + ).build()); final CallbackContext context = new CallbackContext(); context.setCreated(false); - context.setUpdated(true); - context.setRebooted(true); - context.setUpdatedRoles(true); - - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); test_handleRequest_base( context, - ResourceHandlerRequest.builder() - .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) - .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_INSTANCE_ACTIVE, null, () -> RESOURCE_MODEL_BLDR() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .build(), - expectSuccess() - ); - - ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbInstanceRequest.class); - verify(rdsProxy.client(), times(2)).createDBInstance(createCaptor.capture()); - - final CreateDbInstanceRequest requestWithAllTags = createCaptor.getAllValues().get(0); - Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class) - ); - final CreateDbInstanceRequest requestWithSystemTags = createCaptor.getAllValues().get(1); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - verify(rdsProxy.client(), times(3)).describeDBInstances(any(DescribeDbInstancesRequest.class)); - - ArgumentCaptor addTagCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagCaptor.capture()); - Assertions.assertThat(addTagCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class) + expectFailed(HandlerErrorCode.AccessDenied) ); + verify(rdsProxy.client(), times(1)).createDBInstance(any(CreateDbInstanceRequest.class)); } @Test - public void handleRequest_CreateDBInstance_SoftFailTagsReentrance() { + public void handleRequest_CreateDBInstance_FailTagsNoReentranceForSystemTagsOnly() { when(rdsProxy.client().createDBInstance(any(CreateDbInstanceRequest.class))) - .thenReturn(CreateDbInstanceResponse.builder().build()); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); + .thenThrow( + RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") + .awsErrorDetails(AwsErrorDetails.builder() + .errorCode(ErrorCode.AccessDeniedException.toString()) + .build() + ).build()); final CallbackContext context = new CallbackContext(); context.setCreated(false); - context.getTaggingContext().setSoftFailTags(true); context.setUpdated(true); context.setRebooted(true); context.setUpdatedRoles(true); - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); - test_handleRequest_base( context, ResourceHandlerRequest.builder() - .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) - .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_INSTANCE_ACTIVE, + .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))), + null, null, () -> RESOURCE_MODEL_BLDR() - .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) + .tags(null) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.UnauthorizedTaggingOperation) ); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(CreateDbInstanceRequest.class); @@ -741,13 +665,6 @@ public void handleRequest_CreateDBInstance_SoftFailTagsReentrance() { Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) ); - verify(rdsProxy.client(), times(3)).describeDBInstances(any(DescribeDbInstancesRequest.class)); - - ArgumentCaptor addTagCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagCaptor.capture()); - Assertions.assertThat(addTagCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class) - ); } @Test @@ -1981,8 +1898,6 @@ public void handleRequest_RestoreDBInstanceToPointInTime_AccessDeniedTagging() { .build() ).build()) .thenReturn(restoreResponse); - when(rdsProxy.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenReturn(AddTagsToResourceResponse.builder().build()); final CallbackContext context = new CallbackContext(); context.setCreated(false); @@ -1990,44 +1905,28 @@ public void handleRequest_RestoreDBInstanceToPointInTime_AccessDeniedTagging() { context.setRebooted(true); context.setUpdatedRoles(true); - final Tagging.TagSet extraTags = Tagging.TagSet.builder() - .stackTags(TAG_SET.getStackTags()) - .resourceTags(TAG_SET.getResourceTags()) - .build(); test_handleRequest_base( context, ResourceHandlerRequest.builder() .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getSystemTags()))) .desiredResourceTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(TAG_SET.getStackTags()))), - () -> DB_INSTANCE_ACTIVE, + null, null, () -> RESOURCE_MODEL_RESTORING_TO_POINT_IN_TIME.toBuilder() .tags(Translator.translateTagsFromSdk(TAG_SET.getResourceTags())) .useLatestRestorableTime(true) .build(), - expectSuccess() + expectFailed(HandlerErrorCode.AccessDenied) ); ArgumentCaptor createCaptor = ArgumentCaptor.forClass(RestoreDbInstanceToPointInTimeRequest.class); - verify(rdsProxy.client(), times(2)).restoreDBInstanceToPointInTime(createCaptor.capture()); + verify(rdsProxy.client(), times(1)).restoreDBInstanceToPointInTime(createCaptor.capture()); final RestoreDbInstanceToPointInTimeRequest requestWithAllTags = createCaptor.getAllValues().get(0); Assertions.assertThat(requestWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(TAG_SET), software.amazon.awssdk.services.rds.model.Tag.class) ); - final RestoreDbInstanceToPointInTimeRequest requestWithSystemTags = createCaptor.getAllValues().get(1); - Assertions.assertThat(requestWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(TAG_SET.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - verify(rdsProxy.client(), times(3)).describeDBInstances(any(DescribeDbInstancesRequest.class)); - - ArgumentCaptor addTagCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(rdsProxy.client(), times(1)).addTagsToResource(addTagCaptor.capture()); - Assertions.assertThat(addTagCaptor.getValue().tags()).containsExactlyInAnyOrder( - Iterables.toArray(Tagging.translateTagsToSdk(extraTags), software.amazon.awssdk.services.rds.model.Tag.class) - ); } @Test diff --git a/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/BaseHandlerStd.java b/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/BaseHandlerStd.java index baebe5b8a..c3d7b3b17 100644 --- a/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/BaseHandlerStd.java +++ b/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/BaseHandlerStd.java @@ -157,11 +157,9 @@ protected ProgressEvent updateTags( progress, exception, DEFAULT_DB_PARAMETER_GROUP_ERROR_RULE_SET.extendWith( - Tagging.bestEffortErrorRuleSet( - rulesetTagsToAdd, - rulesetTagsToRemove, - Tagging.SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET, - Tagging.HARD_FAIL_TAG_ERROR_RULE_SET + Tagging.getUpdateTagsAccessDeniedRuleSet( + rulesetTagsToAdd, + rulesetTagsToRemove ) ) ); diff --git a/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/CreateHandler.java b/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/CreateHandler.java index 87f7e2435..f040fd3e9 100644 --- a/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/CreateHandler.java +++ b/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/CreateHandler.java @@ -64,7 +64,7 @@ private ProgressEvent safeCreateDBParameterGroup final RequestLogger logger ) { final HandlerMethod createMethod = (pxy, pcl, prg, tgs) -> createDBParameterGroup(pxy, pcl, prg, tgs, logger); - return Tagging.safeCreate(proxy, proxyClient, createMethod, progress, allTags) + return Tagging.createWithTaggingFallback(proxy, proxyClient, createMethod, progress, allTags) .then(p -> Commons.execOnce(p, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(allTags.getStackTags()) diff --git a/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/ReadHandler.java b/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/ReadHandler.java index 32ec0cfec..d87d30e0e 100644 --- a/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/ReadHandler.java +++ b/aws-rds-dbparametergroup/src/main/java/software/amazon/rds/dbparametergroup/ReadHandler.java @@ -103,7 +103,7 @@ private ProgressEvent readTags( return Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_DB_PARAMETER_GROUP_ERROR_RULE_SET.extendWith(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET) + DEFAULT_DB_PARAMETER_GROUP_ERROR_RULE_SET.extendWith(Tagging.IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET) ); } return ProgressEvent.success(model, context); diff --git a/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/BaseHandlerStd.java b/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/BaseHandlerStd.java index 62455c141..efc5d85f9 100644 --- a/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/BaseHandlerStd.java +++ b/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/BaseHandlerStd.java @@ -134,11 +134,9 @@ protected ProgressEvent updateTags( progress, exception, DEFAULT_DB_SUBNET_GROUP_ERROR_RULE_SET.extendWith( - Tagging.bestEffortErrorRuleSet( + Tagging.getUpdateTagsAccessDeniedRuleSet( rulesetTagsToAdd, - rulesetTagsToRemove, - Tagging.SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET, - Tagging.HARD_FAIL_TAG_ERROR_RULE_SET + rulesetTagsToRemove ) ) ); diff --git a/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/CreateHandler.java b/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/CreateHandler.java index b798e8005..7f066e0ee 100644 --- a/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/CreateHandler.java +++ b/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/CreateHandler.java @@ -55,7 +55,7 @@ private ProgressEvent safeCreateDbSubnetGroup(fi final ProxyClient proxyClient, final ProgressEvent progress, final Tagging.TagSet allTags) { - return Tagging.safeCreate(proxy, proxyClient, this::createDbSubnetGroup, progress, allTags) + return Tagging.createWithTaggingFallback(proxy, proxyClient, this::createDbSubnetGroup, progress, allTags) .then(p -> Commons.execOnce(p, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(allTags.getStackTags()) diff --git a/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/ReadHandler.java b/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/ReadHandler.java index d2e04b3a1..5a629c127 100644 --- a/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/ReadHandler.java +++ b/aws-rds-dbsubnetgroup/src/main/java/software/amazon/rds/dbsubnetgroup/ReadHandler.java @@ -70,7 +70,7 @@ protected ProgressEvent readTags( return Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_DB_SUBNET_GROUP_ERROR_RULE_SET.extendWith(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET) + DEFAULT_DB_SUBNET_GROUP_ERROR_RULE_SET.extendWith(Tagging.IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET) ); } return ProgressEvent.success(model, context); diff --git a/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/BaseHandlerStd.java b/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/BaseHandlerStd.java index 74810644a..8255f6ddc 100644 --- a/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/BaseHandlerStd.java +++ b/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/BaseHandlerStd.java @@ -143,11 +143,9 @@ protected ProgressEvent updateTags( progress, exception, DEFAULT_EVENT_SUBSCRIPTION_ERROR_RULE_SET.extendWith( - Tagging.bestEffortErrorRuleSet( + Tagging.getUpdateTagsAccessDeniedRuleSet( rulesetTagsToAdd, - rulesetTagsToRemove, - Tagging.SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET, - Tagging.HARD_FAIL_TAG_ERROR_RULE_SET + rulesetTagsToRemove ) ) ); diff --git a/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/CreateHandler.java b/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/CreateHandler.java index d98df5ae3..9e4acbddf 100644 --- a/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/CreateHandler.java +++ b/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/CreateHandler.java @@ -47,7 +47,7 @@ private ProgressEvent safeCreateEventSubscriptio final ProxyClient proxyClient, final ProgressEvent progress, final Tagging.TagSet allTags) { - return Tagging.safeCreate(proxy, proxyClient, this::createEventSubscription, progress, allTags) + return Tagging.createWithTaggingFallback(proxy, proxyClient, this::createEventSubscription, progress, allTags) .then(p -> Commons.execOnce(p, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(allTags.getStackTags()) diff --git a/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/ReadHandler.java b/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/ReadHandler.java index 63e873f25..a15981680 100644 --- a/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/ReadHandler.java +++ b/aws-rds-eventsubscription/src/main/java/software/amazon/rds/eventsubscription/ReadHandler.java @@ -49,7 +49,7 @@ protected ProgressEvent readTags( return Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_EVENT_SUBSCRIPTION_ERROR_RULE_SET.extendWith(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET) + DEFAULT_EVENT_SUBSCRIPTION_ERROR_RULE_SET.extendWith(Tagging.IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET) ); } return ProgressEvent.success(model, context); diff --git a/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/BaseHandlerStd.java b/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/BaseHandlerStd.java index eb25bdfa0..d9646691b 100644 --- a/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/BaseHandlerStd.java +++ b/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/BaseHandlerStd.java @@ -142,11 +142,9 @@ protected ProgressEvent updateTags( progress, exception, DEFAULT_OPTION_GROUP_ERROR_RULE_SET.extendWith( - Tagging.bestEffortErrorRuleSet( + Tagging.getUpdateTagsAccessDeniedRuleSet( rulesetTagsToAdd, - rulesetTagsToRemove, - Tagging.SOFT_FAIL_IN_PROGRESS_TAGGING_ERROR_RULE_SET, - Tagging.HARD_FAIL_TAG_ERROR_RULE_SET + rulesetTagsToRemove ) ) ); diff --git a/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/CreateHandler.java b/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/CreateHandler.java index a3a56385e..723696679 100644 --- a/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/CreateHandler.java +++ b/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/CreateHandler.java @@ -50,7 +50,7 @@ protected ProgressEvent handleRequest( return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext) .then(progress -> setOptionGroupNameIfEmpty(request, progress)) - .then(progress -> Tagging.safeCreate(proxy, proxyClient, this::createOptionGroup, progress, allTags)) + .then(progress -> Tagging.createWithTaggingFallback(proxy, proxyClient, this::createOptionGroup, progress, allTags)) .then(progress -> Commons.execOnce(progress, () -> { final Tagging.TagSet extraTags = Tagging.TagSet.builder() .stackTags(allTags.getStackTags()) diff --git a/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/ReadHandler.java b/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/ReadHandler.java index a815553af..d7e7ff039 100644 --- a/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/ReadHandler.java +++ b/aws-rds-optiongroup/src/main/java/software/amazon/rds/optiongroup/ReadHandler.java @@ -75,7 +75,7 @@ protected ProgressEvent readTags( return Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_OPTION_GROUP_ERROR_RULE_SET.extendWith(Tagging.SOFT_FAIL_TAG_ERROR_RULE_SET) + DEFAULT_OPTION_GROUP_ERROR_RULE_SET.extendWith(Tagging.IGNORE_LIST_TAGS_PERMISSION_DENIED_ERROR_RULE_SET) ); } return ProgressEvent.success(model, context); diff --git a/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/CreateHandlerTest.java b/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/CreateHandlerTest.java index 2bda25c67..e13d21d7f 100644 --- a/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/CreateHandlerTest.java +++ b/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/CreateHandlerTest.java @@ -11,9 +11,11 @@ import java.time.Duration; +import com.google.common.collect.Iterables; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.extension.ExtendWith; @@ -21,7 +23,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.google.common.collect.Iterables; import lombok.Getter; import software.amazon.awssdk.awscore.exception.AwsErrorDetails; import software.amazon.awssdk.services.rds.RdsClient; @@ -38,10 +39,10 @@ import software.amazon.awssdk.services.rds.model.RdsException; import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; import software.amazon.cloudformation.proxy.HandlerErrorCode; -import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ProxyClient; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; +import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.rds.common.error.ErrorCode; import software.amazon.rds.common.handler.HandlerConfig; import software.amazon.rds.common.handler.Tagging; @@ -215,27 +216,12 @@ public void handleRequest_SoftFailingTagging() { when(proxyClient.client().createOptionGroup(any(CreateOptionGroupRequest.class))) .thenThrow( RdsException.builder() - .awsErrorDetails(AwsErrorDetails.builder() - .errorCode(ErrorCode.AccessDeniedException.toString()) - .build() - ).build()) - .thenReturn(CreateOptionGroupResponse.builder().build()); - - final DescribeOptionGroupsResponse describeDbClusterParameterGroupsResponse = DescribeOptionGroupsResponse.builder() - .optionGroupsList(OPTION_GROUP_ACTIVE).build(); - when(proxyClient.client().describeOptionGroups(any(DescribeOptionGroupsRequest.class))).thenReturn(describeDbClusterParameterGroupsResponse); - - when(proxyClient.client().addTagsToResource(any(AddTagsToResourceRequest.class))) - .thenThrow( - RdsException.builder() + .message("Role not authorized to execute rds:AddTagsToResource") .awsErrorDetails(AwsErrorDetails.builder() .errorCode(ErrorCode.AccessDeniedException.toString()) .build() ).build()); - when(proxyClient.client().listTagsForResource(any(ListTagsForResourceRequest.class))) - .thenReturn(ListTagsForResourceResponse.builder().build()); - final ResourceHandlerRequest request = ResourceHandlerRequest.builder() .clientRequestToken(TestUtils.randomString(32, TestUtils.ALPHA)) .systemTags(Translator.translateTagsToRequest(Translator.translateTagsFromSdk(desiredTags.getSystemTags()))) @@ -247,34 +233,19 @@ public void handleRequest_SoftFailingTagging() { final ProgressEvent response = handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger); - assertThat(response).isNotNull(); - assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); - assertThat(response.getCallbackDelaySeconds()).isEqualTo(0); - assertThat(response.getResourceModels()).isNull(); - assertThat(response.getMessage()).isNull(); - assertThat(response.getErrorCode()).isNull(); - - verify(proxyClient.client(), times(1)).addTagsToResource(any(AddTagsToResourceRequest.class)); - verify(proxyClient.client(), times(2)).describeOptionGroups(any(DescribeOptionGroupsRequest.class)); - verify(proxyClient.client(), times(1)).listTagsForResource(any(ListTagsForResourceRequest.class)); + Assertions.assertThat(response).isNotNull(); + Assertions.assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED); + Assertions.assertThat(response.getCallbackDelaySeconds()).isEqualTo(0); + Assertions.assertThat(response.getMessage()).isNotNull(); + Assertions.assertThat(response.getErrorCode()).isEqualTo(HandlerErrorCode.UnauthorizedTaggingOperation); + Assertions.assertThat(response.getResourceModels()).isNull(); ArgumentCaptor createOptionGroupCaptor = ArgumentCaptor.forClass(CreateOptionGroupRequest.class); - verify(proxyClient.client(), times(2)).createOptionGroup(createOptionGroupCaptor.capture()); + verify(proxyClient.client(), times(1)).createOptionGroup(createOptionGroupCaptor.capture()); final CreateOptionGroupRequest createOptionGroupWithAllTags = createOptionGroupCaptor.getAllValues().get(0); Assertions.assertThat(createOptionGroupWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(desiredTags), software.amazon.awssdk.services.rds.model.Tag.class) ); - final CreateOptionGroupRequest createOptionGroupWithSystemTags = createOptionGroupCaptor.getAllValues().get(1); - Assertions.assertThat(createOptionGroupWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(desiredTags.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(proxyClient.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - final AddTagsToResourceRequest requestWithStackTags = addTagsCaptor.getAllValues().get(0); - Assertions.assertThat(requestWithStackTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(desiredTags.getStackTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); } @Test @@ -287,19 +258,6 @@ public void handleRequest_HardFailingTagging() { .build(); when(proxyClient.client().createOptionGroup(any(CreateOptionGroupRequest.class))) - .thenThrow( - RdsException.builder() - .awsErrorDetails(AwsErrorDetails.builder() - .errorCode(ErrorCode.AccessDeniedException.toString()) - .build() - ).build()) - .thenReturn(CreateOptionGroupResponse.builder().build()); - - final DescribeOptionGroupsResponse describeDbClusterParameterGroupsResponse = DescribeOptionGroupsResponse.builder() - .optionGroupsList(OPTION_GROUP_ACTIVE).build(); - when(proxyClient.client().describeOptionGroups(any(DescribeOptionGroupsRequest.class))).thenReturn(describeDbClusterParameterGroupsResponse); - - when(proxyClient.client().addTagsToResource(any(AddTagsToResourceRequest.class))) .thenThrow( RdsException.builder() .awsErrorDetails(AwsErrorDetails.builder() @@ -323,26 +281,12 @@ public void handleRequest_HardFailingTagging() { Assertions.assertThat(response.getErrorCode()).isEqualTo(HandlerErrorCode.AccessDenied); Assertions.assertThat(response.getResourceModels()).isNull(); - verify(proxyClient.client(), times(1)).addTagsToResource(any(AddTagsToResourceRequest.class)); - verify(proxyClient.client(), times(1)).describeOptionGroups(any(DescribeOptionGroupsRequest.class)); - ArgumentCaptor createOptionGroupCaptor = ArgumentCaptor.forClass(CreateOptionGroupRequest.class); - verify(proxyClient.client(), times(2)).createOptionGroup(createOptionGroupCaptor.capture()); + verify(proxyClient.client(), times(1)).createOptionGroup(createOptionGroupCaptor.capture()); final CreateOptionGroupRequest createOptionGroupWithAllTags = createOptionGroupCaptor.getAllValues().get(0); Assertions.assertThat(createOptionGroupWithAllTags.tags()).containsExactlyInAnyOrder( Iterables.toArray(Tagging.translateTagsToSdk(desiredTags), software.amazon.awssdk.services.rds.model.Tag.class) ); - final CreateOptionGroupRequest createOptionGroupWithSystemTags = createOptionGroupCaptor.getAllValues().get(1); - Assertions.assertThat(createOptionGroupWithSystemTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(desiredTags.getSystemTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); - - ArgumentCaptor addTagsCaptor = ArgumentCaptor.forClass(AddTagsToResourceRequest.class); - verify(proxyClient.client(), times(1)).addTagsToResource(addTagsCaptor.capture()); - final AddTagsToResourceRequest requestWithResourceTags = addTagsCaptor.getAllValues().get(0); - Assertions.assertThat(requestWithResourceTags.tags()).containsExactlyInAnyOrder( - Iterables.toArray(desiredTags.getResourceTags(), software.amazon.awssdk.services.rds.model.Tag.class) - ); } @Test diff --git a/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/UpdateHandlerTest.java b/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/UpdateHandlerTest.java index 332ffd090..a8e59d221 100644 --- a/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/UpdateHandlerTest.java +++ b/aws-rds-optiongroup/src/test/java/software/amazon/rds/optiongroup/UpdateHandlerTest.java @@ -243,8 +243,6 @@ public void handleRequest_SoftFailingTaggingOnRemoveTags() { ) ); - when(proxyClient.client().listTagsForResource(any(ListTagsForResourceRequest.class))) - .thenReturn(ListTagsForResourceResponse.builder().build()); final DescribeOptionGroupsResponse describeDbClusterParameterGroupsResponse = DescribeOptionGroupsResponse.builder() .optionGroupsList(OPTION_GROUP_ACTIVE).build(); when(proxyClient.client().describeOptionGroups(any(DescribeOptionGroupsRequest.class))) @@ -269,15 +267,14 @@ public void handleRequest_SoftFailingTaggingOnRemoveTags() { final ProgressEvent response = handler.handleRequest(proxy, request, new CallbackContext(), proxyClient, logger); assertThat(response).isNotNull(); - assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS); + assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED); assertThat(response.getCallbackDelaySeconds()).isEqualTo(0); + assertThat(response.getMessage()).isNotNull(); + assertThat(response.getErrorCode()).isEqualTo(HandlerErrorCode.UnauthorizedTaggingOperation); assertThat(response.getResourceModels()).isNull(); - assertThat(response.getMessage()).isNull(); - assertThat(response.getErrorCode()).isNull(); verify(proxyClient.client(), times(1)).removeTagsFromResource(any(RemoveTagsFromResourceRequest.class)); - verify(proxyClient.client(), times(2)).describeOptionGroups(any(DescribeOptionGroupsRequest.class)); - verify(proxyClient.client(), times(1)).listTagsForResource(any(ListTagsForResourceRequest.class)); + verify(proxyClient.client(), times(1)).describeOptionGroups(any(DescribeOptionGroupsRequest.class)); } @Test