package software.amazon.rds.dbproxytargetgroup; import java.util.ArrayList; import java.util.List; import java.util.Optional; import com.amazonaws.services.rds.AmazonRDS; import com.amazonaws.services.rds.AmazonRDSClientBuilder; import com.amazonaws.services.rds.model.DBProxyNotFoundException; import com.amazonaws.services.rds.model.DBProxyTarget; import com.amazonaws.services.rds.model.DeregisterDBProxyTargetsRequest; import com.amazonaws.services.rds.model.DescribeDBProxyTargetsRequest; import com.amazonaws.services.rds.model.DescribeDBProxyTargetsResult; import com.amazonaws.services.rds.model.InvalidDBProxyStateException; import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; import software.amazon.cloudformation.proxy.Logger; import software.amazon.cloudformation.proxy.OperationStatus; import software.amazon.cloudformation.proxy.ProgressEvent; import software.amazon.cloudformation.proxy.ResourceHandlerRequest; public class DeleteHandler extends BaseHandler { private AmazonWebServicesClientProxy clientProxy; private AmazonRDS rdsClient; private Logger logger; @Override public ProgressEvent handleRequest( final AmazonWebServicesClientProxy proxy, final ResourceHandlerRequest request, final CallbackContext callbackContext, final Logger logger) { final ResourceModel model = request.getDesiredResourceState(); clientProxy = proxy; rdsClient = AmazonRDSClientBuilder.defaultClient(); this.logger = logger; final CallbackContext currentContext = Optional.ofNullable(callbackContext) .orElse(CallbackContext.builder() .stabilizationRetriesRemaining(Constants.NUMBER_OF_STATE_POLL_RETRIES) .build()); // This Lambda will continually be re-invoked with the current state of the proxy, finally succeeding when deleted. return deleteProxyTargetGroup(model, currentContext); } private ProgressEvent deleteProxyTargetGroup(ResourceModel model, CallbackContext callbackContext) { if (!callbackContext.isTargetsDeregistered()) { boolean deregistered = deregisterOldTargetsHelper(model); return ProgressEvent.builder() .resourceModel(model) .status(OperationStatus.IN_PROGRESS) .callbackContext(CallbackContext.builder() .targetsDeregistered(deregistered) .stabilizationRetriesRemaining(Constants.NUMBER_OF_STATE_POLL_RETRIES) .build()) .build(); } return ProgressEvent.builder() .status(OperationStatus.SUCCESS) .build(); } private boolean deregisterOldTargetsHelper(ResourceModel model) { try { return deregisterOldTargets(model); } catch (DBProxyNotFoundException e) { // Proxy is already deleted, no need to deregister return true; } catch (InvalidDBProxyStateException e) { if (e.getMessage().contains("DELETING")) { // Proxy is deleting, no need to deregister return true; } throw e; } } private boolean deregisterOldTargets(ResourceModel model) { String proxyName = model.getDBProxyName(); String targetGroupName = Optional.ofNullable(model.getTargetGroupName()).orElse("default"); DescribeDBProxyTargetsRequest describeDBProxyTargetsRequest = new DescribeDBProxyTargetsRequest() .withDBProxyName(proxyName) .withTargetGroupName(targetGroupName); DescribeDBProxyTargetsResult describeResult = clientProxy.injectCredentialsAndInvoke(describeDBProxyTargetsRequest, rdsClient::describeDBProxyTargets); List dbClusters = new ArrayList<>(); List dbInstances = new ArrayList<>(); for (DBProxyTarget target: describeResult.getTargets()) { if (target.getType().equals("TRACKED_CLUSTER")) { dbClusters.add(target.getRdsResourceId()); } else { dbInstances.add(target.getRdsResourceId()); } } if (dbClusters.size() > 0) { DeregisterDBProxyTargetsRequest deregisterRequest = new DeregisterDBProxyTargetsRequest() .withDBProxyName(model.getDBProxyName()) .withDBClusterIdentifiers(dbClusters); clientProxy.injectCredentialsAndInvoke(deregisterRequest, rdsClient::deregisterDBProxyTargets); } else if (dbInstances.size() > 0){ DeregisterDBProxyTargetsRequest deregisterRequest = new DeregisterDBProxyTargetsRequest() .withDBProxyName(model.getDBProxyName()) .withDBInstanceIdentifiers(dbInstances); clientProxy.injectCredentialsAndInvoke(deregisterRequest, rdsClient::deregisterDBProxyTargets); } return true; } }