Skip to content

Commit fc6dbea

Browse files
author
Keynan Pratt
committed
Pulling a little more out of BaseHandlerStd for re-use in non-extending classes.
1 parent 5960130 commit fc6dbea

File tree

6 files changed

+886
-795
lines changed

6 files changed

+886
-795
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package software.amazon.rds.dbinstance.common;
2+
3+
import software.amazon.awssdk.services.rds.model.AuthorizationNotFoundException;
4+
import software.amazon.awssdk.services.rds.model.CertificateNotFoundException;
5+
import software.amazon.awssdk.services.rds.model.DbClusterNotFoundException;
6+
import software.amazon.awssdk.services.rds.model.DbClusterSnapshotNotFoundException;
7+
import software.amazon.awssdk.services.rds.model.DbInstanceAlreadyExistsException;
8+
import software.amazon.awssdk.services.rds.model.DbInstanceAutomatedBackupQuotaExceededException;
9+
import software.amazon.awssdk.services.rds.model.DbInstanceNotFoundException;
10+
import software.amazon.awssdk.services.rds.model.DbInstanceRoleAlreadyExistsException;
11+
import software.amazon.awssdk.services.rds.model.DbInstanceRoleNotFoundException;
12+
import software.amazon.awssdk.services.rds.model.DbParameterGroupNotFoundException;
13+
import software.amazon.awssdk.services.rds.model.DbSecurityGroupNotFoundException;
14+
import software.amazon.awssdk.services.rds.model.DbSnapshotAlreadyExistsException;
15+
import software.amazon.awssdk.services.rds.model.DbSnapshotNotFoundException;
16+
import software.amazon.awssdk.services.rds.model.DbSubnetGroupDoesNotCoverEnoughAZsException;
17+
import software.amazon.awssdk.services.rds.model.DbSubnetGroupNotFoundException;
18+
import software.amazon.awssdk.services.rds.model.DbUpgradeDependencyFailureException;
19+
import software.amazon.awssdk.services.rds.model.DomainNotFoundException;
20+
import software.amazon.awssdk.services.rds.model.InstanceQuotaExceededException;
21+
import software.amazon.awssdk.services.rds.model.InsufficientDbInstanceCapacityException;
22+
import software.amazon.awssdk.services.rds.model.InvalidDbClusterStateException;
23+
import software.amazon.awssdk.services.rds.model.InvalidDbInstanceAutomatedBackupStateException;
24+
import software.amazon.awssdk.services.rds.model.InvalidDbInstanceStateException;
25+
import software.amazon.awssdk.services.rds.model.InvalidDbSecurityGroupStateException;
26+
import software.amazon.awssdk.services.rds.model.InvalidDbSnapshotStateException;
27+
import software.amazon.awssdk.services.rds.model.InvalidRestoreException;
28+
import software.amazon.awssdk.services.rds.model.InvalidSubnetException;
29+
import software.amazon.awssdk.services.rds.model.InvalidVpcNetworkStateException;
30+
import software.amazon.awssdk.services.rds.model.KmsKeyNotAccessibleException;
31+
import software.amazon.awssdk.services.rds.model.NetworkTypeNotSupportedException;
32+
import software.amazon.awssdk.services.rds.model.OptionGroupNotFoundException;
33+
import software.amazon.awssdk.services.rds.model.ProvisionedIopsNotAvailableInAzException;
34+
import software.amazon.awssdk.services.rds.model.SnapshotQuotaExceededException;
35+
import software.amazon.awssdk.services.rds.model.StorageQuotaExceededException;
36+
import software.amazon.awssdk.services.rds.model.StorageTypeNotSupportedException;
37+
import software.amazon.awssdk.utils.StringUtils;
38+
import software.amazon.cloudformation.exceptions.CfnInvalidRequestException;
39+
import software.amazon.cloudformation.proxy.HandlerErrorCode;
40+
import software.amazon.cloudformation.proxy.OperationStatus;
41+
import software.amazon.rds.common.error.ErrorCode;
42+
import software.amazon.rds.common.error.ErrorRuleSet;
43+
import software.amazon.rds.common.error.ErrorStatus;
44+
import software.amazon.rds.common.handler.Commons;
45+
46+
import java.util.function.Function;
47+
48+
public class ErrorRuleSets {
49+
50+
public static final ErrorRuleSet DEFAULT_DB_INSTANCE = ErrorRuleSet
51+
.extend(Commons.DEFAULT_ERROR_RULE_SET)
52+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded),
53+
ErrorCode.InstanceQuotaExceeded,
54+
ErrorCode.InsufficientDBInstanceCapacity,
55+
ErrorCode.SnapshotQuotaExceeded,
56+
ErrorCode.StorageQuotaExceeded)
57+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
58+
ErrorCode.DBSubnetGroupNotAllowedFault,
59+
ErrorCode.InvalidParameterCombination,
60+
ErrorCode.InvalidParameterValue,
61+
ErrorCode.InvalidVPCNetworkStateFault,
62+
ErrorCode.KMSKeyNotAccessibleFault,
63+
ErrorCode.MissingParameter,
64+
ErrorCode.ProvisionedIopsNotAvailableInAZFault,
65+
ErrorCode.StorageTypeNotSupportedFault)
66+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound),
67+
ErrorCode.DBClusterNotFoundFault,
68+
ErrorCode.DBParameterGroupNotFound,
69+
ErrorCode.DBSecurityGroupNotFound,
70+
ErrorCode.DBSnapshotNotFound,
71+
ErrorCode.DBSubnetGroupNotFoundFault)
72+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound),
73+
CertificateNotFoundException.class,
74+
DbClusterNotFoundException.class,
75+
DbInstanceNotFoundException.class,
76+
DbParameterGroupNotFoundException.class,
77+
DbSecurityGroupNotFoundException.class,
78+
DbSnapshotNotFoundException.class,
79+
DbClusterSnapshotNotFoundException.class,
80+
DbSubnetGroupNotFoundException.class,
81+
DomainNotFoundException.class,
82+
OptionGroupNotFoundException.class)
83+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded),
84+
DbInstanceAutomatedBackupQuotaExceededException.class,
85+
InsufficientDbInstanceCapacityException.class,
86+
InstanceQuotaExceededException.class,
87+
SnapshotQuotaExceededException.class,
88+
StorageQuotaExceededException.class)
89+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict),
90+
InvalidDbInstanceStateException.class,
91+
InvalidDbClusterStateException.class,
92+
DbUpgradeDependencyFailureException.class,
93+
InvalidDbSecurityGroupStateException.class)
94+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
95+
AuthorizationNotFoundException.class,
96+
DbSubnetGroupDoesNotCoverEnoughAZsException.class,
97+
InvalidVpcNetworkStateException.class,
98+
KmsKeyNotAccessibleException.class,
99+
NetworkTypeNotSupportedException.class,
100+
ProvisionedIopsNotAvailableInAzException.class,
101+
StorageTypeNotSupportedException.class)
102+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
103+
DbInstanceAlreadyExistsException.class)
104+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.GeneralServiceException),
105+
InvalidSubnetException.class)
106+
.build();
107+
108+
public static final ErrorRuleSet DB_INSTANCE_FETCH_ENGINE = ErrorRuleSet
109+
.extend(DEFAULT_DB_INSTANCE)
110+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
111+
CfnInvalidRequestException.class)
112+
.build();
113+
114+
public static final ErrorRuleSet RESTORE_DB_INSTANCE = ErrorRuleSet
115+
.extend(DEFAULT_DB_INSTANCE)
116+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
117+
ErrorCode.DBInstanceAlreadyExists)
118+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
119+
ErrorCode.InvalidDBSnapshotState,
120+
ErrorCode.InvalidRestoreFault)
121+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
122+
DbInstanceAlreadyExistsException.class)
123+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
124+
InvalidDbSnapshotStateException.class,
125+
InvalidRestoreException.class)
126+
.build();
127+
public static final ErrorRuleSet CREATE_DB_INSTANCE = ErrorRuleSet
128+
.extend(DEFAULT_DB_INSTANCE)
129+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
130+
ErrorCode.DBInstanceAlreadyExists)
131+
.withErrorClasses(
132+
ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
133+
DbInstanceAlreadyExistsException.class)
134+
.build();
135+
136+
public static final ErrorRuleSet CREATE_DB_INSTANCE_READ_REPLICA = ErrorRuleSet
137+
.extend(DEFAULT_DB_INSTANCE)
138+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
139+
ErrorCode.DBInstanceAlreadyExists)
140+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.AlreadyExists),
141+
DbInstanceAlreadyExistsException.class)
142+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound),
143+
DbClusterNotFoundException.class)
144+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict),
145+
InvalidDbClusterStateException.class)
146+
.build();
147+
148+
public static final ErrorRuleSet REBOOT_DB_INSTANCE = ErrorRuleSet
149+
.extend(DEFAULT_DB_INSTANCE)
150+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound),
151+
ErrorCode.DBInstanceNotFound)
152+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict),
153+
ErrorCode.InvalidDBInstanceState)
154+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound),
155+
DbInstanceNotFoundException.class)
156+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict),
157+
InvalidDbInstanceStateException.class)
158+
.build();
159+
160+
public static final ErrorRuleSet MODIFY_DB_INSTANCE_AUTOMATIC_BACKUP_REPLICATION = ErrorRuleSet
161+
.extend(DEFAULT_DB_INSTANCE)
162+
.withErrorClasses(ErrorStatus.ignore(OperationStatus.IN_PROGRESS),
163+
InvalidDbInstanceAutomatedBackupStateException.class)
164+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ServiceLimitExceeded),
165+
DbInstanceAutomatedBackupQuotaExceededException.class)
166+
.build();
167+
168+
public static final ErrorRuleSet MODIFY_DB_INSTANCE = ErrorRuleSet
169+
.extend(DEFAULT_DB_INSTANCE)
170+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict),
171+
ErrorCode.InvalidDBInstanceState)
172+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound),
173+
ErrorCode.DBInstanceNotFound)
174+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
175+
ErrorCode.InvalidDBSecurityGroupState,
176+
ErrorCode.InvalidParameterCombination)
177+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.ResourceConflict),
178+
InvalidDbInstanceStateException.class)
179+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound),
180+
DbInstanceNotFoundException.class)
181+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
182+
CfnInvalidRequestException.class,
183+
InvalidDbSecurityGroupStateException.class)
184+
.build();
185+
186+
public static final ErrorRuleSet UPDATE_ASSOCIATED_ROLES = ErrorRuleSet
187+
.extend(DEFAULT_DB_INSTANCE)
188+
.withErrorClasses(ErrorStatus.ignore(),
189+
DbInstanceRoleAlreadyExistsException.class,
190+
DbInstanceRoleNotFoundException.class)
191+
.build();
192+
193+
private static final Function<Exception, ErrorStatus> ignoreDBInstanceBeingDeletedConditionalErrorStatus = exception -> {
194+
if (isDBInstanceBeingDeletedException(exception)) {
195+
return ErrorStatus.ignore(OperationStatus.IN_PROGRESS);
196+
}
197+
return ErrorStatus.failWith(HandlerErrorCode.ResourceConflict);
198+
};
199+
200+
public static final ErrorRuleSet DELETE_DB_INSTANCE = ErrorRuleSet
201+
.extend(DEFAULT_DB_INSTANCE)
202+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
203+
ErrorCode.InvalidParameterValue)
204+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.NotFound),
205+
ErrorCode.DBInstanceNotFound)
206+
.withErrorCodes(ErrorStatus.conditional(ignoreDBInstanceBeingDeletedConditionalErrorStatus),
207+
ErrorCode.InvalidDBInstanceState)
208+
.withErrorCodes(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
209+
ErrorCode.DBSnapshotAlreadyExists)
210+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.NotFound),
211+
DbInstanceNotFoundException.class)
212+
.withErrorClasses(ErrorStatus.conditional(ignoreDBInstanceBeingDeletedConditionalErrorStatus),
213+
InvalidDbInstanceStateException.class)
214+
.withErrorClasses(ErrorStatus.failWith(HandlerErrorCode.InvalidRequest),
215+
DbSnapshotAlreadyExistsException.class)
216+
.build();
217+
218+
// Note: looking up this error message fragment is the only way to distinguish between an already deleting
219+
// instance and any other invalid states (e.g. a stopped instance). It relies on a specific error text returned by
220+
// AWS RDS API. The message text is by no means guarded by any public contract. This error message can change
221+
// in the future with no prior notice by AWS RDS. A change in this error message would cause a CFN stack failure
222+
// upon a stack deletion: if an instance is being deleted out-of-bounds. This is a pretty corner (still common) case
223+
// where the CFN handler is trying to help the customer. A regular stack deletion will not be impacted.
224+
// Considered bounded-safe.
225+
private static final String IS_ALREADY_BEING_DELETED_ERROR_FRAGMENT = "is already being deleted";
226+
227+
private static boolean isDBInstanceBeingDeletedException(final Exception e) {
228+
if (e instanceof InvalidDbInstanceStateException) {
229+
return looksLikeDBInstanceBeingDeletedMessage(e.getMessage());
230+
}
231+
return false;
232+
}
233+
234+
private static boolean looksLikeDBInstanceBeingDeletedMessage(final String message) {
235+
if (StringUtils.isBlank(message)) {
236+
return false;
237+
}
238+
return message.contains(ErrorRuleSets.IS_ALREADY_BEING_DELETED_ERROR_FRAGMENT);
239+
}
240+
}

0 commit comments

Comments
 (0)