Skip to content

Instantly share code, notes, and snippets.

@angelodlfrtr
Created April 17, 2019 13:35
Show Gist options
  • Save angelodlfrtr/e51ab4abde40a980bd904c353a2542e6 to your computer and use it in GitHub Desktop.
Save angelodlfrtr/e51ab4abde40a980bd904c353a2542e6 to your computer and use it in GitHub Desktop.
A go binary to autocompile and push go lambda function to aws lambda
package main
import (
"archive/zip"
"bytes"
"encoding/json"
"flag"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/lambda"
"github.com/aws/aws-sdk-go/service/s3"
. "github.com/logrusorgru/aurora"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
)
type RcConfig struct {
Name string `json:"name"`
Bucket string `json:"bucket"`
Region string `json:"region"`
}
func main() {
// ===============================================================================================
// FLAGS =========================================================================================
// ===============================================================================================
// Load flags
functionPath := flag.String("path", ".", "Function path")
functionName := flag.String("name", "", "Function name")
s3Bucket := flag.String("bucket", "", "S3 bucket name")
region := flag.String("region", "", "AWS Region")
// Parse flags
flag.Parse()
// Get absolute path for lamlbda func
realFunctionPath, err := filepath.Abs(*functionPath)
if err != nil {
fmt.Println(Red(err.Error()))
os.Exit(1)
}
// Check dir exitence
if _, err = os.Stat(realFunctionPath); os.IsNotExist(err) {
fmt.Println(Red(fmt.Sprintf("Function path %s not exist", realFunctionPath)))
os.Exit(1)
}
// Get region
var awsRegion string
if len(*region) > 0 {
awsRegion = *region
} else {
awsRegion = os.Getenv("AWS_DEFAULT_REGION")
}
// ===============================================================================================
// PUSHRC ========================================================================================
// ===============================================================================================
// Try to load .pushrc.json file in function
rcFilePath := fmt.Sprintf("%s/.pushrc.json", realFunctionPath)
var rcBytes []byte
rcBytes, err = ioutil.ReadFile(rcFilePath)
if err != nil {
//fmt.Println(Red(err.Error()))
Magenta(">> No rc file found")
} else {
// Load json
rcConfig := &RcConfig{}
err = json.Unmarshal(rcBytes, &rcConfig)
if err != nil {
fmt.Println(Red(err.Error()))
os.Exit(1)
}
// Append name
if len(rcConfig.Name) > 0 {
if len(*functionName) < 1 {
functionName = &rcConfig.Name
}
}
// Append bucket
if len(rcConfig.Bucket) > 0 {
if len(*s3Bucket) < 1 {
s3Bucket = &rcConfig.Bucket
}
}
// Append region
if len(rcConfig.Region) > 0 {
if len(awsRegion) < 1 {
awsRegion = rcConfig.Region
}
}
}
// ===============================================================================================
// VALIDATE ======================================================================================
// ===============================================================================================
// Check function name
if len(*functionName) < 1 {
fmt.Println(Red("Function name required"))
fmt.Fprintf(os.Stderr, "Usage : pushlambdafungo [options]\n")
flag.PrintDefaults()
os.Exit(1)
}
if len(awsRegion) < 1 {
fmt.Println(Red("AWS region required"))
fmt.Fprintf(os.Stderr, "Usage : pushlambdafungo [options]\n")
flag.PrintDefaults()
}
fmt.Println(">> Run pushlambdafungo for function", Green(realFunctionPath))
fmt.Println(">> Function name :", Green(*functionName))
fmt.Println(">> AWS Region :", Green(awsRegion))
fmt.Println(">> S3 Bucket :", Green(*s3Bucket))
// ===============================================================================================
// BUILD =========================================================================================
// ===============================================================================================
fmt.Println(">> Building target function ...")
// Cross compile function for lambda env
compileCmd := exec.Command(
"go",
"build",
"-o",
fmt.Sprintf("%s/main", realFunctionPath),
fmt.Sprintf("%s/main.go", realFunctionPath),
)
// Append correct env
compileCmd.Env = os.Environ()
compileCmd.Env = append(compileCmd.Env, "GOOS=linux")
var compileOut []byte
compileOut, err = compileCmd.CombinedOutput()
if err != nil {
fmt.Println(err.Error())
fmt.Println(string(compileOut))
os.Exit(1)
}
fmt.Println(">> Build target function", Green("success"))
// ===============================================================================================
// ZIP ===========================================================================================
// ===============================================================================================
fmt.Println(">> Zip generated binary ...")
// Create zip buffer
zipBuf := new(bytes.Buffer)
// Create zip writer
zip := zip.NewWriter(zipBuf)
// Create zip file (will contain out binary)
zipF, _ := zip.Create("main")
// Read compiled binary as array of byte
binaryContent, err := ioutil.ReadFile(fmt.Sprintf("%s/main", realFunctionPath))
if err != nil {
fmt.Println(Red(err.Error()))
os.Exit(1)
}
// Add compiled bynary content to zip file
zipF.Write(binaryContent)
// Close zip writer
zip.Close()
fmt.Println(">> Zip generated binary", Green("success"))
// ===============================================================================================
// S3 UPLOAD =====================================================================================
// ===============================================================================================
fmt.Println(">> Push zip archive to s3 bucket", *s3Bucket, "...")
// Create AWS session
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(awsRegion),
}))
// Create S3 Client
s3Client := s3.New(sess)
// Create io reader from zip buffer
zipReader := bytes.NewReader(zipBuf.Bytes())
// Put object params
s3Input := &s3.PutObjectInput{
Bucket: aws.String(*s3Bucket),
Key: aws.String(fmt.Sprintf("%s.zip", *functionName)),
Body: aws.ReadSeekCloser(zipReader),
}
// Create object in s3
_, err = s3Client.PutObject(s3Input)
if err != nil {
fmt.Println(Red(err.Error()))
os.Exit(1)
}
fmt.Println(">> Push zip archive to s3 bucket", *s3Bucket, Green("success"))
// ===============================================================================================
// UPDATE FUNCTION CODE ==========================================================================
// ===============================================================================================
fmt.Println(">> Update aws lambda function code ...")
lambdaClient := lambda.New(sess)
updateFuncCodeInput := &lambda.UpdateFunctionCodeInput{
FunctionName: aws.String(*functionName),
Publish: aws.Bool(false),
S3Bucket: aws.String(*s3Bucket),
S3Key: aws.String(fmt.Sprintf("%s.zip", *functionName)),
}
_, err = lambdaClient.UpdateFunctionCode(updateFuncCodeInput)
if err != nil {
fmt.Println(Red(err.Error()))
os.Remove(fmt.Sprintf("%s/main", *functionPath))
os.Exit(1)
}
fmt.Println(">> Update aws lambda function code", Green("success"))
// ===============================================================================================
// REMOVE GENERATED BINARY =======================================================================
// ===============================================================================================
err = os.Remove(fmt.Sprintf("%s/main", *functionPath))
if err != nil {
fmt.Println(Red(err.Error()))
os.Exit(1)
}
// ===============================================================================================
// DONE ==========================================================================================
// ===============================================================================================
fmt.Println(">> All done :)")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment