-
Notifications
You must be signed in to change notification settings - Fork 105
/
Copy pathmain.go
156 lines (120 loc) · 4.86 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"fmt"
"net"
"os"
"runtime/debug"
"github.com/jessevdk/go-flags"
"go.amzn.com/lambda/interop"
"go.amzn.com/lambda/rapidcore"
log "github.com/sirupsen/logrus"
)
const (
optBootstrap = "/opt/bootstrap"
runtimeBootstrap = "/var/runtime/bootstrap"
)
type options struct {
LogLevel string `long:"log-level" description:"The level of AWS Lambda Runtime Interface Emulator logs to display. Can also be set by the environment variable 'LOG_LEVEL'. Defaults to the value 'info'."`
InitCachingEnabled bool `long:"enable-init-caching" description:"Enable support for Init Caching"`
// Do not have a default value so we do not need to keep it in sync with the default value in lambda/rapidcore/sandbox_builder.go
RuntimeAPIAddress string `long:"runtime-api-address" description:"The address of the AWS Lambda Runtime API to communicate with the Lambda execution environment."`
RuntimeInterfaceEmulatorAddress string `long:"runtime-interface-emulator-address" default:"0.0.0.0:8080" description:"The address for the AWS Lambda Runtime Interface Emulator to accept HTTP request upon."`
}
func main() {
// More frequent GC reduces the tail latencies, equivalent to export GOGC=33
debug.SetGCPercent(33)
opts, args := getCLIArgs()
logLevel := "info"
// If you specify an option by using a parameter on the CLI command line, it overrides any value from either the corresponding environment variable.
//
// https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
if opts.LogLevel != "" {
logLevel = opts.LogLevel
} else if envLogLevel, envLogLevelSet := os.LookupEnv("LOG_LEVEL"); envLogLevelSet {
logLevel = envLogLevel
}
rapidcore.SetLogLevel(logLevel)
if opts.RuntimeAPIAddress != "" {
_, _, err := net.SplitHostPort(opts.RuntimeAPIAddress)
if err != nil {
log.WithError(err).Fatalf("The command line value for \"--runtime-api-address\" is not a valid network address %q.", opts.RuntimeAPIAddress)
}
}
_, _, err := net.SplitHostPort(opts.RuntimeInterfaceEmulatorAddress)
if err != nil {
log.WithError(err).Fatalf("The command line value for \"--runtime-interface-emulator-address\" is not a valid network address %q.", opts.RuntimeInterfaceEmulatorAddress)
}
bootstrap, handler := getBootstrap(args, opts)
sandbox := rapidcore.
NewSandboxBuilder().
AddShutdownFunc(context.CancelFunc(func() { os.Exit(0) })).
SetExtensionsFlag(true).
SetInitCachingFlag(opts.InitCachingEnabled)
if len(handler) > 0 {
sandbox.SetHandler(handler)
}
if opts.RuntimeAPIAddress != "" {
sandbox.SetRuntimeAPIAddress(opts.RuntimeAPIAddress)
}
funcName := GetenvWithDefault("AWS_LAMBDA_FUNCTION_NAME", "function")
sandboxContext, internalStateFn := sandbox.Create()
// Since we have not specified a custom interop server for standalone, we can
// directly reference the default interop server, which is a concrete type
sandbox.DefaultInteropServer().SetSandboxContext(sandboxContext)
sandbox.DefaultInteropServer().SetInternalStateGetter(internalStateFn)
startHTTPServer(opts.RuntimeInterfaceEmulatorAddress, sandbox, bootstrap, funcName)
}
func getCLIArgs() (options, []string) {
var opts options
parser := flags.NewParser(&opts, flags.IgnoreUnknown)
args, err := parser.ParseArgs(os.Args)
if err != nil {
log.WithError(err).Fatal("Failed to parse command line arguments:", os.Args)
}
return opts, args
}
func isBootstrapFileExist(filePath string) bool {
file, err := os.Stat(filePath)
return !os.IsNotExist(err) && !file.IsDir()
}
func getBootstrap(args []string, opts options) (interop.Bootstrap, string) {
var bootstrapLookupCmd []string
var handler string
currentWorkingDir := "/var/task" // default value
if len(args) <= 1 {
// set default value to /var/task/bootstrap, but switch to the other options if it doesn't exist
bootstrapLookupCmd = []string{
fmt.Sprintf("%s/bootstrap", currentWorkingDir),
}
if !isBootstrapFileExist(bootstrapLookupCmd[0]) {
var bootstrapCmdCandidates = []string{
optBootstrap,
runtimeBootstrap,
}
for i, bootstrapCandidate := range bootstrapCmdCandidates {
if isBootstrapFileExist(bootstrapCandidate) {
bootstrapLookupCmd = []string{bootstrapCmdCandidates[i]}
break
}
}
}
// handler is used later to set an env var for Lambda Image support
handler = ""
} else if len(args) > 1 {
bootstrapLookupCmd = args[1:]
if cwd, err := os.Getwd(); err == nil {
currentWorkingDir = cwd
}
if len(args) > 2 {
// Assume last arg is the handler
handler = args[len(args)-1]
}
log.Infof("exec '%s' (cwd=%s, handler=%s)", args[1], currentWorkingDir, handler)
} else {
log.Panic("insufficient arguments: bootstrap not provided")
}
return NewSimpleBootstrap(bootstrapLookupCmd, currentWorkingDir), handler
}