Skip to content

Instantly share code, notes, and snippets.

@mweagle
mweagle / application.go
Last active April 11, 2016 16:40
Hello world for Medium
// File: application.go
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/Sirupsen/logrus"
sparta "github.com/mweagle/Sparta"
INFO[0000] Welcome to Sparta Option=provision TS=2016-04-11T17:16:54Z Version=0.5.5
INFO[0000] --------------------------------------------------------------------------------
INFO[0000] Verifying IAM Lambda execution roles
INFO[0000] IAM roles verified Count=1
INFO[0000] Running `go generate`
INFO[0000] Compiling binary Name=SpartaHelloWorld.lambda.amd64
INFO[0008] Executable binary size KB=13317 MB=13
INFO[0008] Creating ZIP archive for upload TempName=/Users/mweagle/Documents/gopath/src/MediumPost/SpartaHelloWorld440815707
INFO[0009] Registering Sparta function FunctionName=main.helloWorld
INFO[0009] Lambda function deployment package size KB=4779 MB=4
var createForwarder = function(path) {
var forwardToGolangProcess = function(event, context, metricName)
{
if (!golangProcess) {
ensureGoLangBinary(function() {
golangProcess = child_process.spawn(SPARTA_BINARY_PATH, ['execute', '--signal', process.pid], {});
golangProcess.stdout.on('data', function(buf) {
buf.toString('utf-8').split('\n').forEach(function (eachLine) {
sparta_utils.log(eachLine);
func NewLambda(roleNameOrIAMRoleDefinition interface{},
fn LambdaFunction,
lambdaOptions *LambdaFunctionOptions) *LambdaAWSInfo {
if nil == lambdaOptions {
lambdaOptions = &LambdaFunctionOptions{"", 128, 3, nil}
}
lambdaPtr := runtime.FuncForPC(reflect.ValueOf(fn).Pointer())
lambda := &LambdaAWSInfo{
lambdaFnName: lambdaPtr.Name(),
lambdaFn: fn,
cmd = exec.Command("go", "build", "-o", executableOutput, "-tags", "lambdabinary", ".")
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "GOOS=linux", "GOARCH=amd64")
ctx.logger.WithFields(logrus.Fields{
"Name": executableOutput,
}).Info("Compiling binary")
err = runOSCommand(cmd, ctx.logger)
// Add the string literal adapter, which requires us to add exported
// functions to the end of index.js. These NodeJS exports will be
// linked to the AWS Lambda NodeJS function name, and are basically
// automatically generated pass through proxies to the golang HTTP handler.
nodeJSWriter, err := lambdaArchive.Create("index.js")
if err != nil {
return nil, errors.New("Failed to create ZIP entry: index.js")
}
nodeJSSource := _escFSMustString(false, "/resources/index.js")
nodeJSSource += "\n// DO NOT EDIT - CONTENT UNTIL EOF IS AUTOMATICALLY GENERATED\n"
// Return a string representation of a JS function call that can be exposed
// to AWS Lambda
func createNewNodeJSProxyEntry(lambdaInfo *LambdaAWSInfo, logger *logrus.Logger) string {
logger.WithFields(logrus.Fields{
"FunctionName": lambdaInfo.lambdaFnName,
}).Info("Registering Sparta function")
// We do know the CF resource name here - could write this into
// index.js and expose a GET localhost:9000/lambdaMetadata
// which wraps up DescribeStackResource for the running
func (handler *LambdaHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Remove the leading slash and dispatch it to the golang handler
lambdaFunc := strings.TrimLeft(req.URL.Path, "/")
decoder := json.NewDecoder(req.Body)
var request lambdaRequest
defer func() {
if r := recover(); r != nil {
err, ok := r.(error)
if !ok {
err = fmt.Errorf("%v", r)
var req = http.request(options, function(res) {
res.setEncoding('utf8');
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
// Bridge the NodeJS and golang worlds by including the golang
// HTTP status text in the error response if appropriate. This enables
// the API Gateway integration response to use standard golang StatusText regexp
"core": []iamPolicyStatement{
iamPolicyStatement{
Action: []string{"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"},
Effect: "Allow",
Resource: gocf.Join("",
gocf.String("arn:aws:logs:"),
gocf.Ref("AWS::Region"),
gocf.String(":"),