diff --git a/aws-rds-cfn-common/src/main/java/software/amazon/rds/dbinstance/common/ErrorRuleSets.java b/aws-rds-cfn-common/src/main/java/software/amazon/rds/dbinstance/common/ErrorRuleSets.java new file mode 100644 index 00000000..7b3cda8a --- /dev/null +++ b/aws-rds-cfn-common/src/main/java/software/amazon/rds/dbinstance/common/ErrorRuleSets.java @@ -0,0 +1,240 @@ +package software.amazon.rds.dbinstance.common; + +import software.amazon.awssdk.services.rds.model.AuthorizationNotFoundException; +import software.amazon.awssdk.services.rds.model.CertificateNotFoundException; +import software.amazon.awssdk.services.rds.model.DbClusterNotFoundException; +import software.amazon.awssdk.services.rds.model.DbClusterSnapshotNotFoundException; +import software.amazon.awssdk.services.rds.model.DbInstanceAlreadyExistsException; +import software.amazon.awssdk.services.rds.model.DbInstanceAutomatedBackupQuotaExceededException; +import software.amazon.awssdk.services.rds.model.DbInstanceNotFoundException; +import software.amazon.awssdk.services.rds.model.DbInstanceRoleAlreadyExistsException; +import software.amazon.awssdk.services.rds.model.DbInstanceRoleNotFoundException; +import software.amazon.awssdk.services.rds.model.DbParameterGroupNotFoundException; +import software.amazon.awssdk.services.rds.model.DbSecurityGroupNotFoundException; +import software.amazon.awssdk.services.rds.model.DbSnapshotAlreadyExistsException; +import software.amazon.awssdk.services.rds.model.DbSnapshotNotFoundException; +import software.amazon.awssdk.services.rds.model.DbSubnetGroupDoesNotCoverEnoughAZsException; +import software.amazon.awssdk.services.rds.model.DbSubnetGroupNotFoundException; +import software.amazon.awssdk.services.rds.model.DbUpgradeDependencyFailureException; +import software.amazon.awssdk.services.rds.model.DomainNotFoundException; +import software.amazon.awssdk.services.rds.model.InstanceQuotaExceededException; +import software.amazon.awssdk.services.rds.model.InsufficientDbInstanceCapacityException; +import software.amazon.awssdk.services.rds.model.InvalidDbClusterStateException; +import software.amazon.awssdk.services.rds.model.InvalidDbInstanceAutomatedBackupStateException; +import software.amazon.awssdk.services.rds.model.InvalidDbInstanceStateException; +import software.amazon.awssdk.services.rds.model.InvalidDbSecurityGroupStateException; +import software.amazon.awssdk.services.rds.model.InvalidDbSnapshotStateException; +import software.amazon.awssdk.services.rds.model.InvalidRestoreException; +import software.amazon.awssdk.services.rds.model.InvalidSubnetException; +import software.amazon.awssdk.services.rds.model.InvalidVpcNetworkStateException; +import software.amazon.awssdk.services.rds.model.KmsKeyNotAccessibleException; +import software.amazon.awssdk.services.rds.model.NetworkTypeNotSupportedException; +import software.amazon.awssdk.services.rds.model.OptionGroupNotFoundException; +import software.amazon.awssdk.services.rds.model.ProvisionedIopsNotAvailableInAzException; +import software.amazon.awssdk.services.rds.model.SnapshotQuotaExceededException; +import software.amazon.awssdk.services.rds.model.StorageQuotaExceededException; +import software.amazon.awssdk.services.rds.model.StorageTypeNotSupportedException; +import software.amazon.awssdk.utils.StringUtils; +import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; +import software.amazon.cloudformation.proxy.HandlerErrorCode; +import software.amazon.cloudformation.proxy.OperationStatus; +import software.amazon.rds.common.error.ErrorCode; +import software.amazon.rds.common.error.ErrorRuleSet; +import software.amazon.rds.common.error.ErrorStatus; +import software.amazon.rds.common.handler.Commons; + +import java.util.function.Function; + +public class ErrorRuleSets { + + public static final ErrorRuleSet DEFAULT_DB_INSTANCE = ErrorRuleSet + .extend(Commons.DEFAULT_ERROR_RULE_SET) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded), + ErrorCode.InstanceQuotaExceeded, + ErrorCode.InsufficientDBInstanceCapacity, + ErrorCode.SnapshotQuotaExceeded, + ErrorCode.StorageQuotaExceeded) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + ErrorCode.DBSubnetGroupNotAllowedFault, + ErrorCode.InvalidParameterCombination, + ErrorCode.InvalidParameterValue, + ErrorCode.InvalidVPCNetworkStateFault, + ErrorCode.KMSKeyNotAccessibleFault, + ErrorCode.MissingParameter, + ErrorCode.ProvisionedIopsNotAvailableInAZFault, + ErrorCode.StorageTypeNotSupportedFault) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), + ErrorCode.DBClusterNotFoundFault, + ErrorCode.DBParameterGroupNotFound, + ErrorCode.DBSecurityGroupNotFound, + ErrorCode.DBSnapshotNotFound, + ErrorCode.DBSubnetGroupNotFoundFault) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), + CertificateNotFoundException.class, + DbClusterNotFoundException.class, + DbInstanceNotFoundException.class, + DbParameterGroupNotFoundException.class, + DbSecurityGroupNotFoundException.class, + DbSnapshotNotFoundException.class, + DbClusterSnapshotNotFoundException.class, + DbSubnetGroupNotFoundException.class, + DomainNotFoundException.class, + OptionGroupNotFoundException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded), + DbInstanceAutomatedBackupQuotaExceededException.class, + InsufficientDbInstanceCapacityException.class, + InstanceQuotaExceededException.class, + SnapshotQuotaExceededException.class, + StorageQuotaExceededException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), + InvalidDbInstanceStateException.class, + InvalidDbClusterStateException.class, + DbUpgradeDependencyFailureException.class, + InvalidDbSecurityGroupStateException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + AuthorizationNotFoundException.class, + DbSubnetGroupDoesNotCoverEnoughAZsException.class, + InvalidVpcNetworkStateException.class, + KmsKeyNotAccessibleException.class, + NetworkTypeNotSupportedException.class, + ProvisionedIopsNotAvailableInAzException.class, + StorageTypeNotSupportedException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + DbInstanceAlreadyExistsException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.GeneralServiceException), + InvalidSubnetException.class) + .build(); + + public static final ErrorRuleSet DB_INSTANCE_FETCH_ENGINE = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + CfnInvalidRequestException.class) + .build(); + + public static final ErrorRuleSet RESTORE_DB_INSTANCE = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + ErrorCode.DBInstanceAlreadyExists) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + ErrorCode.InvalidDBSnapshotState, + ErrorCode.InvalidRestoreFault) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + DbInstanceAlreadyExistsException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + InvalidDbSnapshotStateException.class, + InvalidRestoreException.class) + .build(); + public static final ErrorRuleSet CREATE_DB_INSTANCE = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + ErrorCode.DBInstanceAlreadyExists) + .withErrorClasses( + ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + DbInstanceAlreadyExistsException.class) + .build(); + + public static final ErrorRuleSet CREATE_DB_INSTANCE_READ_REPLICA = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + ErrorCode.DBInstanceAlreadyExists) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), + DbInstanceAlreadyExistsException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), + DbClusterNotFoundException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), + InvalidDbClusterStateException.class) + .build(); + + public static final ErrorRuleSet REBOOT_DB_INSTANCE = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), + ErrorCode.DBInstanceNotFound) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), + ErrorCode.InvalidDBInstanceState) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), + DbInstanceNotFoundException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), + InvalidDbInstanceStateException.class) + .build(); + + public static final ErrorRuleSet MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorClasses(ErrorStatus.ignore(OperationStatus.IN_PROGRESS), + InvalidDbInstanceAutomatedBackupStateException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded), + DbInstanceAutomatedBackupQuotaExceededException.class) + .build(); + + public static final ErrorRuleSet MODIFY_DB_INSTANCE = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), + ErrorCode.InvalidDBInstanceState) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), + ErrorCode.DBInstanceNotFound) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + ErrorCode.InvalidDBSecurityGroupState, + ErrorCode.InvalidParameterCombination) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), + InvalidDbInstanceStateException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), + DbInstanceNotFoundException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + CfnInvalidRequestException.class, + InvalidDbSecurityGroupStateException.class) + .build(); + + public static final ErrorRuleSet UPDATE_ASSOCIATED_ROLES = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorClasses(ErrorStatus.ignore(), + DbInstanceRoleAlreadyExistsException.class, + DbInstanceRoleNotFoundException.class) + .build(); + + private static final Function ignoreDBInstanceBeingDeletedConditionalErrorStatus = exception -> { + if (isDBInstanceBeingDeletedException(exception)) { + return ErrorStatus.ignore(OperationStatus.IN_PROGRESS); + } + return ErrorStatus.failWith(HandlerErrorCode.ResourceConflict); + }; + + public static final ErrorRuleSet DELETE_DB_INSTANCE = ErrorRuleSet + .extend(DEFAULT_DB_INSTANCE) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + ErrorCode.InvalidParameterValue) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), + ErrorCode.DBInstanceNotFound) + .withErrorCodes(ErrorStatus.conditional(ignoreDBInstanceBeingDeletedConditionalErrorStatus), + ErrorCode.InvalidDBInstanceState) + .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + ErrorCode.DBSnapshotAlreadyExists) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), + DbInstanceNotFoundException.class) + .withErrorClasses(ErrorStatus.conditional(ignoreDBInstanceBeingDeletedConditionalErrorStatus), + InvalidDbInstanceStateException.class) + .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), + DbSnapshotAlreadyExistsException.class) + .build(); + + // Note: looking up this error message fragment is the only way to distinguish between an already deleting + // instance and any other invalid states (e.g. a stopped instance). It relies on a specific error text returned by + // AWS RDS API. The message text is by no means guarded by any public contract. This error message can change + // in the future with no prior notice by AWS RDS. A change in this error message would cause a CFN stack failure + // upon a stack deletion: if an instance is being deleted out-of-bounds. This is a pretty corner (still common) case + // where the CFN handler is trying to help the customer. A regular stack deletion will not be impacted. + // Considered bounded-safe. + private static final String IS_ALREADY_BEING_DELETED_ERROR_FRAGMENT = "is already being deleted"; + + private static boolean isDBInstanceBeingDeletedException(final Exception e) { + if (e instanceof InvalidDbInstanceStateException) { + return looksLikeDBInstanceBeingDeletedMessage(e.getMessage()); + } + return false; + } + + private static boolean looksLikeDBInstanceBeingDeletedMessage(final String message) { + if (StringUtils.isBlank(message)) { + return false; + } + return message.contains(ErrorRuleSets.IS_ALREADY_BEING_DELETED_ERROR_FRAGMENT); + } +} 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 13326deb..8ca6769c 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 @@ -1,34 +1,61 @@ package software.amazon.rds.dbinstance; -import com.amazonaws.arn.Arn; import com.google.common.collect.ImmutableList; import org.apache.commons.lang3.BooleanUtils; import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.ec2.model.DescribeSecurityGroupsResponse; import software.amazon.awssdk.services.ec2.model.SecurityGroup; import software.amazon.awssdk.services.rds.RdsClient; +import software.amazon.awssdk.services.rds.model.DBCluster; +import software.amazon.awssdk.services.rds.model.DBClusterSnapshot; +import software.amazon.awssdk.services.rds.model.DBInstance; +import software.amazon.awssdk.services.rds.model.DBInstanceAutomatedBackup; +import software.amazon.awssdk.services.rds.model.DBSnapshot; +import software.amazon.awssdk.services.rds.model.DbInstanceNotFoundException; +import software.amazon.awssdk.services.rds.model.DescribeDbClusterSnapshotsResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbClustersResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbInstanceAutomatedBackupsResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbInstancesResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbSnapshotsResponse; +import software.amazon.awssdk.services.rds.model.Event; import software.amazon.awssdk.services.rds.model.Tag; -import software.amazon.awssdk.services.rds.model.*; import software.amazon.awssdk.utils.StringUtils; -import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; -import software.amazon.cloudformation.proxy.*; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.HandlerErrorCode; +import software.amazon.cloudformation.proxy.Logger; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import software.amazon.cloudformation.proxy.delay.Constant; import software.amazon.cloudformation.resource.ResourceTypeSchema; -import software.amazon.rds.common.error.ErrorCode; -import software.amazon.rds.common.error.ErrorRuleSet; -import software.amazon.rds.common.error.ErrorStatus; -import software.amazon.rds.common.handler.*; +import software.amazon.rds.common.handler.Commons; +import software.amazon.rds.common.handler.Events; +import software.amazon.rds.common.handler.HandlerConfig; +import software.amazon.rds.common.handler.HandlerMethod; +import software.amazon.rds.common.handler.Tagging; import software.amazon.rds.common.logging.LoggingProxyClient; import software.amazon.rds.common.logging.RequestLogger; import software.amazon.rds.common.printer.FilteredJsonPrinter; import software.amazon.rds.common.request.RequestValidationException; import software.amazon.rds.common.request.ValidatedRequest; import software.amazon.rds.common.request.Validations; -import software.amazon.rds.dbinstance.client.*; +import software.amazon.rds.dbinstance.client.ApiVersion; +import software.amazon.rds.dbinstance.client.ApiVersionDispatcher; +import software.amazon.rds.dbinstance.client.Ec2ClientProvider; +import software.amazon.rds.dbinstance.client.RdsClientProvider; +import software.amazon.rds.dbinstance.client.VersionedProxyClient; +import software.amazon.rds.dbinstance.common.ErrorRuleSets; import java.time.Duration; import java.time.Instant; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; @@ -44,23 +71,15 @@ public abstract class BaseHandlerStd extends BaseHandler { protected static final int RESOURCE_ID_MAX_LENGTH = 63; protected final static HandlerConfig DEFAULT_DB_INSTANCE_HANDLER_CONFIG = HandlerConfig.builder() - .backoff(Constant.of().delay(Duration.ofSeconds(30)).timeout(Duration.ofMinutes(180)).build()) - .build(); + .backoff(Constant.of().delay(Duration.ofSeconds(30)).timeout(Duration.ofMinutes(180)).build()) + .build(); protected final static HandlerConfig DB_INSTANCE_HANDLER_CONFIG_36H = HandlerConfig.builder() - .backoff(Constant.of().delay(Duration.ofSeconds(30)).timeout(Duration.ofHours(36)).build()) - .build(); + .backoff(Constant.of().delay(Duration.ofSeconds(30)).timeout(Duration.ofHours(36)).build()) + .build(); protected static final RuntimeException MISSING_METHOD_VERSION_EXCEPTION = new RuntimeException("Missing method version"); - // Note: looking up this error message fragment is the only way to distinguish between an already deleting - // instance and any other invalid states (e.g. a stopped instance). It relies on a specific error text returned by - // AWS RDS API. The message text is by no means guarded by any public contract. This error message can change - // in the future with no prior notice by AWS RDS. A change in this error message would cause a CFN stack failure - // upon a stack deletion: if an instance is being deleted out-of-bounds. This is a pretty corner (still common) case - // where the CFN handler is trying to help the customer. A regular stack deletion will not be impacted. - // Considered bounded-safe. - protected static final String IS_ALREADY_BEING_DELETED_ERROR_FRAGMENT = "is already being deleted"; protected static final String ILLEGAL_DELETION_POLICY_ERROR = "DeletionPolicy:Snapshot cannot be specified for a cluster instance, use deletion policy on the cluster instead."; @@ -84,212 +103,29 @@ public abstract class BaseHandlerStd extends BaseHandler { protected static final BiFunction, ResourceModel> NOOP_CALL = (model, proxyClient) -> model; - protected static final Function ignoreDBInstanceBeingDeletedConditionalErrorStatus = exception -> { - if (isDBInstanceBeingDeletedException(exception)) { - return ErrorStatus.ignore(OperationStatus.IN_PROGRESS); - } - return ErrorStatus.failWith(HandlerErrorCode.ResourceConflict); - }; - //TODO: This list should be gone eventually. Event ID should be checked instead. private static final List> EVENT_FAIL_CHECKERS = ImmutableList.of( - (e) -> Events.isEventMessageContains(e, "failed to join a host to a domain"), - (e) -> Events.isEventMessageContains(e, "failed to join cluster instance"), - (e) -> Events.isEventMessageContains(e, "insufficient instance capacity"), - (e) -> Events.isEventMessageContains(e, "rds custom couldn't modify the db instance"), - (e) -> Events.isEventMessageContains(e, "the db engine version upgrade failed"), - (e) -> Events.isEventMessageContains(e, "the instance could not be upgraded"), - (e) -> Events.isEventMessageContains(e, "the storage volume limitation was exceeded"), - (e) -> Events.isEventMessageContains(e, "the update of the replica mode failed"), - (e) -> Events.isEventMessageContains(e, "unable to modify database instance class"), - (e) -> Events.isEventMessageContains(e, "unable to modify the db instance class"), - (e) -> Events.isEventMessageContains(e, "you can't create the db instance"), - (e) -> Events.isEventMessageContains(e, "instance is in a state that cannot be upgraded") + (e) -> Events.isEventMessageContains(e, "failed to join a host to a domain"), + (e) -> Events.isEventMessageContains(e, "failed to join cluster instance"), + (e) -> Events.isEventMessageContains(e, "insufficient instance capacity"), + (e) -> Events.isEventMessageContains(e, "rds custom couldn't modify the db instance"), + (e) -> Events.isEventMessageContains(e, "the db engine version upgrade failed"), + (e) -> Events.isEventMessageContains(e, "the instance could not be upgraded"), + (e) -> Events.isEventMessageContains(e, "the storage volume limitation was exceeded"), + (e) -> Events.isEventMessageContains(e, "the update of the replica mode failed"), + (e) -> Events.isEventMessageContains(e, "unable to modify database instance class"), + (e) -> Events.isEventMessageContains(e, "unable to modify the db instance class"), + (e) -> Events.isEventMessageContains(e, "you can't create the db instance"), + (e) -> Events.isEventMessageContains(e, "instance is in a state that cannot be upgraded") ); - protected static final ErrorRuleSet DEFAULT_DB_INSTANCE_ERROR_RULE_SET = ErrorRuleSet - .extend(Commons.DEFAULT_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded), - ErrorCode.InstanceQuotaExceeded, - ErrorCode.InsufficientDBInstanceCapacity, - ErrorCode.SnapshotQuotaExceeded, - ErrorCode.StorageQuotaExceeded) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - ErrorCode.DBSubnetGroupNotAllowedFault, - ErrorCode.InvalidParameterCombination, - ErrorCode.InvalidParameterValue, - ErrorCode.InvalidVPCNetworkStateFault, - ErrorCode.KMSKeyNotAccessibleFault, - ErrorCode.MissingParameter, - ErrorCode.ProvisionedIopsNotAvailableInAZFault, - ErrorCode.StorageTypeNotSupportedFault) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), - ErrorCode.DBClusterNotFoundFault, - ErrorCode.DBParameterGroupNotFound, - ErrorCode.DBSecurityGroupNotFound, - ErrorCode.DBSnapshotNotFound, - ErrorCode.DBSubnetGroupNotFoundFault) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), - CertificateNotFoundException.class, - DbClusterNotFoundException.class, - DbInstanceNotFoundException.class, - DbParameterGroupNotFoundException.class, - DbSecurityGroupNotFoundException.class, - DbSnapshotNotFoundException.class, - DbClusterSnapshotNotFoundException.class, - DbSubnetGroupNotFoundException.class, - DomainNotFoundException.class, - OptionGroupNotFoundException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded), - DbInstanceAutomatedBackupQuotaExceededException.class, - InsufficientDbInstanceCapacityException.class, - InstanceQuotaExceededException.class, - SnapshotQuotaExceededException.class, - StorageQuotaExceededException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), - InvalidDbInstanceStateException.class, - InvalidDbClusterStateException.class, - DbUpgradeDependencyFailureException.class, - InvalidDbSecurityGroupStateException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - AuthorizationNotFoundException.class, - DbSubnetGroupDoesNotCoverEnoughAZsException.class, - InvalidVpcNetworkStateException.class, - KmsKeyNotAccessibleException.class, - NetworkTypeNotSupportedException.class, - ProvisionedIopsNotAvailableInAzException.class, - StorageTypeNotSupportedException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - DbInstanceAlreadyExistsException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.GeneralServiceException), - InvalidSubnetException.class) - .build(); - - protected static final ErrorRuleSet DB_INSTANCE_FETCH_ENGINE_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - CfnInvalidRequestException.class) - .build(); - - public static final ErrorRuleSet RESTORE_DB_INSTANCE_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - ErrorCode.DBInstanceAlreadyExists) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - ErrorCode.InvalidDBSnapshotState, - ErrorCode.InvalidRestoreFault) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - DbInstanceAlreadyExistsException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - InvalidDbSnapshotStateException.class, - InvalidRestoreException.class) - .build(); - - protected static final ErrorRuleSet CREATE_DB_INSTANCE_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - ErrorCode.DBInstanceAlreadyExists) - .withErrorClasses( - ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - DbInstanceAlreadyExistsException.class) - .build(); - - protected static final ErrorRuleSet CREATE_DB_INSTANCE_READ_REPLICA_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - ErrorCode.DBInstanceAlreadyExists) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists), - DbInstanceAlreadyExistsException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), - DbClusterNotFoundException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), - InvalidDbClusterStateException.class) - .build(); - - protected static final ErrorRuleSet REBOOT_DB_INSTANCE_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), - ErrorCode.DBInstanceNotFound) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), - ErrorCode.InvalidDBInstanceState) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), - DbInstanceNotFoundException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), - InvalidDbInstanceStateException.class) - .build(); - - protected static final ErrorRuleSet MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorClasses(ErrorStatus.ignore(OperationStatus.IN_PROGRESS), - InvalidDbInstanceAutomatedBackupStateException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded), - DbInstanceAutomatedBackupQuotaExceededException.class) - .build(); - - protected static final ErrorRuleSet MODIFY_DB_INSTANCE_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), - ErrorCode.InvalidDBInstanceState) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), - ErrorCode.DBInstanceNotFound) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - ErrorCode.InvalidDBSecurityGroupState, - ErrorCode.InvalidParameterCombination) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict), - InvalidDbInstanceStateException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), - DbInstanceNotFoundException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - CfnInvalidRequestException.class, - InvalidDbSecurityGroupStateException.class) - .build(); - - protected static final ErrorRuleSet UPDATE_ASSOCIATED_ROLES_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorClasses(ErrorStatus.ignore(), - DbInstanceRoleAlreadyExistsException.class, - DbInstanceRoleNotFoundException.class) - .build(); - - protected static final ErrorRuleSet DELETE_DB_INSTANCE_ERROR_RULE_SET = ErrorRuleSet - .extend(DEFAULT_DB_INSTANCE_ERROR_RULE_SET) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - ErrorCode.InvalidParameterValue) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound), - ErrorCode.DBInstanceNotFound) - .withErrorCodes(ErrorStatus.conditional(ignoreDBInstanceBeingDeletedConditionalErrorStatus), - ErrorCode.InvalidDBInstanceState) - .withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - ErrorCode.DBSnapshotAlreadyExists) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound), - DbInstanceNotFoundException.class) - .withErrorClasses(ErrorStatus.conditional(ignoreDBInstanceBeingDeletedConditionalErrorStatus), - InvalidDbInstanceStateException.class) - .withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest), - DbSnapshotAlreadyExistsException.class) - .build(); - protected static final ResourceTypeSchema resourceTypeSchema = ResourceTypeSchema.load(new Configuration().resourceSchemaJsonObject()); public BaseHandlerStd(final HandlerConfig config) { super(); this.config = config; this.apiVersionDispatcher = new ApiVersionDispatcher() - .register(ApiVersion.V12, (m, c) -> !software.amazon.awssdk.utils.CollectionUtils.isNullOrEmpty(m.getDBSecurityGroups())); - } - - private static boolean looksLikeDBInstanceBeingDeletedMessage(final String message) { - if (StringUtils.isBlank(message)) { - return false; - } - return message.contains(IS_ALREADY_BEING_DELETED_ERROR_FRAGMENT); - } - - private static boolean isDBInstanceBeingDeletedException(final Exception e) { - if (e instanceof InvalidDbInstanceStateException) { - return looksLikeDBInstanceBeingDeletedMessage(e.getMessage()); - } - return false; + .register(ApiVersion.V12, (m, c) -> !software.amazon.awssdk.utils.CollectionUtils.isNullOrEmpty(m.getDBSecurityGroups())); } protected ApiVersionDispatcher getApiVersionDispatcher() { @@ -301,20 +137,20 @@ protected void validateRequest(final ResourceHandlerRequest reque } protected abstract ProgressEvent handleRequest( - final AmazonWebServicesClientProxy proxy, - final ValidatedRequest request, - final CallbackContext context, - final VersionedProxyClient rdsProxyClient, - final VersionedProxyClient ec2ProxyClient + final AmazonWebServicesClientProxy proxy, + final ValidatedRequest request, + final CallbackContext context, + final VersionedProxyClient rdsProxyClient, + final VersionedProxyClient ec2ProxyClient ); protected ProgressEvent handleRequest( - final AmazonWebServicesClientProxy proxy, - final ResourceHandlerRequest request, - final CallbackContext context, - final VersionedProxyClient rdsProxyClient, - final VersionedProxyClient ec2ProxyClient, - final RequestLogger requestLogger + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext context, + final VersionedProxyClient rdsProxyClient, + final VersionedProxyClient ec2ProxyClient, + final RequestLogger requestLogger ) { this.requestLogger = requestLogger; resourceStabilizationTime(context); @@ -329,84 +165,84 @@ protected ProgressEvent handleRequest( @Override public final ProgressEvent handleRequest( - final AmazonWebServicesClientProxy proxy, - final ResourceHandlerRequest request, - final CallbackContext context, - final Logger logger + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext context, + final Logger logger ) { return RequestLogger.handleRequest( - logger, + logger, + request, + PARAMETERS_FILTER, + requestLogger -> handleRequest( + proxy, request, - PARAMETERS_FILTER, - requestLogger -> handleRequest( - proxy, - request, - context != null ? context : new CallbackContext(), - new VersionedProxyClient() - .register(ApiVersion.V12, new LoggingProxyClient<>(requestLogger, proxy.newProxy(() -> new RdsClientProvider().getClientForApiVersion(API_VERSION_V12)))) - .register(ApiVersion.DEFAULT, new LoggingProxyClient<>(requestLogger, proxy.newProxy(new RdsClientProvider()::getClient))), - new VersionedProxyClient() - .register(ApiVersion.DEFAULT, new LoggingProxyClient<>(requestLogger, proxy.newProxy(new Ec2ClientProvider()::getClient))), - requestLogger - )); + context != null ? context : new CallbackContext(), + new VersionedProxyClient() + .register(ApiVersion.V12, new LoggingProxyClient<>(requestLogger, proxy.newProxy(() -> new RdsClientProvider().getClientForApiVersion(API_VERSION_V12)))) + .register(ApiVersion.DEFAULT, new LoggingProxyClient<>(requestLogger, proxy.newProxy(new RdsClientProvider()::getClient))), + new VersionedProxyClient() + .register(ApiVersion.DEFAULT, new LoggingProxyClient<>(requestLogger, proxy.newProxy(new Ec2ClientProvider()::getClient))), + requestLogger + )); } protected ProgressEvent updateDbInstanceV12( - final AmazonWebServicesClientProxy proxy, - final ResourceHandlerRequest request, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { requestLogger.log("UpdateDbInstanceAPIv12Invoked"); requestLogger.log("Detected API Version 12", "Detected modifyDbInstanceRequestV12. " + - "This indicates that the customer is using DBSecurityGroup, which may result in certain features not" + - " functioning properly. Please refer to the API model for supported parameters"); + "This indicates that the customer is using DBSecurityGroup, which may result in certain features not" + + " functioning properly. Please refer to the API model for supported parameters"); return proxy.initiate("rds::modify-db-instance-v12", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(resourceModel -> Translator.modifyDbInstanceRequestV12( - request.getPreviousResourceState(), - request.getDesiredResourceState(), - BooleanUtils.isTrue(request.getRollback())) - ) - .backoffDelay(config.getBackoff()) - .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( - modifyRequest, - proxyInvocation.client()::modifyDBInstance - )) - .stabilize((modifyRequest, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) - .handleError((modifyRequest, exception, client, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - MODIFY_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(resourceModel -> Translator.modifyDbInstanceRequestV12( + request.getPreviousResourceState(), + request.getDesiredResourceState(), + BooleanUtils.isTrue(request.getRollback())) + ) + .backoffDelay(config.getBackoff()) + .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( + modifyRequest, + proxyInvocation.client()::modifyDBInstance + )) + .stabilize((modifyRequest, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) + .handleError((modifyRequest, exception, client, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE, + requestLogger + )) + .progress(); } protected ProgressEvent updateDbInstance( - final AmazonWebServicesClientProxy proxy, - final ResourceHandlerRequest request, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate("rds::modify-db-instance", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(resourceModel -> Translator.modifyDbInstanceRequest( - request.getPreviousResourceState(), - request.getDesiredResourceState(), - BooleanUtils.isTrue(request.getRollback())) - ) - .backoffDelay(config.getBackoff()) - .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( - modifyRequest, - proxyInvocation.client()::modifyDBInstance - )) - .stabilize((modifyRequest, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) - .handleError((modifyRequest, exception, client, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - MODIFY_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(resourceModel -> Translator.modifyDbInstanceRequest( + request.getPreviousResourceState(), + request.getDesiredResourceState(), + BooleanUtils.isTrue(request.getRollback())) + ) + .backoffDelay(config.getBackoff()) + .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( + modifyRequest, + proxyInvocation.client()::modifyDBInstance + )) + .stabilize((modifyRequest, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) + .handleError((modifyRequest, exception, client, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE, + requestLogger + )) + .progress(); } protected boolean isFailureEvent(final Event event) { @@ -414,112 +250,112 @@ protected boolean isFailureEvent(final Event event) { } protected DBInstance fetchDBInstance( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DescribeDbInstancesResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbInstancesRequest(model), - rdsProxyClient.client()::describeDBInstances + Translator.describeDbInstancesRequest(model), + rdsProxyClient.client()::describeDBInstances ); return response.dbInstances().get(0); } protected DBInstance fetchDBInstance( - final ProxyClient rdsProxyClient, - final String dbInstanceIdentifier + final ProxyClient rdsProxyClient, + final String dbInstanceIdentifier ) { final DescribeDbInstancesResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbInstanceByDBInstanceIdentifierRequest(dbInstanceIdentifier), - rdsProxyClient.client()::describeDBInstances + Translator.describeDbInstanceByDBInstanceIdentifierRequest(dbInstanceIdentifier), + rdsProxyClient.client()::describeDBInstances ); return response.dbInstances().get(0); } protected DBInstance fetchDBInstanceByResourceId( - final ProxyClient rdsProxyClient, - final String resourceId + final ProxyClient rdsProxyClient, + final String resourceId ) { final DescribeDbInstancesResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbInstanceByResourceIdRequest(resourceId), - rdsProxyClient.client()::describeDBInstances + Translator.describeDbInstanceByResourceIdRequest(resourceId), + rdsProxyClient.client()::describeDBInstances ); return response.dbInstances().get(0); } protected DBInstanceAutomatedBackup fetchAutomaticBackup( - final ProxyClient rdsProxyClient, - final String automaticBackupArn + final ProxyClient rdsProxyClient, + final String automaticBackupArn ) { final DescribeDbInstanceAutomatedBackupsResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDBInstanceAutomaticBackup(automaticBackupArn), - rdsProxyClient.client()::describeDBInstanceAutomatedBackups + Translator.describeDBInstanceAutomaticBackup(automaticBackupArn), + rdsProxyClient.client()::describeDBInstanceAutomatedBackups ); return response.dbInstanceAutomatedBackups().get(0); } protected DBCluster fetchDBCluster( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DescribeDbClustersResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbClustersRequest(model), - rdsProxyClient.client()::describeDBClusters + Translator.describeDbClustersRequest(model), + rdsProxyClient.client()::describeDBClusters ); return response.dbClusters().get(0); } protected DBCluster fetchDBCluster( - final ProxyClient rdsProxyClient, - final String dbClusterIdentifier + final ProxyClient rdsProxyClient, + final String dbClusterIdentifier ) { final DescribeDbClustersResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbClusterRequest(dbClusterIdentifier), - rdsProxyClient.client()::describeDBClusters + Translator.describeDbClusterRequest(dbClusterIdentifier), + rdsProxyClient.client()::describeDBClusters ); return response.dbClusters().get(0); } protected DBSnapshot fetchDBSnapshot( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DescribeDbSnapshotsResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbSnapshotsRequest(model), - rdsProxyClient.client()::describeDBSnapshots + Translator.describeDbSnapshotsRequest(model), + rdsProxyClient.client()::describeDBSnapshots ); return response.dbSnapshots().get(0); } protected DBClusterSnapshot fetchDBClusterSnapshot( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DescribeDbClusterSnapshotsResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbClusterSnapshotsRequest(model), - rdsProxyClient.client()::describeDBClusterSnapshots + Translator.describeDbClusterSnapshotsRequest(model), + rdsProxyClient.client()::describeDBClusterSnapshots ); return response.dbClusterSnapshots().get(0); } protected SecurityGroup fetchSecurityGroup( - final ProxyClient ec2ProxyClient, - final String vpcId, - final String groupName + final ProxyClient ec2ProxyClient, + final String vpcId, + final String groupName ) { final DescribeSecurityGroupsResponse response = ec2ProxyClient.injectCredentialsAndInvokeV2( - Translator.describeSecurityGroupsRequest(vpcId, groupName), - ec2ProxyClient.client()::describeSecurityGroups + Translator.describeSecurityGroupsRequest(vpcId, groupName), + ec2ProxyClient.client()::describeSecurityGroups ); return Optional.ofNullable(response.securityGroups()) - .orElse(Collections.emptyList()) - .stream() - .findFirst() - .orElse(null); + .orElse(Collections.emptyList()) + .stream() + .findFirst() + .orElse(null); } protected boolean isDbInstanceDeleted( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { DBInstance dbInstance; try { @@ -533,9 +369,9 @@ protected boolean isDbInstanceDeleted( } protected boolean isDBInstanceStabilizedAfterMutate( - final ProxyClient rdsProxyClient, - final ResourceModel model, - final CallbackContext context + final ProxyClient rdsProxyClient, + final ResourceModel model, + final CallbackContext context ) { final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); @@ -546,13 +382,13 @@ private void resourceStabilizationTime(final CallbackContext context) { context.timestampOnce(DB_INSTANCE_REQUEST_STARTED_AT, Instant.now()); context.timestamp(DB_INSTANCE_REQUEST_IN_PROGRESS_AT, Instant.now()); context.calculateTimeDeltaInMinutes(DB_INSTANCE_STABILIZATION_TIME, - context.getTimestamp(DB_INSTANCE_REQUEST_IN_PROGRESS_AT), - context.getTimestamp(DB_INSTANCE_REQUEST_STARTED_AT)); + context.getTimestamp(DB_INSTANCE_REQUEST_IN_PROGRESS_AT), + context.getTimestamp(DB_INSTANCE_REQUEST_STARTED_AT)); } protected boolean isInstanceStabilizedAfterReplicationStop( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); @@ -567,8 +403,8 @@ protected boolean isInstanceStabilizedAfterReplicationStart(final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); if (DBInstancePredicates.isDBClusterMember(model)) { @@ -580,8 +416,8 @@ protected boolean isDBInstanceStabilizedAfterReboot( } protected boolean isOptionGroupStabilized( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); @@ -589,8 +425,8 @@ protected boolean isOptionGroupStabilized( } protected boolean isDBParameterGroupStabilized( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); @@ -598,8 +434,8 @@ protected boolean isDBParameterGroupStabilized( } protected boolean isDBClusterParameterGroupStabilized( - final ProxyClient rdsProxyClient, - final ResourceModel model + final ProxyClient rdsProxyClient, + final ResourceModel model ) { final DBCluster dbCluster = fetchDBCluster(rdsProxyClient, model); @@ -607,47 +443,47 @@ protected boolean isDBClusterParameterGroupStabilized( } protected boolean isDBInstanceRoleStabilized( - final ProxyClient rdsProxyClient, - final ResourceModel model, - final Function, Boolean> predicate + final ProxyClient rdsProxyClient, + final ResourceModel model, + final Function, Boolean> predicate ) { final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); return predicate.apply(Optional.ofNullable( - dbInstance.associatedRoles() + dbInstance.associatedRoles() ).orElse(Collections.emptyList()).stream()); } protected boolean isDBInstanceRoleAdditionStabilized( - final ProxyClient rdsProxyClient, - final ResourceModel model, - final DBInstanceRole lookupRole + final ProxyClient rdsProxyClient, + final ResourceModel model, + final DBInstanceRole lookupRole ) { return isDBInstanceRoleStabilized( - rdsProxyClient, - model, - (roles) -> roles.anyMatch(role -> role.roleArn().equals(lookupRole.getRoleArn()) && - Objects.equals(StringUtils.trimToNull(role.featureName()), StringUtils.trimToNull(lookupRole.getFeatureName()))) + rdsProxyClient, + model, + (roles) -> roles.anyMatch(role -> role.roleArn().equals(lookupRole.getRoleArn()) && + Objects.equals(StringUtils.trimToNull(role.featureName()), StringUtils.trimToNull(lookupRole.getFeatureName()))) ); } protected boolean isDBInstanceRoleRemovalStabilized( - final ProxyClient rdsProxyClient, - final ResourceModel model, - final DBInstanceRole lookupRole + final ProxyClient rdsProxyClient, + final ResourceModel model, + final DBInstanceRole lookupRole ) { return isDBInstanceRoleStabilized( - rdsProxyClient, - model, - (roles) -> roles.noneMatch(role -> role.roleArn().equals(lookupRole.getRoleArn())) + rdsProxyClient, + model, + (roles) -> roles.noneMatch(role -> role.roleArn().equals(lookupRole.getRoleArn())) ); } protected ProgressEvent updateAssociatedRoles( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - ProgressEvent progress, - Collection previousRoles, - Collection desiredRoles + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + ProgressEvent progress, + Collection previousRoles, + Collection desiredRoles ) { final Set rolesToRemove = new LinkedHashSet<>(Optional.ofNullable(previousRoles).orElse(Collections.emptyList())); final Set rolesToAdd = new LinkedHashSet<>(Optional.ofNullable(desiredRoles).orElse(Collections.emptyList())); @@ -656,33 +492,33 @@ protected ProgressEvent updateAssociatedRoles( rolesToRemove.removeAll(Optional.ofNullable(desiredRoles).orElse(Collections.emptyList())); return progress - .then(p -> removeOldRoles(proxy, rdsProxyClient, p, rolesToRemove)) - .then(p -> addNewRoles(proxy, rdsProxyClient, p, rolesToAdd)); + .then(p -> removeOldRoles(proxy, rdsProxyClient, p, rolesToRemove)) + .then(p -> addNewRoles(proxy, rdsProxyClient, p, rolesToAdd)); } protected ProgressEvent addNewRoles( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress, - final Collection rolesToAdd + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress, + final Collection rolesToAdd ) { for (final DBInstanceRole role : rolesToAdd) { final ProgressEvent progressEvent = proxy.initiate("rds::add-roles-to-db-instance", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(addRequest -> Translator.addRoleToDbInstanceRequest(progress.getResourceModel(), role)) - .backoffDelay(config.getBackoff()) - .makeServiceCall((request, proxyInvocation) -> { - return proxyInvocation.injectCredentialsAndInvokeV2(request, proxyInvocation.client()::addRoleToDBInstance); - }) - .stabilize((request, response, proxyInvocation, modelRequest, callbackContext) -> isDBInstanceRoleAdditionStabilized( - proxyInvocation, modelRequest, role - )) - .handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException( - ProgressEvent.progress(resourceModel, context), - exception, - UPDATE_ASSOCIATED_ROLES_ERROR_RULE_SET, - requestLogger - )) - .success(); + .translateToServiceRequest(addRequest -> Translator.addRoleToDbInstanceRequest(progress.getResourceModel(), role)) + .backoffDelay(config.getBackoff()) + .makeServiceCall((request, proxyInvocation) -> { + return proxyInvocation.injectCredentialsAndInvokeV2(request, proxyInvocation.client()::addRoleToDBInstance); + }) + .stabilize((request, response, proxyInvocation, modelRequest, callbackContext) -> isDBInstanceRoleAdditionStabilized( + proxyInvocation, modelRequest, role + )) + .handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException( + ProgressEvent.progress(resourceModel, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.UPDATE_ASSOCIATED_ROLES, + requestLogger + )) + .success(); if (!progressEvent.isSuccess()) { return progressEvent; } @@ -691,30 +527,30 @@ protected ProgressEvent addNewRoles( } protected ProgressEvent removeOldRoles( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress, - final Collection rolesToRemove + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress, + final Collection rolesToRemove ) { for (final DBInstanceRole role : rolesToRemove) { final ProgressEvent progressEvent = proxy.initiate("rds::remove-roles-from-db-instance", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(removeRequest -> Translator.removeRoleFromDbInstanceRequest( - progress.getResourceModel(), role - )) - .backoffDelay(config.getBackoff()) - .makeServiceCall((request, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( - request, proxyInvocation.client()::removeRoleFromDBInstance - )) - .stabilize((request, response, proxyInvocation, modelRequest, callbackContext) -> isDBInstanceRoleRemovalStabilized( - proxyInvocation, modelRequest, role - )) - .handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException( - ProgressEvent.progress(resourceModel, context), - exception, - UPDATE_ASSOCIATED_ROLES_ERROR_RULE_SET, - requestLogger - )) - .success(); + .translateToServiceRequest(removeRequest -> Translator.removeRoleFromDbInstanceRequest( + progress.getResourceModel(), role + )) + .backoffDelay(config.getBackoff()) + .makeServiceCall((request, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( + request, proxyInvocation.client()::removeRoleFromDBInstance + )) + .stabilize((request, response, proxyInvocation, modelRequest, callbackContext) -> isDBInstanceRoleRemovalStabilized( + proxyInvocation, modelRequest, role + )) + .handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException( + ProgressEvent.progress(resourceModel, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.UPDATE_ASSOCIATED_ROLES, + requestLogger + )) + .success(); if (!progressEvent.isSuccess()) { return progressEvent; } @@ -723,65 +559,65 @@ protected ProgressEvent removeOldRoles( } protected ProgressEvent reboot( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate( - "rds::reboot-db-instance", - rdsProxyClient, - progress.getResourceModel(), - progress.getCallbackContext() - ).translateToServiceRequest(Translator::rebootDbInstanceRequest) - .backoffDelay(config.getBackoff()) - .makeServiceCall((rebootRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( - rebootRequest, - proxyInvocation.client()::rebootDBInstance - )) - .handleError((request, exception, client, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - REBOOT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + "rds::reboot-db-instance", + rdsProxyClient, + progress.getResourceModel(), + progress.getCallbackContext() + ).translateToServiceRequest(Translator::rebootDbInstanceRequest) + .backoffDelay(config.getBackoff()) + .makeServiceCall((rebootRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( + rebootRequest, + proxyInvocation.client()::rebootDBInstance + )) + .handleError((request, exception, client, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + ErrorRuleSets.REBOOT_DB_INSTANCE, + requestLogger + )) + .progress(); } protected ProgressEvent rebootAwait( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return reboot(proxy, rdsProxyClient, progress).then(p -> stabilizeDBInstanceAfterReboot(proxy, rdsProxyClient, p)); } protected ProgressEvent stabilizeDBInstanceAfterReboot( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate( - "rds::stabilize-db-instance-after-reboot-" + getClass().getSimpleName(), - rdsProxyClient, - progress.getResourceModel(), - progress.getCallbackContext() - ) - .translateToServiceRequest(Function.identity()) - .backoffDelay(config.getBackoff()) - .makeServiceCall(NOOP_CALL) - .stabilize((request, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterReboot(proxyInvocation, model)) - .handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException( - ProgressEvent.progress(resourceModel, context), - exception, - UPDATE_ASSOCIATED_ROLES_ERROR_RULE_SET, - requestLogger - )) - .progress(); + "rds::stabilize-db-instance-after-reboot-" + getClass().getSimpleName(), + rdsProxyClient, + progress.getResourceModel(), + progress.getCallbackContext() + ) + .translateToServiceRequest(Function.identity()) + .backoffDelay(config.getBackoff()) + .makeServiceCall(NOOP_CALL) + .stabilize((request, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterReboot(proxyInvocation, model)) + .handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException( + ProgressEvent.progress(resourceModel, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.UPDATE_ASSOCIATED_ROLES, + requestLogger + )) + .progress(); } protected ProgressEvent ensureEngineSet( - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { final ResourceModel model = progress.getResourceModel(); if (StringUtils.isEmpty(model.getEngine())) { @@ -789,18 +625,18 @@ protected ProgressEvent ensureEngineSet( final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model); model.setEngine(dbInstance.engine()); } catch (Exception e) { - return Commons.handleException(progress, e, DEFAULT_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + return Commons.handleException(progress, e, software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, requestLogger); } } return progress; } protected ProgressEvent updateTags( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress, - final Tagging.TagSet previousTags, - final Tagging.TagSet desiredTags + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress, + final Tagging.TagSet previousTags, + final Tagging.TagSet desiredTags ) { final Collection effectivePreviousTags = Tagging.translateTagsToSdk(previousTags); @@ -820,7 +656,7 @@ protected ProgressEvent updateTags( try { dbInstance = fetchDBInstance(rdsProxyClient, progress.getResourceModel()); } catch (Exception exception) { - return Commons.handleException(progress, exception, DEFAULT_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + return Commons.handleException(progress, exception, software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, requestLogger); } final String arn = dbInstance.dbInstanceArn(); @@ -830,10 +666,10 @@ protected ProgressEvent updateTags( Tagging.addTags(rdsProxyClient, arn, Tagging.translateTagsToSdk(tagsToAdd)); } catch (Exception exception) { return Commons.handleException( - progress, - exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET.extendWith(Tagging.getUpdateTagsAccessDeniedRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)), - requestLogger + progress, + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE.extendWith(Tagging.getUpdateTagsAccessDeniedRuleSet(rulesetTagsToAdd, rulesetTagsToRemove)), + requestLogger ); } @@ -841,11 +677,11 @@ protected ProgressEvent updateTags( } protected ProgressEvent versioned( - final AmazonWebServicesClientProxy proxy, - final VersionedProxyClient rdsProxyClient, - final ProgressEvent progress, - final Tagging.TagSet allTags, - final Map> methodVersions + final AmazonWebServicesClientProxy proxy, + final VersionedProxyClient rdsProxyClient, + final ProgressEvent progress, + final Tagging.TagSet allTags, + final Map> methodVersions ) { final ResourceModel model = progress.getResourceModel(); final CallbackContext callbackContext = progress.getCallbackContext(); @@ -857,66 +693,66 @@ protected ProgressEvent versioned( } protected ProgressEvent stopAutomaticBackupReplicationInRegion( - final String dbInstanceArn, - final AmazonWebServicesClientProxy proxy, - final ProgressEvent progress, - final ProxyClient sourceRegionClient, - final String region + final String dbInstanceArn, + final AmazonWebServicesClientProxy proxy, + final ProgressEvent progress, + final ProxyClient sourceRegionClient, + final String region ) { final ProxyClient rdsClient = new LoggingProxyClient<>(requestLogger, proxy.newProxy(() -> new RdsClientProvider().getClientForRegion(region))); return proxy.initiate("rds::stop-db-instance-automatic-backup-replication", rdsClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(resourceModel -> Translator.stopDbInstanceAutomatedBackupsReplicationRequest(dbInstanceArn)) - .backoffDelay(config.getBackoff()) - .makeServiceCall((request, client) -> rdsClient.injectCredentialsAndInvokeV2( - request, - rdsClient.client()::stopDBInstanceAutomatedBackupsReplication - )) - .stabilize((request, response, client, model, context) -> - isInstanceStabilizedAfterReplicationStop(sourceRegionClient, model)) - .handleError((request, exception, client, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(resourceModel -> Translator.stopDbInstanceAutomatedBackupsReplicationRequest(dbInstanceArn)) + .backoffDelay(config.getBackoff()) + .makeServiceCall((request, client) -> rdsClient.injectCredentialsAndInvokeV2( + request, + rdsClient.client()::stopDBInstanceAutomatedBackupsReplication + )) + .stabilize((request, response, client, model, context) -> + isInstanceStabilizedAfterReplicationStop(sourceRegionClient, model)) + .handleError((request, exception, client, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION, + requestLogger + )) + .progress(); } protected ProgressEvent startAutomaticBackupReplicationInRegion( - final String dbInstanceArn, - final String kmsKeyId, - final AmazonWebServicesClientProxy proxy, - final ProgressEvent progress, - final ProxyClient sourceRegionClient, - final String region + final String dbInstanceArn, + final String kmsKeyId, + final AmazonWebServicesClientProxy proxy, + final ProgressEvent progress, + final ProxyClient sourceRegionClient, + final String region ) { final ProxyClient rdsClient = new LoggingProxyClient<>(requestLogger, proxy.newProxy(() -> new RdsClientProvider().getClientForRegion(region))); final String AUTOMATIC_REPLICATION_KMS_KEY_ERROR = "Encrypted instances require a valid KMS key ID"; final String AUTOMATIC_REPLICATION_KMS_KEY_EVENT_MESSAGE = "Provide a valid value for the AutomaticBackupReplicationKmsKeyId property."; return proxy.initiate("rds::start-db-instance-automatic-backup-replication", rdsClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(resourceModel -> Translator.startDbInstanceAutomatedBackupsReplicationRequest(dbInstanceArn, kmsKeyId)) - .backoffDelay(config.getBackoff()) - .makeServiceCall((request, client) -> rdsClient.injectCredentialsAndInvokeV2( - request, - rdsClient.client()::startDBInstanceAutomatedBackupsReplication - )) - .stabilize((request, response, proxyInvocation, model, context) -> - isInstanceStabilizedAfterReplicationStart(sourceRegionClient, model)) - .handleError((request, exception, client, model, context) -> { - ProgressEvent progressEvent = Commons.handleException( - ProgressEvent.progress(model, context), - exception, - MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION_ERROR_RULE_SET, - requestLogger - ); - if (exception.getMessage().contains(AUTOMATIC_REPLICATION_KMS_KEY_ERROR)) { - progressEvent.setMessage(StringUtils.trimToEmpty(progressEvent.getMessage()) - .concat(" " + AUTOMATIC_REPLICATION_KMS_KEY_EVENT_MESSAGE)); - } - return progressEvent; - }) - .progress(); + .translateToServiceRequest(resourceModel -> Translator.startDbInstanceAutomatedBackupsReplicationRequest(dbInstanceArn, kmsKeyId)) + .backoffDelay(config.getBackoff()) + .makeServiceCall((request, client) -> rdsClient.injectCredentialsAndInvokeV2( + request, + rdsClient.client()::startDBInstanceAutomatedBackupsReplication + )) + .stabilize((request, response, proxyInvocation, model, context) -> + isInstanceStabilizedAfterReplicationStart(sourceRegionClient, model)) + .handleError((request, exception, client, model, context) -> { + ProgressEvent progressEvent = Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION, + requestLogger + ); + if (exception.getMessage().contains(AUTOMATIC_REPLICATION_KMS_KEY_ERROR)) { + progressEvent.setMessage(StringUtils.trimToEmpty(progressEvent.getMessage()) + .concat(" " + AUTOMATIC_REPLICATION_KMS_KEY_EVENT_MESSAGE)); + } + return progressEvent; + }) + .progress(); } } 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 8f6661c3..ad1f6d86 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 @@ -31,6 +31,7 @@ import software.amazon.rds.dbinstance.client.ApiVersion; import software.amazon.rds.dbinstance.client.RdsClientProvider; import software.amazon.rds.dbinstance.client.VersionedProxyClient; +import software.amazon.rds.dbinstance.common.ErrorRuleSets; import software.amazon.rds.dbinstance.util.ResourceModelHelper; import software.amazon.rds.dbinstance.validators.OracleCustomSystemId; @@ -99,7 +100,7 @@ protected ProgressEvent handleRequest( try { model.setEngine(fetchEngine(rdsProxyClient.defaultClient(), progress, proxy)); } catch (Exception e) { - return Commons.handleException(progress, e, DB_INSTANCE_FETCH_ENGINE_RULE_SET, requestLogger); + return Commons.handleException(progress, e, ErrorRuleSets.DB_INSTANCE_FETCH_ENGINE, requestLogger); } } return progress; @@ -126,7 +127,7 @@ protected ProgressEvent handleRequest( progress.getResourceModel().setMultiAZ(ResourceModelHelper.getDefaultMultiAzForEngine(engine)); } } catch (Exception e) { - return Commons.handleException(progress, e, RESTORE_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + return Commons.handleException(progress, e, software.amazon.rds.dbinstance.common.ErrorRuleSets.RESTORE_DB_INSTANCE, requestLogger); } } return versioned(proxy, rdsProxyClient, progress, allTags, ImmutableMap.of( @@ -301,7 +302,7 @@ private ProgressEvent createDbInstanceV12( .handleError((request, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - CREATE_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.CREATE_DB_INSTANCE, requestLogger )) .progress(); @@ -329,7 +330,7 @@ private ProgressEvent createDbInstance( .handleError((request, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - CREATE_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.CREATE_DB_INSTANCE, requestLogger )) .progress(); @@ -361,7 +362,7 @@ private ProgressEvent restoreDbInstanceFromSnaps .handleError((request, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - RESTORE_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.RESTORE_DB_INSTANCE, requestLogger )) .progress(); @@ -389,7 +390,7 @@ private ProgressEvent restoreDbInstanceFromSnaps .handleError((request, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - RESTORE_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.RESTORE_DB_INSTANCE, requestLogger )) .progress(); @@ -417,7 +418,7 @@ private ProgressEvent restoreDbInstanceToPointIn .handleError((request, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - RESTORE_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.RESTORE_DB_INSTANCE, requestLogger )) .progress(); @@ -446,7 +447,7 @@ private ProgressEvent createDbInstanceReadReplic .handleError((request, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - CREATE_DB_INSTANCE_READ_REPLICA_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.CREATE_DB_INSTANCE_READ_REPLICA, requestLogger )) .progress(); @@ -473,7 +474,7 @@ protected ProgressEvent updateDbInstanceAfterCre .handleError((modifyRequest, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - MODIFY_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE, requestLogger )) .progress(); @@ -496,7 +497,7 @@ protected ProgressEvent updateDbInstanceAfterCre .handleError((modifyRequest, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - MODIFY_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE, requestLogger )) .progress(); diff --git a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/DeleteHandler.java b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/DeleteHandler.java index 83f5995d..fa96e1de 100644 --- a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/DeleteHandler.java +++ b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/DeleteHandler.java @@ -14,6 +14,7 @@ import software.amazon.rds.common.request.ValidatedRequest; import software.amazon.rds.common.util.IdentifierFactory; import software.amazon.rds.dbinstance.client.VersionedProxyClient; +import software.amazon.rds.dbinstance.common.ErrorRuleSets; import java.util.function.Function; @@ -54,7 +55,7 @@ protected ProgressEvent handleRequest( final var dbInstance = fetchDBInstance(rdsProxyClient.defaultClient(), progress.getResourceModel()); callbackContext.setSnapshotIdentifier(decideSnapshotIdentifier(request, dbInstance)); } catch (Exception exception) { - return Commons.handleException(progress, exception, DEFAULT_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + return Commons.handleException(progress, exception, software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, requestLogger); } return progress; }, CallbackContext::isDescribed, CallbackContext::setDescribed)) @@ -68,7 +69,7 @@ protected ProgressEvent handleRequest( .handleError((deleteRequest, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - DELETE_DB_INSTANCE_ERROR_RULE_SET, + ErrorRuleSets.DELETE_DB_INSTANCE, requestLogger )).progress() ) @@ -83,7 +84,7 @@ protected ProgressEvent handleRequest( .handleError((noopRequest, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, requestLogger )) .progress() diff --git a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/ReadHandler.java b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/ReadHandler.java index 5a58cef7..425919a3 100644 --- a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/ReadHandler.java +++ b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/ReadHandler.java @@ -9,6 +9,7 @@ import software.amazon.rds.common.handler.HandlerConfig; import software.amazon.rds.common.request.ValidatedRequest; import software.amazon.rds.dbinstance.client.VersionedProxyClient; +import software.amazon.rds.dbinstance.common.ErrorRuleSets; public class ReadHandler extends BaseHandlerStd { @@ -36,7 +37,7 @@ protected ProgressEvent handleRequest( .handleError((describeRequest, exception, client, model, context) -> Commons.handleException( ProgressEvent.progress(model, context), exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, + ErrorRuleSets.DEFAULT_DB_INSTANCE, requestLogger )) .done((describeRequest, describeResponse, proxyInvocation, resourceModel, context) -> { diff --git a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/UpdateHandler.java b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/UpdateHandler.java index 63277146..5e0f59d6 100644 --- a/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/UpdateHandler.java +++ b/aws-rds-dbinstance/src/main/java/software/amazon/rds/dbinstance/UpdateHandler.java @@ -7,10 +7,21 @@ import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.ec2.model.SecurityGroup; import software.amazon.awssdk.services.rds.RdsClient; -import software.amazon.awssdk.services.rds.model.*; +import software.amazon.awssdk.services.rds.model.DBCluster; +import software.amazon.awssdk.services.rds.model.DBClusterMember; +import software.amazon.awssdk.services.rds.model.DBInstance; +import software.amazon.awssdk.services.rds.model.DBParameterGroup; +import software.amazon.awssdk.services.rds.model.DbInstanceNotFoundException; +import software.amazon.awssdk.services.rds.model.DescribeDbEngineVersionsResponse; +import software.amazon.awssdk.services.rds.model.DescribeDbParameterGroupsResponse; +import software.amazon.awssdk.services.rds.model.SourceType; import software.amazon.awssdk.utils.ImmutableMap; import software.amazon.cloudformation.exceptions.CfnInvalidRequestException; -import software.amazon.cloudformation.proxy.*; +import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; +import software.amazon.cloudformation.proxy.HandlerErrorCode; +import software.amazon.cloudformation.proxy.ProgressEvent; +import software.amazon.cloudformation.proxy.ProxyClient; +import software.amazon.cloudformation.proxy.ResourceHandlerRequest; import software.amazon.rds.common.handler.Commons; import software.amazon.rds.common.handler.Events; import software.amazon.rds.common.handler.HandlerConfig; @@ -18,6 +29,7 @@ import software.amazon.rds.common.request.ValidatedRequest; import software.amazon.rds.dbinstance.client.ApiVersion; import software.amazon.rds.dbinstance.client.VersionedProxyClient; +import software.amazon.rds.dbinstance.common.ErrorRuleSets; import software.amazon.rds.dbinstance.status.DBInstanceStatus; import software.amazon.rds.dbinstance.status.DBParameterGroupStatus; import software.amazon.rds.dbinstance.util.ImmutabilityHelper; @@ -43,33 +55,33 @@ public UpdateHandler(final HandlerConfig config) { final String handlerOperation = "UPDATE"; protected ProgressEvent handleRequest( - final AmazonWebServicesClientProxy proxy, - final ValidatedRequest request, - final CallbackContext callbackContext, - final VersionedProxyClient rdsProxyClient, - final VersionedProxyClient ec2ProxyClient + final AmazonWebServicesClientProxy proxy, + final ValidatedRequest request, + final CallbackContext callbackContext, + final VersionedProxyClient rdsProxyClient, + final VersionedProxyClient ec2ProxyClient ) { final ProxyClient rdsClient = rdsProxyClient.defaultClient(); DBInstance instance; try { instance = StringUtils.isNullOrEmpty(request.getPreviousResourceState().getEngine()) ? - fetchDBInstance(rdsClient, request.getPreviousResourceState()) : null; + fetchDBInstance(rdsClient, request.getPreviousResourceState()) : null; } catch (Exception ex) { return Commons.handleException( - ProgressEvent.progress(request.getPreviousResourceState(), callbackContext), - ex, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger + ProgressEvent.progress(request.getPreviousResourceState(), callbackContext), + ex, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, + requestLogger ); } if (!ImmutabilityHelper.isChangeMutable(request.getPreviousResourceState(), request.getDesiredResourceState(), instance, requestLogger)) { return ProgressEvent.failed( - request.getDesiredResourceState(), - callbackContext, - HandlerErrorCode.NotUpdatable, - "Resource is immutable" + request.getDesiredResourceState(), + callbackContext, + HandlerErrorCode.NotUpdatable, + "Resource is immutable" ); } @@ -78,174 +90,174 @@ protected ProgressEvent handleRequest( } final Tagging.TagSet previousTags = Tagging.TagSet.builder() - .systemTags(Tagging.translateTagsToSdk(request.getPreviousSystemTags())) - .stackTags(Tagging.translateTagsToSdk(request.getPreviousResourceTags())) - .resourceTags(Translator.translateTagsToSdk(request.getPreviousResourceState().getTags())) - .build(); + .systemTags(Tagging.translateTagsToSdk(request.getPreviousSystemTags())) + .stackTags(Tagging.translateTagsToSdk(request.getPreviousResourceTags())) + .resourceTags(Translator.translateTagsToSdk(request.getPreviousResourceState().getTags())) + .build(); final Tagging.TagSet desiredTags = Tagging.TagSet.builder() - .systemTags(Tagging.translateTagsToSdk(request.getSystemTags())) - .stackTags(Tagging.translateTagsToSdk(request.getDesiredResourceTags())) - .resourceTags(Translator.translateTagsToSdk(request.getDesiredResourceState().getTags())) - .build(); + .systemTags(Tagging.translateTagsToSdk(request.getSystemTags())) + .stackTags(Tagging.translateTagsToSdk(request.getDesiredResourceTags())) + .resourceTags(Translator.translateTagsToSdk(request.getDesiredResourceState().getTags())) + .build(); final Collection previousRoles = request.getPreviousResourceState().getAssociatedRoles(); final Collection desiredRoles = request.getDesiredResourceState().getAssociatedRoles(); return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext) - .then(progress -> { - try { - if (!Objects.equals(request.getDesiredResourceState().getEngineLifecycleSupport(), - request.getPreviousResourceState().getEngineLifecycleSupport()) && - !request.getRollback()) { - throw new CfnInvalidRequestException("EngineLifecycleSupport cannot be modified."); - } - } catch (CfnInvalidRequestException e) { - return Commons.handleException(progress, e, MODIFY_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + .then(progress -> { + try { + if (!Objects.equals(request.getDesiredResourceState().getEngineLifecycleSupport(), + request.getPreviousResourceState().getEngineLifecycleSupport()) && + !request.getRollback()) { + throw new CfnInvalidRequestException("EngineLifecycleSupport cannot be modified."); } - return progress; - }) - .then(progress -> { - if (shouldSetParameterGroupName(request)) { - return setParameterGroupName(rdsClient, progress); + } catch (CfnInvalidRequestException e) { + return Commons.handleException(progress, e, software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE, requestLogger); + } + return progress; + }) + .then(progress -> { + if (shouldSetParameterGroupName(request)) { + return setParameterGroupName(rdsClient, progress); + } + return progress; + }) + .then(progress -> { + if (shouldSetDefaultVpcId(request)) { + return setDefaultVpcId(rdsClient, ec2ProxyClient.defaultClient(), progress); + } + return progress; + }) + .then(progress -> { + if (shouldUnsetMaxAllocatedStorage(request)) { + return unsetMaxAllocatedStorage(rdsClient, request, progress); + } + return progress; + }) + .then(progress -> Commons.execOnce(progress, () -> { + try { + if (shouldAllocateStorage(request, rdsClient, progress)) { + if (isAllocatedStorageIncrease(request)) { + return allocateStorage(proxy, rdsClient, progress); + } } return progress; - }) - .then(progress -> { - if (shouldSetDefaultVpcId(request)) { - return setDefaultVpcId(rdsClient, ec2ProxyClient.defaultClient(), progress); + } catch (Exception ex) { + return Commons.handleException(progress, ex, software.amazon.rds.dbinstance.common.ErrorRuleSets.MODIFY_DB_INSTANCE, requestLogger); + } + }, CallbackContext::isStorageAllocated, CallbackContext::setStorageAllocated)) + .then(progress -> Commons.execOnce(progress, () -> { + if (ResourceModelHelper.isReadReplicaPromotion(request.getPreviousResourceState(), request.getDesiredResourceState())) { + return promoteReadReplica(proxy, rdsClient, progress); + } + return progress; + }, CallbackContext::isReadReplicaPromoted, CallbackContext::setReadReplicaPromoted)) + .then(progress -> Commons.execOnce(progress, () -> { + progress.getCallbackContext().timestampOnce(RESOURCE_UPDATED_AT, Instant.now()); + return versioned(proxy, rdsProxyClient, progress, null, ImmutableMap.of( + ApiVersion.V12, (pxy, pcl, prg, tgs) -> updateDbInstanceV12(pxy, request, pcl, prg), + ApiVersion.DEFAULT, (pxy, pcl, prg, tgs) -> updateDbInstance(pxy, request, pcl, prg) + )).then(p -> Events.checkFailedEvents( + rdsProxyClient.defaultClient(), + p.getResourceModel().getDBInstanceIdentifier(), + SourceType.DB_INSTANCE, + p.getCallbackContext().getTimestamp(RESOURCE_UPDATED_AT), + p, + this::isFailureEvent, + requestLogger + )); + }, CallbackContext::isUpdated, CallbackContext::setUpdated)) + .then(progress -> Commons.execOnce(progress, () -> { + if (shouldReboot(rdsClient, progress)) { + return rebootAwait(proxy, rdsClient, progress); } return progress; - }) - .then(progress -> { - if (shouldUnsetMaxAllocatedStorage(request)) { - return unsetMaxAllocatedStorage(rdsClient, request, progress); + }, CallbackContext::isRebooted, CallbackContext::setRebooted) + ) + .then(progress -> Commons.execOnce(progress, () -> + updateAssociatedRoles(proxy, rdsClient, progress, previousRoles, desiredRoles), + CallbackContext::isUpdatedRoles, CallbackContext::setUpdatedRoles) + ) + .then(progress -> Commons.execOnce(progress, () -> { + if ((ResourceModelHelper.shouldStopAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState()) + || ResourceModelHelper.shouldStartAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState()))) { + final DBInstance dbInstance = fetchDBInstance(rdsProxyClient.defaultClient(), progress.getResourceModel()); + if (StringUtils.isNullOrEmpty(callbackContext.getDbInstanceArn())) { + callbackContext.setDbInstanceArn(dbInstance.dbInstanceArn()); } - return progress; - }) - .then(progress -> Commons.execOnce(progress, () -> { - try { - if (shouldAllocateStorage(request, rdsClient, progress)) { - if (isAllocatedStorageIncrease(request)) { - return allocateStorage(proxy, rdsClient, progress); - } - } - return progress; - } catch (Exception ex) { - return Commons.handleException(progress, ex, MODIFY_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + if (StringUtils.isNullOrEmpty(callbackContext.getKmsKeyId())) { + callbackContext.setKmsKeyId(dbInstance.kmsKeyId()); } - }, CallbackContext::isStorageAllocated, CallbackContext::setStorageAllocated)) - .then(progress -> Commons.execOnce(progress, () -> { - if (ResourceModelHelper.isReadReplicaPromotion(request.getPreviousResourceState(), request.getDesiredResourceState())) { - return promoteReadReplica(proxy, rdsClient, progress); + } + return progress; + }, (m) -> !StringUtils.isNullOrEmpty(callbackContext.getDbInstanceArn()), (v, c) -> { + })) + .then(progress -> Commons.execOnce(progress, () -> { + if (ResourceModelHelper.shouldStopAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) { + return stopAutomaticBackupReplicationInRegion(callbackContext.getDbInstanceArn(), proxy, progress, rdsProxyClient.defaultClient(), + ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getPreviousResourceState())); } return progress; - }, CallbackContext::isReadReplicaPromoted, CallbackContext::setReadReplicaPromoted)) - .then(progress -> Commons.execOnce(progress, () -> { - progress.getCallbackContext().timestampOnce(RESOURCE_UPDATED_AT, Instant.now()); - return versioned(proxy, rdsProxyClient, progress, null, ImmutableMap.of( - ApiVersion.V12, (pxy, pcl, prg, tgs) -> updateDbInstanceV12(pxy, request, pcl, prg), - ApiVersion.DEFAULT, (pxy, pcl, prg, tgs) -> updateDbInstance(pxy, request, pcl, prg) - )).then(p -> Events.checkFailedEvents( + }, + CallbackContext::isAutomaticBackupReplicationStopped, CallbackContext::setAutomaticBackupReplicationStopped)) + .then(progress -> Commons.execOnce(progress, () -> { + if (ResourceModelHelper.shouldStartAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) { + return startAutomaticBackupReplicationInRegion( + callbackContext.getDbInstanceArn(), + progress.getResourceModel().getAutomaticBackupReplicationKmsKeyId(), + proxy, + progress, rdsProxyClient.defaultClient(), - p.getResourceModel().getDBInstanceIdentifier(), - SourceType.DB_INSTANCE, - p.getCallbackContext().getTimestamp(RESOURCE_UPDATED_AT), - p, - this::isFailureEvent, - requestLogger - )); - }, CallbackContext::isUpdated, CallbackContext::setUpdated)) - .then(progress -> Commons.execOnce(progress, () -> { - if (shouldReboot(rdsClient, progress)) { - return rebootAwait(proxy, rdsClient, progress); - } - return progress; - }, CallbackContext::isRebooted, CallbackContext::setRebooted) - ) - .then(progress -> Commons.execOnce(progress, () -> - updateAssociatedRoles(proxy, rdsClient, progress, previousRoles, desiredRoles), - CallbackContext::isUpdatedRoles, CallbackContext::setUpdatedRoles) - ) - .then(progress -> Commons.execOnce(progress, () -> { - if ((ResourceModelHelper.shouldStopAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState()) - || ResourceModelHelper.shouldStartAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState()))) { - final DBInstance dbInstance = fetchDBInstance(rdsProxyClient.defaultClient(), progress.getResourceModel()); - if (StringUtils.isNullOrEmpty(callbackContext.getDbInstanceArn())) { - callbackContext.setDbInstanceArn(dbInstance.dbInstanceArn()); - } - if (StringUtils.isNullOrEmpty(callbackContext.getKmsKeyId())) { - callbackContext.setKmsKeyId(dbInstance.kmsKeyId()); - } + ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getDesiredResourceState()) + ); } return progress; - }, (m) -> !StringUtils.isNullOrEmpty(callbackContext.getDbInstanceArn()), (v, c) -> { - })) - .then(progress -> Commons.execOnce(progress, () -> { - if (ResourceModelHelper.shouldStopAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) { - return stopAutomaticBackupReplicationInRegion(callbackContext.getDbInstanceArn(), proxy, progress, rdsProxyClient.defaultClient(), - ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getPreviousResourceState())); - } - return progress; - }, - CallbackContext::isAutomaticBackupReplicationStopped, CallbackContext::setAutomaticBackupReplicationStopped)) - .then(progress -> Commons.execOnce(progress, () -> { - if (ResourceModelHelper.shouldStartAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) { - return startAutomaticBackupReplicationInRegion( - callbackContext.getDbInstanceArn(), - progress.getResourceModel().getAutomaticBackupReplicationKmsKeyId(), - proxy, - progress, - rdsProxyClient.defaultClient(), - ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getDesiredResourceState()) - ); - } - return progress; - }, - CallbackContext::isAutomaticBackupReplicationStarted, CallbackContext::setAutomaticBackupReplicationStarted)) - .then(progress -> updateTags(proxy, rdsClient, progress, previousTags, desiredTags)) - .then(progress -> { - final ResourceModel model = request.getDesiredResourceState(); - model.setTags(Translator.translateTagsFromSdk(Tagging.translateTagsToSdk(desiredTags))); - return Commons.reportResourceDrift( - model, - new ReadHandler().handleRequest(proxy, request, progress.getCallbackContext(), rdsProxyClient, ec2ProxyClient), - resourceTypeSchema, - requestLogger, - handlerOperation - ); - }); + }, + CallbackContext::isAutomaticBackupReplicationStarted, CallbackContext::setAutomaticBackupReplicationStarted)) + .then(progress -> updateTags(proxy, rdsClient, progress, previousTags, desiredTags)) + .then(progress -> { + final ResourceModel model = request.getDesiredResourceState(); + model.setTags(Translator.translateTagsFromSdk(Tagging.translateTagsToSdk(desiredTags))); + return Commons.reportResourceDrift( + model, + new ReadHandler().handleRequest(proxy, request, progress.getCallbackContext(), rdsProxyClient, ec2ProxyClient), + resourceTypeSchema, + requestLogger, + handlerOperation + ); + }); } private ProgressEvent handleResourceDrift( - final AmazonWebServicesClientProxy proxy, - final ResourceHandlerRequest request, - final CallbackContext callbackContext, - final VersionedProxyClient rdsProxyClient, - final VersionedProxyClient ec2ProxyClient + final AmazonWebServicesClientProxy proxy, + final ResourceHandlerRequest request, + final CallbackContext callbackContext, + final VersionedProxyClient rdsProxyClient, + final VersionedProxyClient ec2ProxyClient ) { return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext) - .then(progress -> { - if (shouldReboot(rdsProxyClient.defaultClient(), progress) || - (DBInstancePredicates.isDBClusterMember(progress.getResourceModel()) && shouldRebootCluster(rdsProxyClient.defaultClient(), progress))) { - return rebootAwait(proxy, rdsProxyClient.defaultClient(), progress); - } - return progress; - }) - .then(progress -> awaitDBParameterGroupInSyncStatus(proxy, rdsProxyClient.defaultClient(), progress)) - .then(progress -> awaitOptionGroupInSyncStatus(proxy, rdsProxyClient.defaultClient(), progress)) - .then(progress -> { - if (DBInstancePredicates.isDBClusterMember(progress.getResourceModel())) { - return awaitDBClusterParameterGroup(proxy, rdsProxyClient.defaultClient(), progress); - } - return progress; - }) - .then(progress -> new ReadHandler().handleRequest(proxy, request, callbackContext, rdsProxyClient, ec2ProxyClient, requestLogger)); + .then(progress -> { + if (shouldReboot(rdsProxyClient.defaultClient(), progress) || + (DBInstancePredicates.isDBClusterMember(progress.getResourceModel()) && shouldRebootCluster(rdsProxyClient.defaultClient(), progress))) { + return rebootAwait(proxy, rdsProxyClient.defaultClient(), progress); + } + return progress; + }) + .then(progress -> awaitDBParameterGroupInSyncStatus(proxy, rdsProxyClient.defaultClient(), progress)) + .then(progress -> awaitOptionGroupInSyncStatus(proxy, rdsProxyClient.defaultClient(), progress)) + .then(progress -> { + if (DBInstancePredicates.isDBClusterMember(progress.getResourceModel())) { + return awaitDBClusterParameterGroup(proxy, rdsProxyClient.defaultClient(), progress); + } + return progress; + }) + .then(progress -> new ReadHandler().handleRequest(proxy, request, callbackContext, rdsProxyClient, ec2ProxyClient, requestLogger)); } private boolean shouldReboot( - final ProxyClient proxyClient, - final ProgressEvent progress + final ProxyClient proxyClient, + final ProgressEvent progress ) { try { final DBInstance dbInstance = fetchDBInstance(proxyClient, progress.getResourceModel()); @@ -259,8 +271,8 @@ private boolean shouldReboot( } private boolean shouldRebootCluster( - final ProxyClient proxyClient, - final ProgressEvent progress + final ProxyClient proxyClient, + final ProgressEvent progress ) { final String dbInstanceIdentifier = progress.getResourceModel().getDBInstanceIdentifier(); final DBCluster dbCluster = fetchDBCluster(proxyClient, progress.getResourceModel()); @@ -279,14 +291,14 @@ private boolean shouldSetParameterGroupName(final ResourceHandlerRequest unsetMaxAllocatedStorage( - final ProxyClient rdsProxyClient, - final ResourceHandlerRequest request, - ProgressEvent progress + final ProxyClient rdsProxyClient, + final ResourceHandlerRequest request, + ProgressEvent progress ) { // In order to disable an instance autoscaling, `MaxAllocatedStorage` property has to be unset. // The only way to unset `MaxAllocatedStorage` is to set it to `AllocatedStorage` value upon an update. @@ -295,36 +307,36 @@ private ProgressEvent unsetMaxAllocatedStorage( final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, request.getDesiredResourceState()); request.getDesiredResourceState().setMaxAllocatedStorage(dbInstance.allocatedStorage()); } catch (Exception exception) { - return Commons.handleException(progress, exception, MODIFY_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + return Commons.handleException(progress, exception, ErrorRuleSets.MODIFY_DB_INSTANCE, requestLogger); } return progress; } private ProgressEvent allocateStorage( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + ProgressEvent progress ) { progress.getCallbackContext().setAllocatingStorage(true); return proxy.initiate("rds::increase-allocated-storage", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(Translator::updateAllocatedStorageRequest) - .backoffDelay(config.getBackoff()) - .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( - modifyRequest, - proxyInvocation.client()::modifyDBInstance)) - .stabilize((request, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) - .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(Translator::updateAllocatedStorageRequest) + .backoffDelay(config.getBackoff()) + .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( + modifyRequest, + proxyInvocation.client()::modifyDBInstance)) + .stabilize((request, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) + .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, + requestLogger + )) + .progress(); } private ProgressEvent setParameterGroupName( - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { final String dbParameterGroupName = progress.getResourceModel().getDBParameterGroupName(); @@ -336,8 +348,8 @@ private ProgressEvent setParameterGroupName( final String engineVersion = progress.getResourceModel().getEngineVersion(); final DescribeDbParameterGroupsResponse response = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbParameterGroupsRequest(dbParameterGroupName), - rdsProxyClient.client()::describeDBParameterGroups + Translator.describeDbParameterGroupsRequest(dbParameterGroupName), + rdsProxyClient.client()::describeDBParameterGroups ); final Optional maybeDbParameterGroup = response.dbParameterGroups().stream().findFirst(); @@ -348,8 +360,8 @@ private ProgressEvent setParameterGroupName( final String dbParameterGroupFamily = maybeDbParameterGroup.get().dbParameterGroupFamily(); final DescribeDbEngineVersionsResponse describeDbEngineVersionsResponse = rdsProxyClient.injectCredentialsAndInvokeV2( - Translator.describeDbEngineVersionsRequest(dbParameterGroupFamily, engine, engineVersion), - rdsProxyClient.client()::describeDBEngineVersions + Translator.describeDbEngineVersionsRequest(dbParameterGroupFamily, engine, engineVersion), + rdsProxyClient.client()::describeDBEngineVersions ); if (CollectionUtils.isNullOrEmpty(describeDbEngineVersionsResponse.dbEngineVersions())) { @@ -364,28 +376,28 @@ private ProgressEvent setParameterGroupName( private boolean shouldSetDefaultVpcId(final ResourceHandlerRequest request) { // DBCluster member instances inherit default vpc security groups from the corresponding umbrella cluster return !DBInstancePredicates.isDBClusterMember(request.getDesiredResourceState()) && - !DBInstancePredicates.isRdsCustomOracleInstance(request.getDesiredResourceState()) && - CollectionUtils.isNullOrEmpty(request.getDesiredResourceState().getVPCSecurityGroups()); + !DBInstancePredicates.isRdsCustomOracleInstance(request.getDesiredResourceState()) && + CollectionUtils.isNullOrEmpty(request.getDesiredResourceState().getVPCSecurityGroups()); } private boolean shouldUnsetMaxAllocatedStorage(final ResourceHandlerRequest request) { return request.getPreviousResourceState() != null && - request.getPreviousResourceState().getMaxAllocatedStorage() != null && - request.getDesiredResourceState().getMaxAllocatedStorage() == null; + request.getPreviousResourceState().getMaxAllocatedStorage() != null && + request.getDesiredResourceState().getMaxAllocatedStorage() == null; } private boolean isAllocatedStorageIncrease( - final ResourceHandlerRequest request + final ResourceHandlerRequest request ) { return BooleanUtils.isNotTrue(request.getRollback()) && - request.getPreviousResourceState() != null && - Translator.getAllocatedStorage(request.getDesiredResourceState()) > Translator.getAllocatedStorage(request.getPreviousResourceState()); + request.getPreviousResourceState() != null && + Translator.getAllocatedStorage(request.getDesiredResourceState()) > Translator.getAllocatedStorage(request.getPreviousResourceState()); } private boolean shouldAllocateStorage( - final ResourceHandlerRequest request, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final ResourceHandlerRequest request, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { // need to store this in the context to prevent premature exit from storage-full-handle if (progress.getCallbackContext().isAllocatingStorage()) { @@ -396,9 +408,9 @@ private boolean shouldAllocateStorage( } private ProgressEvent setDefaultVpcId( - final ProxyClient rdsProxyClient, - final ProxyClient ec2ProxyClient, - final ProgressEvent progress + final ProxyClient rdsProxyClient, + final ProxyClient ec2ProxyClient, + final ProgressEvent progress ) { SecurityGroup securityGroup; @@ -407,7 +419,7 @@ private ProgressEvent setDefaultVpcId( final String vpcId = dbInstance.dbSubnetGroup().vpcId(); securityGroup = fetchSecurityGroup(ec2ProxyClient, vpcId, "default"); } catch (Exception e) { - return Commons.handleException(progress, e, DEFAULT_DB_INSTANCE_ERROR_RULE_SET, requestLogger); + return Commons.handleException(progress, e, software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, requestLogger); } if (securityGroup != null) { @@ -421,80 +433,80 @@ private ProgressEvent setDefaultVpcId( } private ProgressEvent awaitDBParameterGroupInSyncStatus( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate("rds::stabilize-db-parameter-group-drift", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(Function.identity()) - .backoffDelay(config.getBackoff()) - .makeServiceCall(NOOP_CALL) - .stabilize((request, response, proxyInvocation, model, context) -> isDBParameterGroupStabilized(proxyInvocation, model)) - .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(Function.identity()) + .backoffDelay(config.getBackoff()) + .makeServiceCall(NOOP_CALL) + .stabilize((request, response, proxyInvocation, model, context) -> isDBParameterGroupStabilized(proxyInvocation, model)) + .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, + requestLogger + )) + .progress(); } private ProgressEvent awaitOptionGroupInSyncStatus( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate("rds::stabilize-option-group-drift", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(Function.identity()) - .backoffDelay(config.getBackoff()) - .makeServiceCall(NOOP_CALL) - .stabilize((request, response, proxyInvocation, model, context) -> isOptionGroupStabilized(proxyInvocation, model)) - .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(Function.identity()) + .backoffDelay(config.getBackoff()) + .makeServiceCall(NOOP_CALL) + .stabilize((request, response, proxyInvocation, model, context) -> isOptionGroupStabilized(proxyInvocation, model)) + .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, + requestLogger + )) + .progress(); } private ProgressEvent awaitDBClusterParameterGroup( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate("rds::stabilize-db-cluster-parameter-group-drift", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(Function.identity()) - .backoffDelay(config.getBackoff()) - .makeServiceCall(NOOP_CALL) - .stabilize((request, response, proxyInvocation, model, context) -> isDBClusterParameterGroupStabilized(proxyInvocation, model)) - .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(Function.identity()) + .backoffDelay(config.getBackoff()) + .makeServiceCall(NOOP_CALL) + .stabilize((request, response, proxyInvocation, model, context) -> isDBClusterParameterGroupStabilized(proxyInvocation, model)) + .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, + requestLogger + )) + .progress(); } private ProgressEvent promoteReadReplica( - final AmazonWebServicesClientProxy proxy, - final ProxyClient rdsProxyClient, - final ProgressEvent progress + final AmazonWebServicesClientProxy proxy, + final ProxyClient rdsProxyClient, + final ProgressEvent progress ) { return proxy.initiate("rds::promote-read-replica", rdsProxyClient, progress.getResourceModel(), progress.getCallbackContext()) - .translateToServiceRequest(Translator::promoteReadReplicaRequest) - .backoffDelay(config.getBackoff()) - .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( - modifyRequest, - proxyInvocation.client()::promoteReadReplica)) - .stabilize((request, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) - .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( - ProgressEvent.progress(model, context), - exception, - DEFAULT_DB_INSTANCE_ERROR_RULE_SET, - requestLogger - )) - .progress(); + .translateToServiceRequest(Translator::promoteReadReplicaRequest) + .backoffDelay(config.getBackoff()) + .makeServiceCall((modifyRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2( + modifyRequest, + proxyInvocation.client()::promoteReadReplica)) + .stabilize((request, response, proxyInvocation, model, context) -> isDBInstanceStabilizedAfterMutate(proxyInvocation, model, context)) + .handleError((request, exception, proxyInvocation, model, context) -> Commons.handleException( + ProgressEvent.progress(model, context), + exception, + software.amazon.rds.dbinstance.common.ErrorRuleSets.DEFAULT_DB_INSTANCE, + requestLogger + )) + .progress(); } }