Skip to content

Commit

Permalink
Merge pull request #9 from MonsantoCo/master
Browse files Browse the repository at this point in the history
Add ability to specify multiple lambda handlers per project.
  • Loading branch information
fiadliel committed Nov 15, 2015
2 parents 80ce762 + 5582016 commit 1f45db2
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 45 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,38 @@ sbt-aws-lambda can be configured using sbt settings, environment variables or by
| region | AWS_REGION | The name of the AWS region to connect to. Defaults to `us-east-1` |
| awsLambdaTimeout | | The Lambda timeout in seconds (1-300). Defaults to AWS default. |
| awsLambdaMemory | | The amount of memory in MB for the Lambda function (128-1536, multiple of 64). Defaults to AWS default. |
| lambdaHandlers | | Sequence of Lambda names to handler functions (for multiple lambda methods per project). Overrides `lambdaName` and `handlerName` if present. |

An example configuration might look like this:


```scala
retrieveManaged := true

enablePlugins(AwsLambdaPlugin)

lambdaHandlers := Seq(
"function1" -> "com.gilt.example.Lambda::handleRequest1",
"function2" -> "com.gilt.example.Lambda::handleRequest2",
"function3" -> "com.gilt.example.OtherLambda::handleRequest3"
)

// or, instead of the above, for just one function/handler
//
// lambdaName := Some("function1")
//
// handlerName := Some("com.gilt.example.Lambda::handleRequest1")

s3Bucket := Some("lambda-jars")

awsLambdaMemory := Some(192)

awsLambdaTimeout := Some(30)

roleArn := Some("arn:aws:iam::123456789000:role/lambda_basic_execution")

```
(note that you will need to use a real ARN for your role rather than copying this one).


