Skip to content

Commit

Permalink
[CFN-27] Working towards a more extensible DBInstance create flow. St…
Browse files Browse the repository at this point in the history
…atic methods and error rules have been pulled out of the base handler class; The instance create factory is now constructed by factory according to the model.

[CFN-27] Continuing to seperate db-instance create flows. This pulls out the create from snapshot logic at the cost of some more copy pasta to be addressed in the next commit.
[CFN-27] The 'safeAddTags' method is still c/p but the core change in pattern has finished resulting in a trim create step in the create handler (line 103).

...
  • Loading branch information
Keynan Pratt committed Nov 25, 2024
1 parent fc6dbea commit 9727a77
Show file tree
Hide file tree
Showing 13 changed files with 733 additions and 366 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package software.amazon.rds;

public class ProgressStep {
}
8 changes: 4 additions & 4 deletions aws-rds-dbinstance/pom.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>software.amazon.rds.dbinstance</groupId>
Expand Down Expand Up @@ -267,7 +267,7 @@
<limit>
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.8</minimum>
<minimum>0.82</minimum>
</limit>
<limit>
<counter>INSTRUCTION</counter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public abstract class BaseHandlerStd extends BaseHandler<CallbackContext> {

protected static final RuntimeException MISSING_METHOD_VERSION_EXCEPTION = new RuntimeException("Missing method version");


protected static final String ILLEGAL_DELETION_POLICY_ERROR = "DeletionPolicy:Snapshot cannot be specified for a cluster instance, use deletion policy on the cluster instead.";

protected static final String UNKNOWN_SOURCE_REGION_ERROR = "Unknown source region";
Expand Down Expand Up @@ -395,8 +394,10 @@ protected boolean isInstanceStabilizedAfterReplicationStop(
return DBInstancePredicates.isInstanceStabilizedAfterReplicationStop(dbInstance, model);
}

protected boolean isInstanceStabilizedAfterReplicationStart(final ProxyClient<RdsClient> rdsProxyClient,
final ResourceModel model) {
protected boolean isInstanceStabilizedAfterReplicationStart(
final ProxyClient<RdsClient> rdsProxyClient,
final ResourceModel model
) {
final DBInstance dbInstance = fetchDBInstance(rdsProxyClient, model);

return DBInstancePredicates.isInstanceStabilizedAfterReplicationStart(dbInstance, model);
Expand Down Expand Up @@ -519,6 +520,7 @@ protected ProgressEvent<ResourceModel, CallbackContext> addNewRoles(
requestLogger
))
.success();

if (!progressEvent.isSuccess()) {
return progressEvent;
}
Expand Down Expand Up @@ -547,7 +549,7 @@ protected ProgressEvent<ResourceModel, CallbackContext> removeOldRoles(
.handleError((request, exception, proxyInvocation, resourceModel, context) -> Commons.handleException(
ProgressEvent.progress(resourceModel, context),
exception,
software.amazon.rds.dbinstance.common.ErrorRuleSets.UPDATE_ASSOCIATED_ROLES,
ErrorRuleSets.UPDATE_ASSOCIATED_ROLES,
requestLogger
))
.success();
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ public static CreateDbInstanceRequest createDbInstanceRequest(
return builder.build();
}

static RestoreDbInstanceToPointInTimeRequest restoreDbInstanceToPointInTimeRequest(
public static RestoreDbInstanceToPointInTimeRequest restoreDbInstanceToPointInTimeRequest(
final ResourceModel model,
final Tagging.TagSet tagSet
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package software.amazon.rds.dbinstance.client;

import javax.annotation.Nonnull;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
Expand All @@ -24,6 +25,7 @@ public ApiVersionDispatcher<M, C> register(final ApiVersion version, final BiPre
* @param context An instance of Context.
* @return Returns the highest {@code ApiVersion} matching the input model and context. If no matchers triggered, DEFAULT version is returned (hence no need to register a match-all tester for DEFAULT version).
*/
@Nonnull
public ApiVersion dispatch(final M model, final C context) {
for (final Map.Entry<ApiVersion, BiPredicate<M, C>> entry : versionTesters.entrySet()) {
if (entry.getValue().test(model, context)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package software.amazon.rds.dbinstance.common;

import lombok.AllArgsConstructor;
import software.amazon.awssdk.services.rds.RdsClient;
import software.amazon.awssdk.services.rds.model.DBInstance;
import software.amazon.awssdk.services.rds.model.DBSnapshot;
import software.amazon.awssdk.services.rds.model.DescribeDbInstancesResponse;
import software.amazon.awssdk.services.rds.model.DescribeDbSnapshotsResponse;
import software.amazon.cloudformation.proxy.ProxyClient;
import software.amazon.rds.dbinstance.ResourceModel;
import software.amazon.rds.dbinstance.Translator;

@AllArgsConstructor
public class Fetch {
private final ProxyClient<RdsClient> rdsProxyClient;

public DBInstance dbInstance(final ResourceModel model) {
final DescribeDbInstancesResponse response = rdsProxyClient.injectCredentialsAndInvokeV2(
Translator.describeDbInstancesRequest(model),
rdsProxyClient.client()::describeDBInstances
);
return response.dbInstances().get(0);
}

public DBSnapshot dbSnapshot(final ResourceModel model) {
final DescribeDbSnapshotsResponse response = rdsProxyClient.injectCredentialsAndInvokeV2(
Translator.describeDbSnapshotsRequest(model),
rdsProxyClient.client()::describeDBSnapshots
);
return response.dbSnapshots().get(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package software.amazon.rds.dbinstance.common.create;

import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.rds.dbinstance.CallbackContext;
import software.amazon.rds.dbinstance.ResourceModel;
import software.amazon.rds.dbinstance.util.ResourceModelHelper;

public interface DBInstanceFactory {

ProgressEvent<ResourceModel, CallbackContext> create(
ProgressEvent<ResourceModel, CallbackContext> input
);

boolean modelSatisfiesConstructor(ResourceModel model);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package software.amazon.rds.dbinstance.common.create;

import lombok.AllArgsConstructor;
import software.amazon.awssdk.services.rds.RdsClient;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
import software.amazon.rds.common.handler.HandlerConfig;
import software.amazon.rds.common.handler.Tagging;
import software.amazon.rds.common.logging.RequestLogger;
import software.amazon.rds.dbinstance.CallbackContext;
import software.amazon.rds.dbinstance.ResourceModel;
import software.amazon.rds.dbinstance.client.ApiVersionDispatcher;
import software.amazon.rds.dbinstance.client.VersionedProxyClient;
import software.amazon.rds.dbinstance.util.ResourceModelHelper;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;

@AllArgsConstructor
public class DBInstanceFactoryFactory {

private final Collection<DBInstanceFactory> factories;
private final DBInstanceFactory defaultFactory;

public DBInstanceFactoryFactory(
final AmazonWebServicesClientProxy proxy,
final VersionedProxyClient<RdsClient> rdsProxyClient,
final Tagging.TagSet allTags,
final RequestLogger requestLogger,
final HandlerConfig config,
final ApiVersionDispatcher<ResourceModel, CallbackContext> apiVersionDispatcher
) {

factories = new ArrayList<>();
// The order of this list matters. Do NOT re-order.
factories.add(new FromPointInTime(
proxy,
rdsProxyClient,
allTags,
requestLogger,
config
));
factories.add(new ReadReplica(
proxy,
rdsProxyClient,
allTags,
requestLogger,
config
));
factories.add(new FromSnapshot(
proxy,
rdsProxyClient,
allTags,
requestLogger,
config,
apiVersionDispatcher
));

defaultFactory = new FreshInstance(
proxy,
rdsProxyClient,
allTags,
requestLogger,
config,
apiVersionDispatcher
);
}

public DBInstanceFactory createFactory(ResourceModel model) {
return discernFactoryType(model).orElse(defaultFactory);
}

private Optional<DBInstanceFactory> discernFactoryType(ResourceModel model) {
for (DBInstanceFactory fac : factories) {
if (fac.modelSatisfiesConstructor(model)) {
return Optional.of(fac);
}
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package software.amazon.rds.dbinstance.common.create;

import lombok.AllArgsConstructor;
import software.amazon.awssdk.services.rds.RdsClient;
import software.amazon.awssdk.services.rds.model.DBInstance;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.ProxyClient;
import software.amazon.rds.common.handler.Commons;
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.RequestLogger;
import software.amazon.rds.dbinstance.CallbackContext;
import software.amazon.rds.dbinstance.DBInstancePredicates;
import software.amazon.rds.dbinstance.ResourceModel;
import software.amazon.rds.dbinstance.Translator;
import software.amazon.rds.dbinstance.client.ApiVersion;
import software.amazon.rds.dbinstance.client.ApiVersionDispatcher;
import software.amazon.rds.dbinstance.client.VersionedProxyClient;
import software.amazon.rds.dbinstance.common.ErrorRuleSets;
import software.amazon.rds.dbinstance.common.Fetch;

@AllArgsConstructor
public class FreshInstance implements DBInstanceFactory {

private final AmazonWebServicesClientProxy proxy;
private final VersionedProxyClient<RdsClient> rdsProxyClient;
private final Tagging.TagSet allTags;
private final RequestLogger requestLogger;
private final HandlerConfig config;
private final ApiVersionDispatcher<ResourceModel, CallbackContext> apiVersionDispatcher;

@Override
public ProgressEvent<ResourceModel, CallbackContext> create(ProgressEvent<ResourceModel, CallbackContext> progress) {
final ResourceModel model = progress.getResourceModel();
final CallbackContext callbackContext = progress.getCallbackContext();
final ApiVersion apiVersion = selectVersion(model, callbackContext);

if (apiVersion == ApiVersion.V12) {
return createDbInstanceV12(proxy, rdsProxyClient.forVersion(apiVersion), progress, allTags);
}

return safeAddTags(this::createDbInstance).invoke(proxy, rdsProxyClient.forVersion(apiVersion), progress, allTags);
}

@Override
public boolean modelSatisfiesConstructor(ResourceModel model) {
return true;
}

private ProgressEvent<ResourceModel, CallbackContext> createDbInstance(
final AmazonWebServicesClientProxy proxy,
final ProxyClient<RdsClient> rdsProxyClient,
final ProgressEvent<ResourceModel, CallbackContext> progress,
final Tagging.TagSet tagSet
) {
final Fetch fetch = new Fetch(rdsProxyClient);
return proxy.initiate(
"rds::create-db-instance",
rdsProxyClient,
progress.getResourceModel(),
progress.getCallbackContext()
).translateToServiceRequest(model -> Translator.createDbInstanceRequest(model, tagSet))
.backoffDelay(config.getBackoff())
.makeServiceCall((createRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2(
createRequest,
proxyInvocation.client()::createDBInstance
))
.stabilize((request, response, proxyInvocation, model, context) -> {
final DBInstance dbInstance = fetch.dbInstance(model);
return DBInstancePredicates.isDBInstanceStabilizedAfterMutate(dbInstance, model, context, requestLogger);
})
.handleError((request, exception, client, model, context) -> Commons.handleException(
ProgressEvent.progress(model, context),
exception,
software.amazon.rds.dbinstance.common.ErrorRuleSets.CREATE_DB_INSTANCE,
requestLogger
))
.progress();
}

private ProgressEvent<ResourceModel, CallbackContext> createDbInstanceV12(
final AmazonWebServicesClientProxy proxy,
final ProxyClient<RdsClient> rdsProxyClient,
final ProgressEvent<ResourceModel, CallbackContext> progress,
final Tagging.TagSet tagSet
) {
requestLogger.log("CreateDbInstanceAPIv12Invoked");
requestLogger.log("API version 12 create detected",
"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");
final Fetch fetch = new Fetch(rdsProxyClient);
return proxy.initiate(
"rds::create-db-instance-v12",
rdsProxyClient,
progress.getResourceModel(),
progress.getCallbackContext()
).translateToServiceRequest(Translator::createDbInstanceRequestV12)
.backoffDelay(config.getBackoff())
.makeServiceCall((createRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2(
createRequest,
proxyInvocation.client()::createDBInstance
))
.stabilize((request, response, proxyInvocation, model, context) -> {
final DBInstance dbInstance = fetch.dbInstance(model);
return DBInstancePredicates.isDBInstanceStabilizedAfterMutate(dbInstance, model, context, requestLogger);
})
.handleError((request, exception, client, model, context) -> Commons.handleException(
ProgressEvent.progress(model, context),
exception,
ErrorRuleSets.CREATE_DB_INSTANCE,
requestLogger
))
.progress();
}

private ApiVersion selectVersion(ResourceModel model, CallbackContext callbackContext) {
return apiVersionDispatcher.dispatch(model, callbackContext);
}

private HandlerMethod<ResourceModel, CallbackContext> safeAddTags(final HandlerMethod<ResourceModel, CallbackContext> handlerMethod) {
return (proxy, rdsProxyClient, progress, tagSet) -> progress.then(p -> Tagging.createWithTaggingFallback(proxy, rdsProxyClient, handlerMethod, progress, tagSet));
}
}
Loading

0 comments on commit 9727a77

Please sign in to comment.