
br.com.ingenieux.mojo.apigateway.CreateOrUpdateMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apigateway-maven-plugin Show documentation
Show all versions of apigateway-maven-plugin Show documentation
Beanstalker's support for AWS API Gateway
The newest version!
/*
* Copyright (c) 2016 ingenieux Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package br.com.ingenieux.mojo.apigateway;
import com.google.common.collect.Lists;
import com.amazonaws.services.apigateway.model.CreateDeploymentRequest;
import com.amazonaws.services.apigateway.model.CreateDeploymentResult;
import com.amazonaws.services.apigateway.model.CreateRestApiRequest;
import com.amazonaws.services.apigateway.model.CreateRestApiResult;
import com.amazonaws.services.apigateway.model.PutMode;
import com.amazonaws.services.apigateway.model.PutRestApiRequest;
import com.amazonaws.services.apigateway.model.PutRestApiResult;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.flipkart.zjsonpatch.JsonPatch;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrSubstitutor;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import br.com.ingenieux.mojo.apigateway.util.Unthrow;
import br.com.ingenieux.mojo.aws.util.RoleResolver;
import static java.lang.String.format;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang.StringUtils.defaultString;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Mojo(name = "create-or-update", requiresProject = true)
public class CreateOrUpdateMojo extends AbstractAPIGatewayMojo {
/**
* Regex to Find Parameter Keys (when importing)
*/
public static final Pattern KEY_PARAM_REGEX = Pattern.compile("^apigateway\\.param\\.(.+)$");
/**
* Regex to Find Stage Parameters
*/
public static final Pattern KEY_STAGE_VARIABLE_REGEX = Pattern.compile("^apigateway\\.stage\\.([^\\.]{3,}).(.+)$");
private static final String STR_TEMPLATE_LAMBDA_METHOD = loadResourceAsString("lambda-method.json");
private static final String STR_TEMPLATE_CORS_METHOD =
loadResourceAsString("cors-method.json");
private static String loadResourceAsString(String name) {
try {
return IOUtils.toString(CreateOrUpdateMojo.class.getClassLoader().getResource("templates/" + name));
} catch (Exception exc) {
throw new IllegalStateException("While loading template: " + name, exc);
}
}
private static final Pattern PATTERN_PARAMETER = Pattern.compile("\\{(\\w+)\\}");
/**
* Rest API Description
*/
@Parameter(property = "apigateway.restApiDescription", required = false, defaultValue = "API for ${project.artifactId}")
protected String restApiDescription;
/**
* Stage Name Description
*/
@Parameter(property = "apigateway.stageNameDescription", required = true, defaultValue = "${apigateway.stageName} stage")
protected String stageNameDescription;
/**
* Stage Deployment Description
*/
@Parameter(property = "apigateway.stageDeploymentDescription", required = true, defaultValue = "Updated by apigateway-maven-plugin")
protected String deploymentDescription;
/**
* Deployment File to Use (Swagger)
*/
@Parameter(
property = "apigateway.deploymentFile",
required = true,
defaultValue = "${project.build.outputDirectory}/META-INF/apigateway/apigateway-swagger.json"
)
protected File deploymentFile;
/**
* Deployment File to Use (Lambda)
*/
@Parameter(property = "apigateway.lambdasFile", defaultValue = "${project.build.outputDirectory}/META-INF/lambda-definitions.json")
protected File lambdasFile;
/**
* Cache Cluster Enabled (when creating a new stage)
*/
@Parameter(property = "apigateway.cacheClusterEnabled", defaultValue = "false")
protected Boolean cacheClusterEnabled;
/**
* Cache Cluster Size (when creating a new stage)
*/
@Parameter(property = "apigateway.cacheClusterSize")
protected String cacheClusterSize;
/**
* New Stage Definitions
*/
@Parameter(required = false)
protected Map> stageVariables = new LinkedHashMap<>();
/**
* Overwrite Definitions (otherwise, merge)
*/
@Parameter(property = "apigateway.overwriteDefinitions", required = true, defaultValue = "false")
protected Boolean overwriteDefinitions;
/**
* Overwrite Definitions (otherwise, merge)
*/
@Parameter(property = "apigateway.overwriteDefinitions", required = true, defaultValue = "false")
protected Boolean skipInterpolate;
/**
* Parameters
*/
@Parameter(property = "apigateway.parameters", required = false)
protected Map parameters = new HashMap<>();
/**
* Remove Conflicting Declarations? Disable for advanced usage
*/
@Parameter(property = "apigateway.removeConflicting", required = true, defaultValue = "true")
protected boolean removeConflicting;
/**
* Resulting Body to use
*/
protected String body;
private RoleResolver roleResolver;
private List lambdaDefinitions = Collections.emptyList();
private ObjectNode templateChildNode;
private ObjectNode templateOptionsNode;
private ObjectNode swaggerDefinition;
@Override
protected Object executeInternal() throws Exception {
this.roleResolver = new RoleResolver(createServiceFor(AmazonIdentityManagementClient.class));
initConstants();
initProperties();
loadLambdaDefinitions();
createOrUpdateRestApi();
loadAndInterpolateSwaggerFile();
importDefinitions();
cleanupPermissions();
CreateDeploymentResult result = deploy();
return result;
}
private void initConstants() throws Exception {
try {
this.templateChildNode = (ObjectNode) objectMapper.readTree(STR_TEMPLATE_LAMBDA_METHOD);
} catch (Exception exc) {
getLog().warn("While building template credentials node:", exc);
}
try {
this.templateChildNode.with("x-amazon-apigateway-integration").put("credentials", roleResolver.lookupRoleGlob("*/apigateway-lambda-invoker"));
} catch (Exception exc) {
getLog().warn("While building template credentials node:", exc);
}
try {
this.templateOptionsNode = (ObjectNode) objectMapper.readTree(STR_TEMPLATE_CORS_METHOD);
} catch (Exception exc) {
getLog().warn("While building template credentials node:", exc);
}
}
private CreateDeploymentResult deploy() {
/**
* Step #1: Doing the stage itself
*/
CreateDeploymentRequest req =
new CreateDeploymentRequest()
.withRestApiId(restApiId)
.withStageName(stageName)
.withDescription(deploymentDescription)
.withStageName(stageName)
.withStageDescription(stageNameDescription)
.withCacheClusterEnabled(cacheClusterEnabled)
.withCacheClusterSize(cacheClusterSize)
.withVariables(getStageVariables(stageName));
getLog().info("Creating Deployment Request: " + req);
CreateDeploymentResult result = getService().createDeployment(req);
getLog().info("Deployment Request Result: " + result);
return result;
}
private Map getStageVariables(String stageName) {
if (stageVariables.containsKey(stageName)) {
return stageVariables.get(stageName);
}
return Collections.emptyMap();
}
private void cleanupPermissions() {
}
private void initProperties() {
final Properties props = getProperties();
props
.entrySet()
.stream()
.map(e -> KEY_PARAM_REGEX.matcher(e.getKey() + ""))
.filter(m -> m.matches())
.forEach(
m -> {
String k = m.group(1);
String v = curProject.getProperties().getProperty(m.group(0), "");
if (isEmpty(v) && parameters.containsKey(k)) {
getLog().info("Removing parameter " + k);
parameters.remove(k);
} else {
getLog().info("Updating parameter " + k + ": " + v);
parameters.put(k, v);
}
});
props
.entrySet()
.stream()
.map(e -> KEY_STAGE_VARIABLE_REGEX.matcher(e.getKey() + ""))
.filter(m -> m.matches())
.forEach(
m -> {
String env = m.group(1);
String k = m.group(2);
String v = curProject.getProperties().getProperty(m.group(0), "");
Map stageVariablesForEnv = stageVariables.get(env);
if (null == stageVariablesForEnv) {
stageVariablesForEnv = new LinkedHashMap();
stageVariables.put(env, stageVariablesForEnv);
}
if (isEmpty(v) && stageVariablesForEnv.containsKey(k)) {
getLog().info("Removing stage variable " + k);
stageVariablesForEnv.remove(k);
} else {
getLog().info("Updating stage variable " + k + ": " + v);
stageVariablesForEnv.put(k, v);
}
});
if (props.containsKey("apigateway.restApiId")) {
restApiId = props.getProperty("apigateway.restApiId");
}
if (props.containsKey("apigateway.restApiName")) {
restApiName = props.getProperty("apigateway.restApiName");
}
// if (props.containsKey("apigateway.restApiHost")) {
// restApiHost = props.getProperty("apigateway.restApiHost");
// }
}
protected void loadLambdaDefinitions() throws Exception {
if (null != lambdasFile && lambdasFile.exists()) {
getLog().info("Loading lambdas from " + lambdasFile.getPath());
Map defs = objectMapper.readValue(lambdasFile, new TypeReference
© 2015 - 2025 Weber Informatics LLC | Privacy Policy