Publishing new versions of this plugin
Expand Down
83 changes: 38 additions & 45 deletions src/main/scala/com/gilt/aws/lambda/AwsLambdaPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import sbt._
object AwsLambdaPlugin extends AutoPlugin {

object autoImport {
val createLambda = taskKey[LambdaARN]("Create a new AWS Lambda function from the current project")
val updateLambda = taskKey[LambdaARN]("Package and deploy the current project to an existing AWS Lambda")
val createLambda = taskKey[Map[String, LambdaARN]]("Create a new AWS Lambda function from the current project")
val updateLambda = taskKey[Map[String, LambdaARN]]("Package and deploy the current project to an existing AWS Lambda")

val s3Bucket = settingKey[Option[String]]("ID of the S3 bucket where the jar will be uploaded")
val lambdaName = settingKey[Option[String]]("Name of the AWS Lambda to update")
Expand All @@ -15,6 +15,7 @@ object AwsLambdaPlugin extends AutoPlugin {
val region = settingKey[Option[String]]("Name of the AWS region to connect to")
val awsLambdaTimeout = settingKey[Option[Int]]("The Lambda timeout length in seconds (1-300)")
val awsLambdaMemory = settingKey[Option[Int]]("The amount of memory in MB for the Lambda function (128-1536, multiple of 64)")
val lambdaHandlers = settingKey[Seq[(String, String)]]("A sequence of pairs of Lambda function names to handlers (for multiple handlers in one jar)")
}

import autoImport._
Expand All @@ -26,60 +27,70 @@ object AwsLambdaPlugin extends AutoPlugin {
region = region.value,
jar = sbtassembly.AssemblyKeys.assembly.value,
s3Bucket = s3Bucket.value,
lambdaName = lambdaName.value
lambdaName = lambdaName.value,
handlerName = handlerName.value,
lambdaHandlers = lambdaHandlers.value
),
createLambda := doCreateLambda(
region = region.value,
jar = sbtassembly.AssemblyKeys.assembly.value,
s3Bucket = s3Bucket.value,
lambdaName = lambdaName.value,
handlerName = handlerName.value,
lambdaHandlers = lambdaHandlers.value,
roleArn = roleArn.value,
timeout = awsLambdaTimeout.value,
memory = awsLambdaMemory.value
),
s3Bucket := None,
lambdaName := Some(sbt.Keys.name.value),
handlerName := None,
lambdaHandlers := List.empty[(String, String)],
roleArn := None,
region := Some("us-east-1")
region := Some("us-east-1"),
awsLambdaMemory := None,
awsLambdaTimeout := None
)

private def doUpdateLambda(region: Option[String], jar: File, s3Bucket: Option[String], lambdaName: Option[String]): LambdaARN = {
private def doUpdateLambda(region: Option[String], jar: File, s3Bucket: Option[String], lambdaName: Option[String],
handlerName: Option[String], lambdaHandlers: Seq[(String, String)]): Map[String, LambdaARN] = {
val resolvedRegion = resolveRegion(region)
val resolvedBucketId = resolveBucketId(s3Bucket)
val resolvedLambdaName = resolveLambdaName(lambdaName)
val resolvedLambdaHandlers = resolveLambdaHandlers(lambdaName, handlerName, lambdaHandlers)

AwsS3.pushJarToS3(jar, resolvedBucketId) match {
case Success(s3Key) =>
case Success(s3Key) => (for (resolvedLambdaName <- resolvedLambdaHandlers.keys) yield {
AwsLambda.updateLambda(resolvedRegion, resolvedLambdaName, resolvedBucketId, s3Key) match {
case Success(updateFunctionCodeResult) =>
LambdaARN(updateFunctionCodeResult.getFunctionArn)
resolvedLambdaName.value -> LambdaARN(updateFunctionCodeResult.getFunctionArn)
case Failure(exception) =>
sys.error(s"Error updating lambda: ${exception.getStackTraceString}")
}
}).toMap
case Failure(exception) =>
sys.error(s"Error uploading jar to S3 lambda: ${exception.getStackTraceString}")
}
}

private def doCreateLambda(region: Option[String], jar: File, s3Bucket: Option[String], lambdaName: Option[String], handlerName: Option[String], roleArn: Option[String], timeout: Option[Int], memory: Option[Int]): LambdaARN = {
private def doCreateLambda(region: Option[String], jar: File, s3Bucket: Option[String], lambdaName: Option[String],
handlerName: Option[String], lambdaHandlers: Seq[(String, String)], roleArn: Option[String], timeout: Option[Int], memory: Option[Int]): Map[String, LambdaARN] = {
val resolvedRegion = resolveRegion(region)
val resolvedLambdaName = resolveLambdaName(lambdaName)
val resolvedHandlerName = resolveHandlerName(handlerName)
val resolvedLambdaHandlers = resolveLambdaHandlers(lambdaName, handlerName, lambdaHandlers)
val resolvedRoleName = resolveRoleARN(roleArn)
val resolvedBucketId = resolveBucketId(s3Bucket)
val resolvedTimeout = resolveTimeout(timeout)
val resolvedMemory = resolveMemory(memory)

AwsS3.pushJarToS3(jar, resolvedBucketId) match {
case Success(s3Key) =>
AwsLambda.createLambda(resolvedRegion, jar, resolvedLambdaName, resolvedHandlerName, resolvedRoleName, resolvedBucketId, resolvedTimeout, resolvedMemory) match {
case Success(createFunctionCodeResult) =>
LambdaARN(createFunctionCodeResult.getFunctionArn)
case Failure(exception) =>
sys.error(s"Failed to create lambda function: ${exception.getLocalizedMessage}\n${exception.getStackTraceString}")
}
(for ((resolvedLambdaName, resolvedHandlerName) <- resolvedLambdaHandlers) yield {
AwsLambda.createLambda(resolvedRegion, jar, resolvedLambdaName, resolvedHandlerName, resolvedRoleName, resolvedBucketId, resolvedTimeout, resolvedMemory) match {
case Success(createFunctionCodeResult) =>
resolvedLambdaName.value -> LambdaARN(createFunctionCodeResult.getFunctionArn)
case Failure(exception) =>
sys.error(s"Failed to create lambda function: ${exception.getLocalizedMessage}\n${exception.getStackTraceString}")
}
}).toMap
case Failure(exception) =>
sys.error(s"Error upload jar to S3 lambda: ${exception.getLocalizedMessage}")
}
Expand All @@ -105,25 +116,13 @@ object AwsLambdaPlugin extends AutoPlugin {
}
}

private def resolveLambdaName(sbtSettingValueOpt: Option[String]): LambdaName = {
sbtSettingValueOpt match {
case Some(f) => LambdaName(f)
case None => sys.env.get(EnvironmentVariables.lambdaName) match {
case Some(envVarFunctionName) => LambdaName(envVarFunctionName)
case None => promptUserForFunctionName()
}
}
}

private def resolveHandlerName(sbtSettingValueOpt: Option[String]): HandlerName = {
sbtSettingValueOpt match {
case Some(f) => HandlerName(f)
case None => sys.env.get(EnvironmentVariables.handlerName) match {
case Some(envVarFunctionName) => HandlerName(envVarFunctionName)
case None => promptUserForHandlerName()
}
private def resolveLambdaHandlers(lambdaName: Option[String], handlerName: Option[String],
lambdaHandlers: Seq[(String, String)]): Map[LambdaName, HandlerName] =
if (lambdaHandlers.nonEmpty) lambdaHandlers.map { case (l, h) => LambdaName(l) -> HandlerName(h)}.toMap else {
val l = lambdaName.getOrElse(sys.env.getOrElse(EnvironmentVariables.lambdaName, promptUserForFunctionName()))
val h = handlerName.getOrElse(sys.env.getOrElse(EnvironmentVariables.handlerName, promptUserForHandlerName()))
Map(LambdaName(l) -> HandlerName(h))
}
}

private def resolveRoleARN(sbtSettingValueOpt: Option[String]): RoleARN = {
sbtSettingValueOpt match {
Expand Down Expand Up @@ -178,17 +177,11 @@ object AwsLambdaPlugin extends AutoPlugin {
}
}

private def promptUserForFunctionName(): LambdaName = {
val inputValue = readInput(s"Enter the name of the AWS Lambda. (You also could have set the environment variable: ${EnvironmentVariables.lambdaName} or the sbt setting: lambdaName)")
private def promptUserForFunctionName(): String =
readInput(s"Enter the name of the AWS Lambda. (You also could have set the environment variable: ${EnvironmentVariables.lambdaName} or the sbt setting: lambdaName)")

LambdaName(inputValue)
}

private def promptUserForHandlerName(): HandlerName = {
val inputValue = readInput(s"Enter the name of the AWS Lambda handler. (You also could have set the environment variable: ${EnvironmentVariables.handlerName} or the sbt setting: handlerName)")

HandlerName(inputValue)
}
private def promptUserForHandlerName(): String =
readInput(s"Enter the name of the AWS Lambda handler. (You also could have set the environment variable: ${EnvironmentVariables.handlerName} or the sbt setting: handlerName)")

private def promptUserForRoleARN(): RoleARN = {
AwsIAM.basicLambdaRole() match {
Expand Down

0 comments on commit 1f45db2

Please sign in to comment.