Sparta takes a set of golang functions and automatically provisions them in AWS Lambda as a logical unit.
Functions must implement
type LambdaFunction func(*json.RawMessage,
*LambdaContext,
http.ResponseWriter,
*logrus.Logger)
where
json.RawMessage
: The arbitraryjson.RawMessage
event data provided to the function.LambdaContext
: golang compatible representation of the AWS Lambda Contexthttp.ResponseWriter
: Writer for response. The HTTP status code & response body is translated to a pass/fail result provided to thecontext.done()
handler.logrus.Logger
: logrus logger with JSON output. See an example for including JSON fields.
Given a set of registered golang functions, Sparta will:
- Either verify or provision the defined IAM roles
- Build a deployable application via
Provision()
- Zip the contents and associated JS proxying logic
- Dynamically create a CloudFormation template to either create or update the service state.
- Optionally:
- Register with S3 and SNS for push source configuration
- Provision an API Gateway service to make your functions publicly available
Note that Lambda updates may be performed with no interruption in service.
- Create application.go :
```go
package main
import (
"encoding/json"
"fmt"
"github.com/Sirupsen/logrus"
sparta "github.com/mweagle/Sparta"
"net/http"
)
func echoEvent(event *sparta.LambdaEvent,
context *sparta.LambdaContext,
w http.ResponseWriter,
logger *logrus.Logger) {
logger.WithFields(logrus.Fields{
"RequestID": context.AWSRequestID,
}).Info("Request received")
eventData, err := json.Marshal(*event)
if err != nil {
logger.Error("Failed to marshal event data: ", err.Error())
http.Error(*w, err.Error(), http.StatusInternalServerError)
}
logger.Info("Event data: ", string(eventData))
}
func main() {
var lambdaFunctions []*sparta.LambdaAWSInfo
lambdaEcho := sparta.NewLambda(sparta.IAMRoleDefinition{},
echoEvent,
nil)
lambdaFunctions = append(lambdaFunctions, lambdaEcho)
sparta.Main("SpartaEcho",
"This is a sample Sparta application",
lambdaFunctions)
}
```
go get ./...
go run application.go provision --s3Bucket MY_S3_BUCKET_NAME
- You'll need to change MY_S3_BUCKET_NAME to an accessible S3 bucketname
- Visit the AWS Lambda console and confirm your Lambda function is accessible
See also the Sparta Application for an example.
The []sparta.LambdaAWSInfo.Permissions
slice allows Lambda functions to automatically manage remote event source subscriptions. Push-based event sources are updated via CustomResources that are injected into the CloudFormation template if appropriate.
Examples:
The per-service API logic is inline NodeJS ZipFile code. See the provision directory for more.
See also the Sparta Application for a standalone example.
It's possible to expose to your golang functions over HTTPS by associating an API Gateway. To enable API Gateway support, you must:
- Define a Stage
- Define an API Gateway name and provide the previously defined stage.
- Create one or more
(resource, httpMethod)
pairs that are bound to your lambda function.
Example:
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/Sirupsen/logrus"
sparta "github.com/mweagle/Sparta"
)
////////////////////////////////////////////////////////////////////////////////
// Echo handler
//
func echoEvent(event *json.RawMessage,
context *sparta.LambdaContext,
w http.ResponseWriter,
logger *logrus.Logger) {
logger.WithFields(logrus.Fields{
"RequestID": context.AWSRequestID,
"Event": string(*event),
}).Info("Request received")
fmt.Fprintf(*w, "Hello World!")
}
func main() {
stage := sparta.NewStage("test")
apiGateway := sparta.NewAPIGateway("MySpartaAPI", stage)
var lambdaFunctions []*sparta.LambdaAWSInfo
lambdaFn := sparta.NewLambda(sparta.IAMRoleDefinition{}, echoEvent, nil)
apiGatewayResource, _ := apiGateway.NewResource("/hello/echo", lambdaFn)
apiGatewayResource.NewMethod("GET")
lambdaFunctions = append(lambdaFunctions, lambdaFn)
sparta.Main("SampleApplication",
"Sample application with API Gateway support",
lambdaFunctions,
apiGateway)
}
This API can be deployed via:
go run api.go --level debug provision --s3Bucket $MY_S3_BUCKET_NAME
The provisioning log will output the AWS-assigned API Gateway URL as in:
...
Outputs: [{
Description: "API Gateway URL",
OutputKey: "URL",
OutputValue: "https://vpv0e9nv83.execute-api.us-west-2.amazonaws.com/test"
}],
...
You can then access a specific resource by appending the path component to the OutputValue of the URL value as in:
$ curl -vs https://jhn4bubx7h.execute-api.us-west-2.amazonaws.com/test/hello/echo
* Trying 54.230.147.237...
* Connected to jhn4bubx7h.execute-api.us-west-2.amazonaws.com (54.230.147.237) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.execute-api.us-west-2.amazonaws.com
* Server certificate: Symantec Class 3 Secure Server CA - G4
* Server certificate: VeriSign Class 3 Public Primary Certification Authority - G5
> GET /test/hello/echo HTTP/1.1
> Host: jhn4bubx7h.execute-api.us-west-2.amazonaws.com
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 14
< Connection: keep-alive
< Date: Mon, 23 Nov 2015 17:02:01 GMT
< x-amzn-RequestId: e968e0f1-9203-11e5-9134-61048221e24a
< X-Cache: Miss from cloudfront
< Via: 1.1 5687015cb50d88319b87aae0ee898267.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: lxP1CTKaV5ArYkfZCNJeWnUaF-63AwCM3-puXo315d_HwSvdhz7ibQ==
<
* Connection #0 to host jhn4bubx7h.execute-api.us-west-2.amazonaws.com left intact
"Hello World!"
NOTE: Providing nil
as the Stage argument to sparta.NewAPIGateway()
will provision an API instance, but will not deploy it.
- Verify your golang SDK credentials are properly configured
- If referring to pre-existing IAM Roles, verify that the Lambda IAM Permissions are properly configured and that the correct IAM RoleName is provided to
sparta.NewLambda()
- More information on the Lambda permission model is available here
It's also possible to generate a visual representation of your Lambda connections
via the describe
command line argument.
go run application.go describe --out ./graph.html && open ./graph.html
View the latest versions at GoDoc or run make docs
in the source directory & visit http://localhost:8090.
- golang isn't officially supported by AWS (yet)
- But, you can vote to make golang officially supported.
- Because of this, there is a per-container initialization cost of:
- Copying the embedded binary to /tmp
- Changing the binary permissions
- Launching it from the new location
- See the AWS Forum for more background
- Depending on container reuse, this initialization penalty (~
700ms
) may prove burdensome. - See the JAWS project for a pure NodeJS alternative. - See the PAWS project for a pure Python alternative.
- There are Lambda Limits that may affect your development
- Eliminate NodeJS CustomResources
- Support API Gateway updates
- Currently API reprovisioning is done by
delete
=>create
- Currently API reprovisioning is done by
- Optimize CONSTANTS.go for deployed binary
- Implement APIGateway graph
- Support APIGateway inline Model definition
- Support custom domains