package software.amazon.rds.dbproxy; import com.amazonaws.services.rds.AmazonRDS; import com.amazonaws.services.rds.AmazonRDSClientBuilder; import com.amazonaws.services.rds.model.DBProxy; import com.amazonaws.services.rds.model.DBProxyNotFoundException; import com.amazonaws.services.rds.model.DeleteDBProxyRequest; import com.amazonaws.services.rds.model.DeleteDBProxyResult; import com.amazonaws.services.rds.model.DescribeDBProxiesRequest; import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy; import software.amazon.cloudformation.proxy.HandlerErrorCode; 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 static final String TIMED_OUT_MESSAGE = "Timed out waiting for proxy to terminate."; private AmazonWebServicesClientProxy clientProxy; private AmazonRDS rdsClient; @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(); final CallbackContext currentContext = callbackContext == null ? CallbackContext.builder().stabilizationRetriesRemaining(Constants.NUMBER_OF_STATE_POLL_RETRIES).build() : callbackContext; // This Lambda will continually be re-invoked with the current state of the proxy, finally succeeding when deleted. return deleteProxyAndUpdateProgress(model, currentContext); } private ProgressEvent deleteProxyAndUpdateProgress(ResourceModel model, CallbackContext callbackContext) { if (callbackContext.getStabilizationRetriesRemaining() == 0) { throw new RuntimeException(TIMED_OUT_MESSAGE); } if (callbackContext.getProxy() == null) { try { return ProgressEvent.builder() .resourceModel(model) .status(OperationStatus.IN_PROGRESS) .callbackContext(CallbackContext.builder() .proxy(deleteProxy(model.getDBProxyName())) .stabilizationRetriesRemaining(Constants.NUMBER_OF_STATE_POLL_RETRIES) .build()) .build(); } catch (DBProxyNotFoundException e) { return ProgressEvent.defaultFailureHandler(e, HandlerErrorCode.NotFound); } } else if (callbackContext.isDeleted()) { return ProgressEvent.builder() .status(OperationStatus.SUCCESS) .build(); } else { try { Thread.sleep(Constants.POLL_RETRY_DELAY_IN_MS); } catch (InterruptedException e) { throw new RuntimeException(e); } return ProgressEvent.builder() .resourceModel(model) .status(OperationStatus.IN_PROGRESS) .callbackContext(CallbackContext.builder() .proxy(callbackContext.getProxy()) .deleted(!doesProxyExist(model.getDBProxyName())) .stabilizationRetriesRemaining(callbackContext.getStabilizationRetriesRemaining() - 1) .build()) .build(); } } private DBProxy deleteProxy(String proxyName) { DeleteDBProxyRequest request = new DeleteDBProxyRequest().withDBProxyName(proxyName); DeleteDBProxyResult result = clientProxy.injectCredentialsAndInvoke(request, rdsClient::deleteDBProxy); return result.getDBProxy(); } private boolean doesProxyExist(String proxyName) { DescribeDBProxiesRequest describeDBProxiesRequest; describeDBProxiesRequest = new DescribeDBProxiesRequest().withDBProxyName(proxyName); try { clientProxy.injectCredentialsAndInvoke(describeDBProxiesRequest, rdsClient::describeDBProxies); return true; } catch (DBProxyNotFoundException e) { return false; } } }