Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions aws-rds-dbinstance/aws-rds-dbinstance.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@
"type": "string",
"description": "The Amazon Web Services KMS key identifier for encryption of the replicated automated backups. The KMS key ID is the Amazon Resource Name (ARN) for the KMS encryption key in the destination Amazon Web Services Region, for example, `arn:aws:kms:us-east-1:123456789012:key/AKIAIOSFODNN7EXAMPLE` ."
},
"AutomaticBackupReplicationRetentionPeriod": {
"type": "integer",
"minimum": 1,
"description": "The number of days for which automated cross-region replicated backups are retained. If this value is unset, default to BackupRetentionPeriod."
},
"AvailabilityZone": {
"type": "string",
"description": "The Availability Zone (AZ) where the database will be created. For information on AWS Regions and Availability Zones."
Expand Down Expand Up @@ -641,6 +646,7 @@
"rds:DescribeDBEngineVersions",
"rds:DescribeDBInstances",
"rds:DescribeDBParameterGroups",
"rds:DescribeDBInstanceAutomatedBackups",
"rds:DescribeEvents",
"rds:ModifyDBInstance",
"rds:PromoteReadReplica",
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class CallbackContext extends StdCallbackContext implements TaggingContex
private boolean automaticBackupReplicationStopped;
private boolean automaticBackupReplicationStarted;
private String dbInstanceArn;
private String automaticBackupReplicationArn;
private String currentRegion;
private String kmsKeyId;
private String snapshotIdentifier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import software.amazon.rds.dbinstance.client.RdsClientProvider;
import software.amazon.rds.dbinstance.client.VersionedProxyClient;
import software.amazon.rds.dbinstance.util.ResourceModelHelper;
import software.amazon.rds.dbinstance.validators.AutomaticBackupReplicationValidator;
import software.amazon.rds.dbinstance.validators.OracleCustomSystemId;

public class CreateHandler extends BaseHandlerStd {
Expand Down Expand Up @@ -59,6 +60,8 @@ protected void validateRequest(final ResourceHandlerRequest<ResourceModel> reque
Validations.validateTimestamp(request.getDesiredResourceState().getRestoreTime());

OracleCustomSystemId.validateRequest(request.getDesiredResourceState());

AutomaticBackupReplicationValidator.validateRequest(request.getDesiredResourceState());
}

private void validateDeletionPolicyForClusterInstance(final ResourceHandlerRequest<ResourceModel> request) throws RequestValidationException {
Expand Down Expand Up @@ -192,18 +195,21 @@ ApiVersion.DEFAULT, safeAddTags(this::createDbInstance)
return progress;
}, (m) -> !StringUtils.isNullOrEmpty(callbackContext.getDbInstanceArn()), (v, c) -> {}))
.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;
},
final ResourceModel resourceModel = progress.getResourceModel();

