Skip to content

Commit

Permalink
Merge pull request #12 from spatocode/more-runtime-support
Browse files Browse the repository at this point in the history
Support more runtime auto build
  • Loading branch information
spatocode authored Sep 29, 2023
2 parents 23956d2 + 621e155 commit 9f2f059
Show file tree
Hide file tree
Showing 20 changed files with 675 additions and 202 deletions.
3 changes: 1 addition & 2 deletions assets/tests/jerm.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@
"memory": 512,
"keep_warm": false
},
"dir": "/home/ubuntu/bodystats",
"entry": "bodyie"
"dir": "/home/ubuntu/bodystats"
}
44 changes: 10 additions & 34 deletions cloud/aws/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"path/filepath"
"sort"
"strconv"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
Expand Down Expand Up @@ -56,13 +55,15 @@ func NewLambda(cfg *config.Config) (*Lambda, error) {
timeout: DefaultTimeout,
}

lambdaConfig := config.Platform{Name: config.Lambda}
err := lambdaConfig.Defaults()
if err != nil {
return nil, err
if l.config.Platform.Name == "" {
lambdaConfig := config.Platform{Name: config.Lambda}
err := lambdaConfig.Defaults()
if err != nil {
return nil, err
}
l.config.Platform = lambdaConfig
}

l.config.Platform = lambdaConfig
awsConfig, err := l.getAwsConfig()
if err != nil {
return nil, err
Expand Down Expand Up @@ -98,9 +99,6 @@ func (l *Lambda) Build() (string, error) {
log.Debug("building Jerm project for Lambda...")

r := config.NewRuntime()
if l.config.Entry == "" {
l.config.Entry = r.Entry()
}

go func() {
err := l.config.ToJson(jerm.DefaultConfigFile)
Expand All @@ -109,18 +107,14 @@ func (l *Lambda) Build() (string, error) {
}
}()

handler, err := r.Build(l.config)
packageDir, function, err := r.Build(l.config)
if err != nil {
return "", err
}

dir := filepath.Dir(handler)
l.functionHandler = function

if l.config.Platform.Handler == "" {
err := l.CreateFunctionEntry(handler)
return dir, err
}
return dir, err
return packageDir, nil
}

func (l *Lambda) Invoke(command string) error {
Expand Down Expand Up @@ -433,24 +427,6 @@ func (l *Lambda) listLambdaVersions() ([]lambdaTypes.FunctionConfiguration, erro
return response.Versions, err
}

// CreateFunctionEntry creates a Lambda function handler file
func (l *Lambda) CreateFunctionEntry(file string) error {
log.Debug("creating lambda handler...")
f, err := os.Create(file)
if err != nil {
return err
}
defer f.Close()

handler := strings.ReplaceAll(awsLambdaHandler, ".wsgi", l.config.Entry+".wsgi")
_, err = f.Write([]byte(handler))
if err != nil {
return err
}
l.functionHandler = "handler.lambda_handler"
return nil
}

func (l *Lambda) isAlreadyDeployed() (bool, error) {
log.Debug("fetching function code location...")
versions, err := l.listLambdaVersions()
Expand Down
3 changes: 2 additions & 1 deletion cmd/manage.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/spatocode/jerm/cloud/aws"
"github.com/spatocode/jerm/config"
"github.com/spatocode/jerm/internal/log"
"github.com/spatocode/jerm/internal/utils"
)

// manageCmd represents the manage command
Expand All @@ -37,7 +38,7 @@ var manageCmd = &cobra.Command{
return
}

runtime := config.NewPythonRuntime()
runtime := config.NewPythonRuntime(utils.Command())
python, ok := runtime.(*config.Python)
if !ok || !python.IsDjango() {
log.PrintError("manage command is for Django projects only")
Expand Down
1 change: 0 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ type Config struct {
Region string `json:"region"`
Platform Platform `json:"platform"`
Dir string `json:"dir"`
Entry string `json:"entry"`
}

func (c *Config) GetFunctionName() string {
Expand Down
14 changes: 13 additions & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ func TestConfigDefaults(t *testing.T) {
assert.NotNil(cfg.Region)
}

func TestConfigToJson(t *testing.T) {
assert := assert.New(t)
testfile := "../assets/test.json"
cfg := &Config{}

assert.False(utils.FileExists(testfile))
err := cfg.ToJson(testfile)
assert.Nil(err)
assert.True(utils.FileExists(testfile))

helperCleanup(t, []string{testfile})
}

func TestReadConfig(t *testing.T) {
assert := assert.New(t)
c, err := ReadConfig("../assets/tests/jerm.json")
Expand All @@ -44,7 +57,6 @@ func TestReadConfig(t *testing.T) {
assert.Equal(512, c.Platform.Memory)
assert.Equal(false, c.Platform.KeepWarm)
assert.Equal("/home/ubuntu/bodystats", c.Dir)
assert.Equal("bodyie", c.Entry)
}

func TestIgnoredFiles(t *testing.T) {
Expand Down
32 changes: 18 additions & 14 deletions config/golang.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ type Go struct {
}

// NewGoConfig instantiates a new Go runtime
func NewGoRuntime() RuntimeInterface {
runtime := &Runtime{}
func NewGoRuntime(cmd utils.ShellCommand) RuntimeInterface {
runtime := &Runtime{cmd, RuntimeGo, DefaultGoVersion, ""}
g := &Go{runtime}
g.Name = RuntimeGo
version, err := g.getVersion()
if err != nil {
log.Debug(fmt.Sprintf("encountered an error while getting go version. Default to %s", DefaultGoVersion))
g.Version = DefaultGoVersion
return g
}
g.Version = version
Expand All @@ -32,27 +30,33 @@ func NewGoRuntime() RuntimeInterface {
// Gets the go version
func (g *Go) getVersion() (string, error) {
log.Debug("getting go version...")
goVersion, err := utils.GetShellCommandOutput("go", "version")
goVersion, err := g.RunCommand("go", "version")
if err != nil {
return "", err
}
s := strings.Split(goVersion, " ")
if len(s) > 1 {
version := strings.Split(s[2], "go")
return version[1], nil
return strings.TrimSpace(version[1]), nil
}
return "", errors.New("encountered error on go version")
}

// Builds the go deployment package
func (g *Go) Build(config *Config) (string, error) {
return "", nil
}
// Build builds the go deployment package
// It returns the executable path, the function name and error if any
func (g *Go) Build(config *Config) (string, string, error) {
_, err := g.RunCommand("go", "mod", "tidy")
if err != nil {
return "", "", err
}

env := []string{"GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=0"}
_, err = g.RunCommandWithEnv(env, "go", "build", "main.go")
if err != nil {
return "", "", err
}

// Entry is the directory where the cloud function handler resides.
// The directory can be a file.
func (g *Go) Entry() string {
return "main.go"
return "main", "main", nil
}

// lambdaRuntime is the name of the go runtime as specified by AWS Lambda
Expand Down
79 changes: 79 additions & 0 deletions config/golang_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package config

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestNewGolangRuntime(t *testing.T) {
assert := assert.New(t)
fakeOutput = "go version go1.21.0 linux/amd64"
r := NewGoRuntime(fakeCommandExecutor{})
g := r.(*Go)
assert.Equal(RuntimeGo, g.Name)
assert.Equal("1.21.0", g.Version)
}

func TestNewGolangRuntimeDefaultVersion(t *testing.T) {
assert := assert.New(t)
fakeOutput = ""
r := NewGoRuntime(fakeCommandExecutor{})
g := r.(*Go)
assert.Equal(RuntimeGo, g.Name)
assert.Equal(DefaultGoVersion, g.Version)
}

func TestGoGetVersion(t *testing.T) {
assert := assert.New(t)
fakeOutput = "go version go1.21.0 linux/amd64"
r := NewGoRuntime(fakeCommandExecutor{})
g := r.(*Go)
v, err := g.getVersion()
assert.Nil(err)
assert.Equal(RuntimeGo, g.Name)
assert.Equal("1.21.0", v)
}

func TestGoGetVersionError(t *testing.T) {
assert := assert.New(t)
fakeOutput = ""
r := NewGoRuntime(fakeCommandExecutor{})
g := r.(*Go)
v, err := g.getVersion()
assert.NotNil(err)
assert.Equal(RuntimeGo, g.Name)
assert.Equal("", v)
}

func TestGoLambdaRuntime(t *testing.T) {
assert := assert.New(t)
fakeOutput = "go version go1.21.0 linux/amd64"
r := NewGoRuntime(fakeCommandExecutor{})
g := r.(*Go)
v, err := g.lambdaRuntime()
assert.Nil(err)
assert.Equal("go1.x", v)
}

func TestGoBuild(t *testing.T) {
assert := assert.New(t)
fakeOutput = "go version go1.21.0 linux/amd64"
r := NewGoRuntime(fakeCommandExecutor{})
cfg := &Config{Name: "test", Stage: "env"}
p, f, err := r.Build(cfg)
assert.Nil(err)
assert.Equal("main", p)
assert.Equal("main", f)
}

func TestGoBuildError(t *testing.T) {
assert := assert.New(t)
fakeOutput = ""
r := NewGoRuntime(fakeCommandExecutor{})
cfg := &Config{Name: "test", Stage: "env"}
p, f, err := r.Build(cfg)
assert.NotNil(err)
assert.Equal("", p)
assert.Equal("", f)
}
6 changes: 3 additions & 3 deletions cloud/aws/handler.go → config/handlers/django.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package aws
package handlers

const (
awsLambdaHandler = `
AwsLambdaHandlerDjango = `
import sys
import json
import io
Expand All @@ -20,7 +20,7 @@ logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
def handler(event, context):
if settings.DEBUG:
logger.debug("Jerm Event: {}".format(event))
Expand Down
19 changes: 19 additions & 0 deletions config/handlers/statichtml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package handlers

const (
AwsLambdaHandlerStaticPage = `
const fs = require('fs');
const html = fs.readFileSync('index.html', { encoding:'utf8' });
exports.handler = async (event) => {
const response = {
statusCode: 200,
headers: {
'Content-Type': 'text/html',
},
body: html,
};
return response;
};
`
)
17 changes: 5 additions & 12 deletions config/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ type Node struct {
}

// NewNodeConfig instantiates a new NodeJS runtime
func NewNodeRuntime() RuntimeInterface {
runtime := &Runtime{}
func NewNodeRuntime(cmd utils.ShellCommand) RuntimeInterface {
runtime := &Runtime{cmd, RuntimeNode, DefaultNodeVersion, ""}
n := &Node{runtime}
n.Name = RuntimeNode
version, err := n.getVersion()
if err != nil {
log.Debug(fmt.Sprintf("encountered an error while getting nodejs version. Default to %s", DefaultNodeVersion))
n.Version = DefaultNodeVersion
log.Debug(fmt.Sprintf("encountered an error while getting nodejs version. Default to v%s", DefaultNodeVersion))
return n
}
n.Version = version
Expand All @@ -31,19 +29,14 @@ func NewNodeRuntime() RuntimeInterface {
// Gets the nodejs version
func (n *Node) getVersion() (string, error) {
log.Debug("getting nodejs version...")
nodeVersion, err := utils.GetShellCommandOutput("node", "-v")
nodeVersion, err := n.RunCommand("node", "-v")
if err != nil {
return "", err
}
nodeVersion = nodeVersion[1:]
nodeVersion = strings.TrimSpace(nodeVersion[1:])
return nodeVersion, nil
}

// Builds the nodejs deployment package
func (n *Node) Build(config *Config) (string, error) {
return "", nil
}

// lambdaRuntime is the name of the nodejs runtime as specified by AWS Lambda
func (n *Node) lambdaRuntime() (string, error) {
v := strings.Split(n.Version, ".")
Expand Down
Loading

0 comments on commit 9f2f059

Please sign in to comment.