List of usage examples for com.amazonaws.services.apigateway AmazonApiGatewayClientBuilder standard
public static AmazonApiGatewayClientBuilder standard()
From source file:squash.deployment.lambdas.ApiGatewayCustomResourceLambda.java
License:Apache License
/** * Implementation for the AWS Lambda function backing the ApiGateway resource. * //from w w w .j a va2 s . com * <p>This lambda requires the following environment variables: * * <p>Keys suppling arn of other AWS lambda functions that the Api invokes: * <ul> * <li>ValidDatesGETLambdaURI</li> * <li>BookingsGETLambdaURI</li> * <li>BookingRulesGETLambdaURI</li> * <li>BookingsPUTDELETELambdaURI</li> * <li>BookingRuleOrExclusionPUTDELETELambdaURI</li> * </ul> * * <p>Other keys: * <ul> * <li>BookingsApiGatewayInvocationRole - role allowing Api to invoke these three lambda functions.</li> * <li>WebsiteBucket - name of S3 bucket serving the booking website.</li> * <li>StageName - the name to give to the Api's stage.</li> * <li>Region - the AWS region in which the Cloudformation stack is created.</li> * <li>Revision - integer incremented to force stack updates to update this resource.</li> * </ul> * * <p>On success, it returns the following output to Cloudformation: * <ul> * <li>ApiGatewayBaseUrl - base Url of the created ApiGateway Api.</li> * </ul> * * @param request request parameters as provided by the CloudFormation service * @param context context as provided by the CloudFormation service */ @Override public Object handleRequest(Map<String, Object> request, Context context) { LambdaLogger logger = context.getLogger(); logger.log("Starting ApiGateway custom resource handleRequest"); // Handle standard request parameters Map<String, String> standardRequestParameters = LambdaInputLogger.logStandardRequestParameters(request, logger); String requestType = standardRequestParameters.get("RequestType"); // Handle required environment variables logger.log("Logging required environment variables for custom resource request"); String region = System.getenv("AWS_REGION"); String revision = System.getenv("Revision"); String validDatesGETLambdaURI = wrapURI((System.getenv("ValidDatesGETLambdaURI")), region); String bookingsGETLambdaURI = wrapURI((System.getenv("BookingsGETLambdaURI")), region); String bookingRulesGETLambdaURI = wrapURI((System.getenv("BookingRulesGETLambdaURI")), region); String bookingsPUTDELETELambdaURI = wrapURI((System.getenv("BookingsPUTDELETELambdaURI")), region); String bookingRuleOrExclusionPUTDELETELambdaURI = wrapURI( System.getenv("BookingRuleOrExclusionPUTDELETELambdaURI"), region); String bookingsApiGatewayInvocationRole = System.getenv("BookingsApiGatewayInvocationRole"); squashWebsiteBucket = System.getenv("WebsiteBucket"); String stageName = System.getenv("StageName"); // Log out our required environment variables logger.log("Logging custom parameters to ApiGateway custom resource request:"); logger.log("ValidDatesGETLambdaURI: " + validDatesGETLambdaURI); logger.log("BookingsGETLambdaURI: " + bookingsGETLambdaURI); logger.log("BookingRulesGETLambdaURI: " + bookingRulesGETLambdaURI); logger.log("BookingsPUTDELETELambdaURI: " + bookingsPUTDELETELambdaURI); logger.log("BookingRuleOrExclusionPUTDELETELambdaURI: " + bookingRuleOrExclusionPUTDELETELambdaURI); logger.log("BookingsApiGatewayInvocationRole: " + bookingsApiGatewayInvocationRole); logger.log("Squash website bucket: " + squashWebsiteBucket); logger.log("StageName: " + stageName); logger.log("Region: " + region); logger.log("Revision: " + revision); // API calls below can sometimes give access denied errors during stack // creation which I think is bc required new roles have not yet propagated // across AWS. We sleep here to allow time for this propagation. try { Thread.sleep(10000); } catch (InterruptedException e) { logger.log("Sleep to allow new roles to propagate has been interrupted."); } // Prepare our response to be sent in the finally block CloudFormationResponder cloudFormationResponder = new CloudFormationResponder(standardRequestParameters, "DummyPhysicalResourceId"); // Initialise failure response, which will be changed on success String responseStatus = "FAILED"; String apiGatewayBaseUrl = null; try { cloudFormationResponder.initialise(); // Create ApiGateway client AmazonApiGateway apiGatewayClient = AmazonApiGatewayClientBuilder.standard().withRegion(region).build(); String apiName = "SquashApi" + standardRequestParameters.get("StackId"); logger.log("Setting api name to: " + apiName); if (requestType.equals("Create")) { // Ensure an API of the same name does not already exist - can happen // e.g. if wrongly put two of these custom resources in the stack // template. logger.log("Verifying an api with name: " + apiName + " does not already exist."); GetRestApisRequest getRestApisRequest = new GetRestApisRequest(); GetRestApisResult apis = apiGatewayClient.getRestApis(getRestApisRequest); List<RestApi> apiList = apis.getItems(); Boolean apiExists = apiList.stream().filter(api -> api.getName().equals(apiName)).findFirst() .isPresent(); if (apiExists) { logger.log(apiName + " exists already - creating another api with this name is not allowed"); // Change physical id in responder - this is bc CloudFormation will // follow up this failed creation with a Delete request to clean up // - and we want to ignore that delete call - but not delete calls // for our original resource - and we use the PhysicalId to tell these // two cases apart. cloudFormationResponder.setPhysicalResourceId("DuplicatePhysicalResourceId"); return null; } // Api does not already exist - so create it logger.log("Creating API"); CreateRestApiRequest createRestApiRequest = new CreateRestApiRequest(); createRestApiRequest.setName(apiName); createRestApiRequest.setDescription("Api for managing squash court bookings"); CreateRestApiResult createRestApiResult = apiGatewayClient.createRestApi(createRestApiRequest); String restApiId = createRestApiResult.getId(); cloudFormationResponder.setPhysicalResourceId(restApiId); // Add all resources and methods to the Api, then upload its SDK to S3. constructApiAndUploadSdk(restApiId, apiGatewayClient, region, validDatesGETLambdaURI, bookingsGETLambdaURI, bookingsPUTDELETELambdaURI, bookingRulesGETLambdaURI, bookingRuleOrExclusionPUTDELETELambdaURI, bookingsApiGatewayInvocationRole, stageName, logger); apiGatewayBaseUrl = getApiGatewayBaseUrl(restApiId, region, stageName); logger.log("Created API with base url: " + apiGatewayBaseUrl); } else if (requestType.equals("Update")) { // We update an Api by removing all existing resources from it and then // adding them back, whilst retaining the original ApiId. This ensures // that its deployment creates a new entry in the deployment history of // the Api - i.e. it mimics editing and re-deploying the api in the // console. String restApiId = standardRequestParameters.get("PhysicalResourceId"); // Keep same physical id - otherwise CloudFormation thinks it needs to // follow up with a Delete request on the 'previous' physical resource. cloudFormationResponder.setPhysicalResourceId(restApiId); logger.log("Updating Api for apiId: " + restApiId); // Remove all existing resources (except the root) from this Api logger.log("Removing existing resources from Api with apiId: " + restApiId); GetResourcesRequest getResourcesRequest = new GetResourcesRequest(); getResourcesRequest.setRestApiId(restApiId); GetResourcesResult getResourcesResult = apiGatewayClient.getResources(getResourcesRequest); getResourcesResult.getItems().stream().filter(r -> !r.getPath().equals("/")).forEach(resource -> { logger.log("About to delete resource: " + resource.getPath()); DeleteResourceRequest deleteResourceRequest = new DeleteResourceRequest(); deleteResourceRequest.setRestApiId(restApiId); deleteResourceRequest.setResourceId(resource.getId()); apiGatewayClient.deleteResource(deleteResourceRequest); logger.log("Successfully deleted resource: " + resource.getPath()); }); // Remove the existing SDK from the S3 website bucket removeSdkFromS3(logger); // And add back the updated set of resources and SDK logger.log("Adding back updated resources to Api with apiId: " + restApiId); constructApiAndUploadSdk(restApiId, apiGatewayClient, region, validDatesGETLambdaURI, bookingsGETLambdaURI, bookingsPUTDELETELambdaURI, bookingRulesGETLambdaURI, bookingRuleOrExclusionPUTDELETELambdaURI, bookingsApiGatewayInvocationRole, stageName, logger); apiGatewayBaseUrl = getApiGatewayBaseUrl(restApiId, region, stageName); logger.log("Updated API with base url: " + apiGatewayBaseUrl); } else if (requestType.equals("Delete")) { String restApiId = standardRequestParameters.get("PhysicalResourceId"); logger.log("Deleting Api for apiId: " + restApiId); // Early-out if this is a Delete corresponding to a failed attempt to // create a duplicate API, otherwise we will end up wrongly deleting // our (valid) original API instead. if (restApiId.equals("DuplicatePhysicalResourceId")) { logger.log("Ignoring delete request as it's for a non-existent duplicate API"); } else { // Delete the API GetRestApiRequest getRestApiRequest = new GetRestApiRequest(); getRestApiRequest.setRestApiId(restApiId); // This will throw if the api does not exist GetRestApiResult api = apiGatewayClient.getRestApi(getRestApiRequest); DeleteRestApiRequest deleteRestApiRequest = new DeleteRestApiRequest(); deleteRestApiRequest.setRestApiId(api.getId()); apiGatewayClient.deleteRestApi(deleteRestApiRequest); // Remove the sdk from the website bucket removeSdkFromS3(logger); } } responseStatus = "SUCCESS"; return null; } catch (AmazonServiceException ase) { ExceptionUtils.logAmazonServiceException(ase, logger); return null; } catch (AmazonClientException ace) { ExceptionUtils.logAmazonClientException(ace, logger); return null; } catch (Exception e) { logger.log("Exception caught in ApiGateway Lambda: " + e.getMessage()); return null; } finally { cloudFormationResponder.addKeyValueOutputsPair("ApiGatewayBaseUrl", apiGatewayBaseUrl); cloudFormationResponder.sendResponse(responseStatus, logger); } }