if (ResourceModelHelper.shouldStartAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) {
return startAutomaticBackupReplicationInRegion(
callbackContext.getDbInstanceArn(),
ResourceModelHelper.getAutomaticBackupReplicationRetentionPeriod(resourceModel),
resourceModel.getAutomaticBackupReplicationKmsKeyId(),
proxy,
progress,
rdsProxyClient.defaultClient(),
ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getDesiredResourceState())
);
}
return progress;
},
CallbackContext::isAutomaticBackupReplicationStarted, CallbackContext::setAutomaticBackupReplicationStarted))
.then(progress -> {
model.setTags(Translator.translateTagsFromSdk(Tagging.translateTagsToSdk(allTags)));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
package software.amazon.rds.dbinstance;

import com.amazonaws.util.StringUtils;
import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.rds.RdsClient;
import software.amazon.awssdk.services.rds.model.DBInstance;
import software.amazon.awssdk.services.rds.model.DBInstanceAutomatedBackup;
import software.amazon.awssdk.services.rds.model.DBInstanceAutomatedBackupsReplication;
import software.amazon.awssdk.services.rds.model.RdsException;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.ProxyClient;
import software.amazon.rds.common.error.ErrorStatus;
import software.amazon.rds.common.error.HandlerErrorStatus;
import software.amazon.rds.common.handler.Commons;
import software.amazon.rds.common.handler.HandlerConfig;
import software.amazon.rds.common.request.ValidatedRequest;
import software.amazon.rds.dbinstance.util.ResourceModelHelper;
import software.amazon.rds.dbinstance.client.RdsClientProvider;
import software.amazon.rds.dbinstance.client.VersionedProxyClient;

import java.util.List;

public class ReadHandler extends BaseHandlerStd {

public ReadHandler() {
Expand All @@ -20,28 +32,98 @@ public ReadHandler(final HandlerConfig config) {
super(config);
}



protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(
final AmazonWebServicesClientProxy proxy,
final ValidatedRequest<ResourceModel> request,
final CallbackContext callbackContext,
final VersionedProxyClient<RdsClient> rdsProxyClient,
final VersionedProxyClient<Ec2Client> ec2ProxyClient
) {
return proxy.initiate("rds::describe-db-instance", rdsProxyClient.defaultClient(), request.getDesiredResourceState(), callbackContext)
.translateToServiceRequest(Translator::describeDbInstancesRequest)
.makeServiceCall((describeRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2(
describeRequest,
proxyInvocation.client()::describeDBInstances
))
.handleError((describeRequest, exception, client, model, context) -> Commons.handleException(
ProgressEvent.progress(model, context),
exception,
DEFAULT_DB_INSTANCE_ERROR_RULE_SET,
requestLogger
))
.done((describeRequest, describeResponse, proxyInvocation, resourceModel, context) -> {
final DBInstance dbInstance = describeResponse.dbInstances().get(0);
return ProgressEvent.success(Translator.translateDbInstanceFromSdk(dbInstance), context);
});
return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext)
.then(progress -> describeDbInstance(progress, proxy, rdsProxyClient))
.then(progress -> {
// If replication found for DB instance, we describe it
if (!StringUtils.isNullOrEmpty(progress.getCallbackContext().getAutomaticBackupReplicationArn())) {
return describeAutomatedBackupsReplication(progress, proxy);
}
return progress;
})
.then(progress -> ProgressEvent.success(progress.getResourceModel(), progress.getCallbackContext()));
}

protected ProgressEvent<ResourceModel, CallbackContext> describeDbInstance(
final ProgressEvent<ResourceModel, CallbackContext> progress,
final AmazonWebServicesClientProxy proxy,
final VersionedProxyClient<RdsClient> rdsProxyClient
) {
final CallbackContext callbackContext = progress.getCallbackContext();
final ResourceModel resourceModel = progress.getResourceModel();

return proxy.initiate("rds::describe-db-instance", rdsProxyClient.defaultClient(), resourceModel, callbackContext)
.translateToServiceRequest(Translator::describeDbInstancesRequest)
.makeServiceCall((describeRequest, proxyInvocation) -> {
return proxyInvocation.injectCredentialsAndInvokeV2(
describeRequest,
proxyInvocation.client()::describeDBInstances
);
})
.handleError((describeRequest, exception, client, model, context) -> Commons.handleException(
ProgressEvent.progress(model, context),
exception,
DEFAULT_DB_INSTANCE_ERROR_RULE_SET,
requestLogger
))
.done((describeRequest, describeResponse, automatedBackupProxyInvocation, model, context) -> {
final DBInstance dbInstance = describeResponse.dbInstances().get(0);
final ResourceModel currentModel = Translator.translateDbInstanceFromSdk(dbInstance);
final List<DBInstanceAutomatedBackupsReplication> replications = dbInstance.dbInstanceAutomatedBackupsReplications();
if (replications.isEmpty()) {
context.setAutomaticBackupReplicationStopped(true);
return ProgressEvent.progress(currentModel, context);
}
context.setAutomaticBackupReplicationArn(replications.get(0).dbInstanceAutomatedBackupsArn());

return ProgressEvent.progress(currentModel, context);
});
}

protected ProgressEvent<ResourceModel, CallbackContext> describeAutomatedBackupsReplication(
final ProgressEvent<ResourceModel, CallbackContext> progress,
final AmazonWebServicesClientProxy proxy
) {
final CallbackContext callbackContext = progress.getCallbackContext();
final ResourceModel resourceModel = progress.getResourceModel();

if (StringUtils.isNullOrEmpty(callbackContext.getAutomaticBackupReplicationArn())) {
return ProgressEvent.progress(resourceModel, callbackContext);
}

final String replicationRegion = ResourceModelHelper.getRegionFromArn(callbackContext.getAutomaticBackupReplicationArn());
final ProxyClient<RdsClient> replicationRegionProxyClient =
proxy.newProxy(() -> new RdsClientProvider().getClientForRegion(replicationRegion));

return proxy.initiate("rds::describe-db-instance-automated-backups", replicationRegionProxyClient, resourceModel, callbackContext)
.translateToServiceRequest(model -> Translator.describeDBInstanceAutomaticBackupRequest(callbackContext.getAutomaticBackupReplicationArn()))
.backoffDelay(config.getBackoff())
.makeServiceCall((describeRequest, proxyInvocation) -> proxyInvocation.injectCredentialsAndInvokeV2(
describeRequest,
proxyInvocation.client()::describeDBInstanceAutomatedBackups
))
.handleError((describeRequest, exception, client, model, context) ->Commons.handleException(
ProgressEvent.progress(model, context),
exception,
DESCRIBE_AUTOMATED_BACKUPS_SOFTFAIL_ERROR_RULE_SET,
requestLogger
))
.done((describeRequest, describeResponse, proxyInvocation, model, context) -> {
DBInstanceAutomatedBackup dbInstanceAutomatedBackup = describeResponse.dbInstanceAutomatedBackups().get(0);
model.setAutomaticBackupReplicationRetentionPeriod(dbInstanceAutomatedBackup.backupRetentionPeriod());
model.setAutomaticBackupReplicationRegion(replicationRegion);
model.setAutomaticBackupReplicationKmsKeyId(dbInstanceAutomatedBackup.kmsKeyId());
context.setAutomaticBackupReplicationStarted(true);
return ProgressEvent.progress(model, context);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static DescribeDbInstancesRequest describeDbInstanceByResourceIdRequest(f
.build();
}

public static DescribeDbInstanceAutomatedBackupsRequest describeDBInstanceAutomaticBackup(final String automaticBackupArn) {
public static DescribeDbInstanceAutomatedBackupsRequest describeDBInstanceAutomaticBackupRequest(final String automaticBackupArn) {
return DescribeDbInstanceAutomatedBackupsRequest.builder()
.dbInstanceAutomatedBackupsArn(automaticBackupArn)
.build();
Expand Down Expand Up @@ -777,10 +777,12 @@ public static DescribeDbEngineVersionsRequest describeDbEngineVersionsRequest(

public static StartDbInstanceAutomatedBackupsReplicationRequest startDbInstanceAutomatedBackupsReplicationRequest(
final String dbInstanceArn,
final Integer backupRetentionPeriod,
final String kmsKeyId
) {
return StartDbInstanceAutomatedBackupsReplicationRequest.builder()
.sourceDBInstanceArn(dbInstanceArn)
.backupRetentionPeriod(backupRetentionPeriod)
.kmsKeyId(kmsKeyId)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
import software.amazon.rds.common.handler.Events;
import software.amazon.rds.common.handler.HandlerConfig;
import software.amazon.rds.common.handler.Tagging;
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.ApiVersion;
import software.amazon.rds.dbinstance.client.VersionedProxyClient;
import software.amazon.rds.dbinstance.status.DBInstanceStatus;
import software.amazon.rds.dbinstance.status.DBParameterGroupStatus;
import software.amazon.rds.dbinstance.util.ImmutabilityHelper;
import software.amazon.rds.dbinstance.util.ResourceModelHelper;
import software.amazon.rds.dbinstance.validators.AutomaticBackupReplicationValidator;
import software.amazon.rds.dbinstance.validators.OracleCustomSystemId;

import java.time.Instant;
import java.util.Collection;
Expand All @@ -42,6 +46,13 @@ public UpdateHandler(final HandlerConfig config) {

final String handlerOperation = "UPDATE";

@Override
protected void validateRequest(final ResourceHandlerRequest<ResourceModel> request) throws RequestValidationException {
super.validateRequest(request);

AutomaticBackupReplicationValidator.validateRequest(request.getDesiredResourceState());
}

protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(
final AmazonWebServicesClientProxy proxy,
final ValidatedRequest<ResourceModel> request,
Expand Down Expand Up @@ -184,28 +195,32 @@ protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(
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 -> {
if (ResourceModelHelper.shouldStopAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) {
return Commons.execOnce(progress, () -> stopAutomaticBackupReplicationInRegion(
callbackContext.getDbInstanceArn(),
proxy,
progress,
rdsProxyClient.defaultClient(),
ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getPreviousResourceState())),
CallbackContext::isAutomaticBackupReplicationStopped, CallbackContext::setAutomaticBackupReplicationStopped);
}
return progress;
})
.then(progress -> {
if (ResourceModelHelper.shouldStartAutomaticBackupReplication(request.getPreviousResourceState(), request.getDesiredResourceState())) {
return Commons.execOnce(progress, () -> startAutomaticBackupReplicationInRegion(
callbackContext.getDbInstanceArn(),
ResourceModelHelper.getAutomaticBackupReplicationRetentionPeriod(request.getDesiredResourceState()),
ResourceModelHelper.getAutomaticBackupReplicationKmsKeyId(request.getDesiredResourceState()),
proxy,
progress,
rdsProxyClient.defaultClient(),
ResourceModelHelper.getAutomaticBackupReplicationRegion(request.getDesiredResourceState())),
CallbackContext::isAutomaticBackupReplicationStarted, CallbackContext::setAutomaticBackupReplicationStarted);
}
return progress;
})
.then(progress -> updateTags(proxy, rdsClient, progress, previousTags, desiredTags))
.then(progress -> {
final ResourceModel model = request.getDesiredResourceState();
Expand Down
Loading
Loading