diff --git a/.travis.yml b/.travis.yml index 1c347df..893f6d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ cache: - "$HOME/.m2" after_success: # run the integration test for Pull requests -- test "${TRAVIS_PULL_REQUEST}" != "false" && echo ${TRAVIS_PULL_REQUEST} && ./gradlew integrationTest --info +- test "${TRAVIS_PULL_REQUEST}" != "false" && ./gradlew integrationTest --info # run the integration test and release for tagged releases - test "${TRAVIS_PULL_REQUEST}" == "false" && test "${TRAVIS_TAG}" != "" && ./gradlew integrationTest publishPlugins --stacktrace --info @@ -18,3 +18,4 @@ env: - secure: egvlxzyYuAWEtb7tp+Gdsw/pSlC+UX0X9MSXAfD4jCSaC8B5rMfc+x5aJjLrn+nqWb291xYO/zs47cYbT1wrgG/nP7r1yV6sENYFZ+x0KUDa828QB40c9o3YeTOlemT+lX6AsWa3nvbWx1R6qgExJaEyce87+QYAqDkbeHP1bX5Dif3VmpvePvePZPsJnR/jLPwsseXzFQBMpyM+6RcX60lAFry/QUmtNp8asznMiO6GgWqNlJToHUshTC/3lI20FwG+6fxop1F+m+QfqABSy7r251r0tOsdPPAL03MlmItI2DNxgR0M4aQAL9WthGXdbJRAb/xAJoXcDh9Q1YYvvEf5DvTtP91oWTLpLM+hiU02bS5WVctfVOiGGtX9AAlhSNyG0jea3OAbwcXmode+dDjHAhPkHQjVOnn7j84WGrbJQpm9mggjxN17yx9f1ACaW3vCpejtSHt1MmQMeb6uIeW2KVvqoTb/YJ+surSODguN9hEDYA0Jr6eOV+ItJfam0P4iNtyEWpc0ct9lTB/UlD520Ol7lRGL7LkbMJbxirIZPX9Ouu2urBVZkBGYfXj63+4u6G4SaeHTXtUC20+MoxIDDlrpAKMGa3nFuz4uoGwkVCumbVYuzIrPRiv9PdkqYOIDEVeVd3hxeCdBYQABB1XkOEI/WC6hKoWFOsgSlww= - secure: oztD48eGvlrRCOfM9prUmZ19jmrIjFWGFD6Q01bZFtroBae+NMrVTv/5GuY+nbIx1L7azGp9up7MBlXAdHPBvFolAbuM0qLYWuco4NOv/QBk08nPGjqzwmVWmmaxbvHOW8EBXgbf2hLI3tbi3ddoTbnXdgjaCgOmt3Ig7P2VSqh1ANgQBvQW8vWbbmbn/QXViWNerOmRn3At5WZ0wvWqwcs8ALFonYh+XqR4XArMf8rCG/aujIBkSpQ53sbEqc5FOcor1atKhGQ1dQ0dikT5wafTRaXUm1RCY1JERuU2kUqIPVJPo0RfILN+qYDWC6viiTCRZe/ggdBdBeW63adCjjL+spZ8YXFKia7MjL0sxrEJG+FbopJd+LdXbJUjGZgtXzMKt9IJuorszMbfntavFdY4OLmUQbgb575IKaReBrxJQbFxyQSr37VXhZrmHbtCHZfdqu3ZkLggWunydFGMaH9zlV1apIoJJ5hPbAwk/z7RfXzxbW9gI+Uo5MfK8kFDqp+irG5GEUGuyb/h6WTS/lDBAp63AMYmEIX98wv62e3oxtDaS8c3xojlxSOPpvUhSSQDi8MlP1dRkvputX9XjsOYccVDIUF7gIlxuseio3RB2NJ6GddrZGEhdnCdTTOiMTXE5kkw0JpA4tar32shuFWdC+o6m3f8gi/aQWbD3wU= - secure: BI30ckfS4zvDfLo9oXfPupZqrfzJqnnOOCYZ7+5qkxyUleuWs39yTkFT7t9vhCOO0Lk0o6nTFoVcpdLXTe16uRENEq5xGPJxaWaiL4lZhUKMPrD4NffEgaTLUEHMCFzUXa3Z3JckyADzDpG6QoVF2NlAk+VONOXZZUMtTzyvzDzGj9MHOBpMmuhqXasbJRu9jsdQaPHRZ9FxlK4z2UJODkF5YQGuHvYiCQqdi+BDii5wQ+bchaaILljfLoeBF35m5yxXXPQmzMg+Nt6/3S5dQyscw5su8aNEbF5sN8oWzBcvE/fas48PM3ohRZ6csZTPuLGhfl/f279BaVShT7fN21UzAGRGSD5kAZNGeVtKLJr+cao6gV/05Kgy6naQlhmqmR3KiSmrC0HUlB0uMALQKeBi4PjJ8ortsTdzQvYPayg/4NmIA9L+MvRIKr2icGY4SmOK0IdoOvIPNJqV5DcHvl2zl4XXMCRKXzixh1DZG8gR2m5AnimCWMmi1guBGQsj1fBJin5K3nsYICe93dO4vvjCg2go1cjOoNZVleYcc9fjQhXffoT55ZEt71lfemHKE1SkYxSzrpzGZtWMd7EPvKf+dXYY3gzNFG9IHjs15zifLRObdqlITPTExDP5d8jAD7R2jvHNc5NArV20SYWrzwgHCcBiyPVSPN2HIT7/tsc= + - secure: QBX+A8JlKEu+bQBwimHWytT2LJhvqx5BVNMYtnEEKf59Cr1jXItbczvajQSIwyLWBrUf3KtAlNRPTfWynIDwSdJ/6zccc2EvI2tKJvFi4hJNRDj23SEZYO6Zwj6coBg+bQUkksiOr02X2G9Hk1AhUquZ1WY5Lg7aHtjvXP4xFKkp5Rt/+4LC+hQkpnG2+I90flV6YR60jW2B6GsSOkDFxukcbnlPmdGWEQUPii3PulpSZaIKyUyhmohXo/iHgRtArUc1Lwpybmo6tPRLsx4m/2VVFGY8A31Zmj7aGbGt8//XqkhCz0Ncv3ewg5mMVVWrnFE0cVaOYXpETRp+fQGOuFOVSaHUIskq3PW/BrFTMmfcq4jVZS8+gkH6dD2CSARuESRe5V/fYdi727Ybea9h1J01qBefcouEJiTLw8OG8SOl475LQ1clsMoa+He+ATNLkW9Qpb4deOJ7F3LHS+TqHaVAETD/v/uPuMowXLYam65MHOvsjImWPgg+dYQdTGiaQbFTQhiGo3Tf0ifqrg0kebGAYpbLtV1rTld0V4I30CHpIsXGjwTcq+mFzaN+Fpw4hOqbQOQjPXdFy3xkdt+XPjf/wFgisdczHd/bB4kNhCvLfZEQ4mq1v50wQGl95LosponRY/oAh3i/tN+ZWQhpLeGefXfmj27mkydmOX2lges= diff --git a/gradle.properties b/gradle.properties index 3562b60..72b8001 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ group=com.fieldju artifactId=gradle-aws-sam-deployer-plugin -version=1.5.0 +version=1.5.1 diff --git a/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/DeploySamTaskIntegrationTest.groovy b/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/DeploySamTaskIntegrationTest.groovy index da206c2..5643913 100644 --- a/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/DeploySamTaskIntegrationTest.groovy +++ b/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/DeploySamTaskIntegrationTest.groovy @@ -10,6 +10,7 @@ import com.amazonaws.services.s3.AmazonS3Client import com.amazonaws.services.s3.model.DeleteObjectsRequest import com.amazonaws.waiters.Waiter import com.amazonaws.waiters.WaiterParameters +import com.fieldju.commons.EnvUtils import com.fieldju.gradle.plugins.lambdasam.AwsSamDeployerPlugin import groovy.util.logging.Slf4j import org.gradle.api.Project @@ -47,7 +48,7 @@ class DeploySamTaskIntegrationTest { s3 = AmazonS3Client.builder().standard().withRegion(regionString).build() prefix = "gradle-aws-sam-deployer-plugin-integration-test/${UUID.randomUUID().toString()}" - bucket = getRequiredTestParam('S3_BUCKET', 'The s3 bucket to upload the lambda fat jar') + bucket = EnvUtils.getRequiredEnv('S3_BUCKET', 'The us-west-2 s3 bucket to upload the lambda fat jar') log.info("Integration Test stack name: ${testStackName}") } @@ -118,13 +119,4 @@ class DeploySamTaskIntegrationTest { fail("Failed to assert that the stack: ${testStackName} was successfully created, msg: ${e.errorMessage}") } } - - static String getRequiredTestParam(String key, String msg) { - def value = System.getenv(key) - if (value == null || value.trim() == "") { - throw new RuntimeException("The environment variable: ${key} is required. Msg: ${msg}") - } - return value - } - } diff --git a/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTaskIntegrationTest.groovy b/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTaskIntegrationTest.groovy new file mode 100644 index 0000000..716a014 --- /dev/null +++ b/src/integration-test/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTaskIntegrationTest.groovy @@ -0,0 +1,127 @@ +package com.fieldju.gradle.plugins.lambdasam.tasks + +import com.amazonaws.services.cloudformation.AmazonCloudFormation +import com.amazonaws.services.cloudformation.AmazonCloudFormationClient +import com.amazonaws.services.cloudformation.model.AmazonCloudFormationException +import com.amazonaws.services.cloudformation.model.DeleteStackRequest +import com.amazonaws.services.cloudformation.model.DescribeStacksRequest +import com.amazonaws.services.s3.AmazonS3 +import com.amazonaws.services.s3.AmazonS3Client +import com.amazonaws.services.s3.model.DeleteObjectsRequest +import com.amazonaws.waiters.Waiter +import com.amazonaws.waiters.WaiterParameters +import com.fieldju.commons.EnvUtils +import com.fieldju.gradle.plugins.lambdasam.AwsSamDeployerPlugin +import groovy.util.logging.Slf4j +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.After +import org.junit.Before +import org.junit.Test + +import java.nio.file.Files +import java.nio.file.Paths + +import static org.junit.Assert.assertEquals +import static org.junit.Assert.fail + +@Slf4j +class MultiRegionPackageAndDeploySamTaskIntegrationTest { + final static def regions = ['us-west-2','us-east-1'] + Map regionS3Map = [:] + Map regionAmazonCloudFormationMap = [:] + Map regionS3BucketMap + String testStackName + String prefix + + @Before + void before() { + testStackName = "MultiRegionPackageAndDeploySamTaskIntegrationTest-${UUID.randomUUID()}" + regionS3BucketMap = [ + 'us-west-2': EnvUtils.getRequiredEnv('S3_BUCKET', 'The us-west-2 s3 bucket to upload the lambda fat jar'), + 'us-east-1': EnvUtils.getRequiredEnv('S3_BUCKET_EAST', 'The us-east-2 s3 bucket to upload the lambda fat jar') + ] + + regions.each { regionString -> + regionAmazonCloudFormationMap.put(regionString, AmazonCloudFormationClient.builder() + .standard() + .withRegion(regionString) + .build() as AmazonCloudFormationClient) + regionS3Map.put(regionString, AmazonS3Client.builder().standard().withRegion(regionString).build()) + } + + prefix = "gradle-aws-sam-deployer-plugin-integration-test/${UUID.randomUUID().toString()}" + log.info("Integration Test stack name: ${testStackName}") + } + + @After + void after() { + log.info("Deleting Test CloudFormation Stacks") + + regions.each { region -> + def cloudFormation = regionAmazonCloudFormationMap.get(region) + def s3 = regionS3Map.get(region) + def bucket = regionS3BucketMap.get(region) + try { + cloudFormation.deleteStack(new DeleteStackRequest().withStackName(testStackName)) + Waiter waiter = cloudFormation.waiters().stackDeleteComplete() + waiter.run(new WaiterParameters(new DescribeStacksRequest().withStackName(testStackName))) + log.info("Successfully deleted Test CloudFormation Stack ${testStackName} in region ${region}") + + List keys = s3.listObjectsV2(bucket, prefix).getObjectSummaries().collect { it.key } + keys.each { key -> + log.info("Deleting test key: ${key}") + s3.deleteObjects(new DeleteObjectsRequest(bucket).withKeys(key)) + } + } catch (Throwable t) { + log.error("Failed to delete stack: ${testStackName} in region: ${region}, please ensure it gets cleaned up manually", t) + } + } + } + + @Test + void "test that the package and deploy sam tasks can deploy hello word lambda function"() { + File temp = File.createTempDir() + + def samTemplateSource = Paths.get(getClass().getClassLoader().getResource('application.yaml').toURI()) + def samTemplateDest = Paths.get("${temp.absolutePath}${File.separator}application.yaml") + def fatJarSource = Paths.get(getClass().getClassLoader().getResource('jvm-hello-world-lambda.jar').toURI()) + def fatJarDest = Paths.get("${temp.absolutePath}${File.separator}jvm-hello-world-lambda.jar") + + Files.copy(samTemplateSource, samTemplateDest) + Files.copy(fatJarSource, fatJarDest) + + Project project = ProjectBuilder.builder().withName('DeploySamTaskIntegrationTest').withProjectDir(temp).build() + AwsSamDeployerPlugin plugin = new AwsSamDeployerPlugin() + plugin.apply(project) + + MultiRegionPackageAndDeploySamTask task = project.task('testTask', type: MultiRegionPackageAndDeploySamTask) as MultiRegionPackageAndDeploySamTask + task.regions = regions + task.stackName = testStackName + task.templatePath = "${temp.absolutePath}${File.separator}application.yaml" + task.regionToS3BucketMap = regionS3BucketMap + task.s3Prefix = prefix + task.forceUploads = true + task.tokenArtifactMap = [ + '@@LAMBDA_FAT_JAR@@': "${temp.absolutePath}${File.separator}jvm-hello-world-lambda.jar" + ] + task.parameterOverrides = [ + Foo: 'bar' + ] + + MultiRegionPackageAndDeploySamTask testTask = project.tasks.getByName('testTask') as MultiRegionPackageAndDeploySamTask + testTask.taskAction() + + regions.each { region -> + try { + def res = regionAmazonCloudFormationMap.get(region).describeStacks(new DescribeStacksRequest().withStackName(testStackName)) + assertEquals("There should be one and only one stack with the name: ${testStackName}", 1, res.stacks.size()) + assertEquals("There should be one and only one parameter", 1, res.stacks.get(0).parameters.size()) + assertEquals("The param Foo should be bar", "bar", res.stacks.get(0).parameters.get(0).getParameterValue()) + } catch (AmazonCloudFormationException e) { + log.error("Failed trying to describe stack: ${testStackName}", e) + fail("Failed to assert that the stack: ${testStackName} was successfully created, msg: ${e.errorMessage}") + } + } + } +} diff --git a/src/main/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTask.groovy b/src/main/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTask.groovy index 5e4fb08..65cf28d 100644 --- a/src/main/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTask.groovy +++ b/src/main/groovy/com/fieldju/gradle/plugins/lambdasam/tasks/MultiRegionPackageAndDeploySamTask.groovy @@ -52,14 +52,19 @@ class MultiRegionPackageAndDeploySamTask extends DefaultTask { regions.each { String region -> logger.lifecycle("---- Processing region: ${region} ----") - String s3Bucket = regionToS3BucketMap."${region}" - String kmsKeyId = regionToKmsKeyIdMap."${region}" + String s3Bucket + if (regionToS3BucketMap.containsKey(region)) { + s3Bucket = regionToS3BucketMap.get(region) + } else { + throw new Exception("There was no s3 bucket defined for region: ${region} in regionToS3BucketMap: ${regionToS3BucketMap}") + } + String kmsKeyId = regionToKmsKeyIdMap.get(region) def processedTemplatePath = helper.uploadArtifactsAndInjectS3UrlsIntoCopiedCFTemplate(region, s3Bucket, s3Prefix, kmsKeyId, forceUploads, templatePath, tokenArtifactMap, project, ant) Map calculatedParameterOverrides = [:] - if (parameterOverrides.isEmpty()) { + if (! parameterOverrides.isEmpty()) { calculatedParameterOverrides = parameterOverrides } else if (regionToParameterOverridesMap.containsKey(region)) { calculatedParameterOverrides = regionToParameterOverridesMap."${region}"