|
1 | | -// main entrypoint of init |
2 | | -// initial structure based upon /cmd/aws-lambda-rie/main.go |
3 | 1 | package main |
4 | 2 |
|
5 | 3 | import ( |
6 | | - "context" |
| 4 | + "io" |
| 5 | + "log/slog" |
7 | 6 | "os" |
8 | 7 | "runtime/debug" |
9 | | - "strconv" |
10 | 8 | "strings" |
11 | | - "time" |
12 | 9 |
|
13 | | - "github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/interop" |
14 | | - "github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/rapidcore" |
| 10 | + mlogging "github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda-managed-instances/logging" |
| 11 | + |
| 12 | + "github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda-managed-instances/rapidcore/env" |
15 | 13 | log "github.com/sirupsen/logrus" |
16 | 14 | ) |
17 | 15 |
|
@@ -105,160 +103,90 @@ func main() { |
105 | 103 | UnsetLsEnvs() |
106 | 104 |
|
107 | 105 | // set up logging following the Logrus logging levels: https://github.com/sirupsen/logrus#level-logging |
| 106 | + configureLogging(lsOpts.InitLogLevel) |
| 107 | + |
| 108 | + // Download code archives |
| 109 | + if err := DownloadCodeArchives(lsOpts.CodeArchives); err != nil { |
| 110 | + log.Fatal("Failed to download code archives: " + err.Error()) |
| 111 | + } |
| 112 | + |
| 113 | + if err := AdaptFilesystemPermissions(lsOpts.ChmodPaths); err != nil { |
| 114 | + log.Warnln("Could not change file mode of code directories:", err) |
| 115 | + } |
| 116 | + |
| 117 | + // Check if running in managed mode |
| 118 | + if _, ok := os.LookupEnv(env.AWS_LAMBDA_MAX_CONCURRENCY); ok { |
| 119 | + runManaged(lsOpts) |
| 120 | + return |
| 121 | + } |
| 122 | + |
| 123 | + runStandard(lsOpts) |
| 124 | +} |
| 125 | + |
| 126 | +func doInitDaemon(addr, port string, enable bool, lvl string) *Daemon { |
| 127 | + endpoint := "http://" + addr + ":" + port |
| 128 | + xrayConfig := initConfig(endpoint, getXRayLogLevel(lvl)) |
| 129 | + d := initDaemon(xrayConfig, enable) |
| 130 | + runDaemon(d) |
| 131 | + return d |
| 132 | +} |
| 133 | + |
| 134 | +func configureManagedLogger(logLevel string) { |
| 135 | + level := slogLevelFromString(logLevel) |
| 136 | + slog.SetDefault(mlogging.CreateNewLogger(level, io.Writer(os.Stderr))) |
| 137 | +} |
| 138 | + |
| 139 | +func configureStandardLogger(logLevel string) { |
| 140 | + log.SetOutput(os.Stderr) |
| 141 | +} |
| 142 | + |
| 143 | +func configureLogging(logLevel string) { |
108 | 144 | log.SetReportCaller(true) |
109 | | - // https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon-configuration.html |
110 | | - xRayLogLevel := "info" |
111 | | - switch lsOpts.InitLogLevel { |
| 145 | + switch logLevel { |
112 | 146 | case "trace": |
113 | 147 | log.SetFormatter(&log.JSONFormatter{}) |
114 | 148 | log.SetLevel(log.TraceLevel) |
115 | | - xRayLogLevel = "debug" |
116 | 149 | case "debug": |
117 | 150 | log.SetLevel(log.DebugLevel) |
118 | | - xRayLogLevel = "debug" |
119 | 151 | case "info": |
120 | 152 | log.SetLevel(log.InfoLevel) |
121 | 153 | case "warn": |
122 | 154 | log.SetLevel(log.WarnLevel) |
123 | | - xRayLogLevel = "warn" |
124 | 155 | case "error": |
125 | 156 | log.SetLevel(log.ErrorLevel) |
126 | | - xRayLogLevel = "error" |
127 | 157 | case "fatal": |
128 | 158 | log.SetLevel(log.FatalLevel) |
129 | | - xRayLogLevel = "error" |
130 | 159 | case "panic": |
131 | 160 | log.SetLevel(log.PanicLevel) |
132 | | - xRayLogLevel = "error" |
133 | 161 | default: |
134 | 162 | log.Fatal("Invalid value for LOCALSTACK_INIT_LOG_LEVEL") |
135 | 163 | } |
| 164 | +} |
136 | 165 |
|
137 | | - // patch MaxPayloadSize |
138 | | - payloadSize, err := strconv.Atoi(lsOpts.MaxPayloadSize) |
139 | | - if err != nil { |
140 | | - log.Panicln("Please specify a number for LOCALSTACK_MAX_PAYLOAD_SIZE") |
141 | | - } |
142 | | - interop.MaxPayloadSize = payloadSize |
143 | | - |
144 | | - // download code archive if env variable is set |
145 | | - if err := DownloadCodeArchives(lsOpts.CodeArchives); err != nil { |
146 | | - log.Fatal("Failed to download code archives: " + err.Error()) |
147 | | - } |
148 | | - |
149 | | - if err := AdaptFilesystemPermissions(lsOpts.ChmodPaths); err != nil { |
150 | | - log.Warnln("Could not change file mode of code directories:", err) |
151 | | - } |
152 | | - |
153 | | - // parse CLI args |
154 | | - bootstrap, handler := getBootstrap(os.Args) |
155 | | - |
156 | | - // Switch to non-root user and drop root privileges |
157 | | - if IsRootUser() && lsOpts.User != "" && lsOpts.User != "root" { |
158 | | - uid := 993 |
159 | | - gid := 990 |
160 | | - AddUser(lsOpts.User, uid, gid) |
161 | | - if err := os.Chown("/tmp", uid, gid); err != nil { |
162 | | - log.Warnln("Could not change owner of directory /tmp:", err) |
163 | | - } |
164 | | - UserLogger().Debugln("Process running as root user.") |
165 | | - err := DropPrivileges(lsOpts.User) |
166 | | - if err != nil { |
167 | | - log.Warnln("Could not drop root privileges.", err) |
168 | | - } else { |
169 | | - UserLogger().Debugln("Process running as non-root user.") |
170 | | - } |
171 | | - } |
172 | | - |
173 | | - // file watcher for hot-reloading |
174 | | - fileWatcherContext, cancelFileWatcher := context.WithCancel(context.Background()) |
175 | | - |
176 | | - logCollector := NewLogCollector() |
177 | | - localStackLogsEgressApi := NewLocalStackLogsEgressAPI(logCollector) |
178 | | - tracer := NewLocalStackTracer() |
179 | | - |
180 | | - // build sandbox |
181 | | - sandbox := rapidcore. |
182 | | - NewSandboxBuilder(). |
183 | | - //SetTracer(tracer). |
184 | | - AddShutdownFunc(func() { |
185 | | - log.Debugln("Stopping file watcher") |
186 | | - cancelFileWatcher() |
187 | | - }). |
188 | | - SetExtensionsFlag(true). |
189 | | - SetInitCachingFlag(true). |
190 | | - SetLogsEgressAPI(localStackLogsEgressApi). |
191 | | - SetTracer(tracer) |
192 | | - |
193 | | - // Corresponds to the 'AWS_LAMBDA_RUNTIME_API' environment variable. |
194 | | - // We need to ensure the runtime server is up before the INIT phase, |
195 | | - // but this envar is only set after the InitHandler is called. |
196 | | - runtimeAPIAddress := "127.0.0.1:9001" |
197 | | - sandbox.SetRuntimeAPIAddress(runtimeAPIAddress) |
198 | | - |
199 | | - // xray daemon |
200 | | - endpoint := "http://" + lsOpts.LocalstackIP + ":" + lsOpts.EdgePort |
201 | | - xrayConfig := initConfig(endpoint, xRayLogLevel) |
202 | | - d := initDaemon(xrayConfig, lsOpts.EnableXRayTelemetry == "1") |
203 | | - sandbox.AddShutdownFunc(func() { |
204 | | - log.Debugln("Shutting down xray daemon") |
205 | | - d.stop() |
206 | | - log.Debugln("Flushing segments in xray daemon") |
207 | | - d.close() |
208 | | - }) |
209 | | - runDaemon(d) // async |
210 | | - |
211 | | - defaultInterop := sandbox.DefaultInteropServer() |
212 | | - interopServer := NewCustomInteropServer(lsOpts, defaultInterop, logCollector) |
213 | | - sandbox.SetInteropServer(interopServer) |
214 | | - if len(handler) > 0 { |
215 | | - sandbox.SetHandler(handler) |
216 | | - } |
217 | | - exitChan := make(chan struct{}) |
218 | | - sandbox.AddShutdownFunc(func() { |
219 | | - exitChan <- struct{}{} |
220 | | - }) |
221 | | - |
222 | | - // initialize all flows and start runtime API |
223 | | - sandboxContext, internalStateFn := sandbox.Create() |
224 | | - // Populate our custom interop server |
225 | | - interopServer.SetSandboxContext(sandboxContext) |
226 | | - interopServer.SetInternalStateGetter(internalStateFn) |
227 | | - |
228 | | - // get timeout |
229 | | - invokeTimeoutEnv := GetEnvOrDie("AWS_LAMBDA_FUNCTION_TIMEOUT") // TODO: collect all AWS_* env parsing |
230 | | - invokeTimeoutSeconds, err := strconv.Atoi(invokeTimeoutEnv) |
231 | | - if err != nil { |
232 | | - log.Fatalln(err) |
233 | | - } |
234 | | - go RunHotReloadingListener(interopServer, lsOpts.HotReloadingPaths, fileWatcherContext, lsOpts.FileWatcherStrategy) |
235 | | - |
236 | | - log.Debugf("Awaiting initialization of runtime api at %s.", runtimeAPIAddress) |
237 | | - // Fixes https://github.com/localstack/localstack/issues/12680 |
238 | | - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) |
239 | | - if err := waitForRuntimeAPI(ctx, runtimeAPIAddress); err != nil { |
240 | | - log.Fatalf("Lambda Runtime API server at %s did not come up in 30s, with error %s", runtimeAPIAddress, err.Error()) |
241 | | - } |
242 | | - cancel() |
243 | | - |
244 | | - // start runtime init. It is important to start `InitHandler` synchronously because we need to ensure the |
245 | | - // notification channels and status fields are properly initialized before `AwaitInitialized` |
246 | | - log.Debugln("Starting runtime init.") |
247 | | - InitHandler(sandbox.LambdaInvokeAPI(), GetEnvOrDie("AWS_LAMBDA_FUNCTION_VERSION"), int64(invokeTimeoutSeconds), bootstrap, lsOpts.AccountId) // TODO: replace this with a custom init |
248 | | - |
249 | | - log.Debugln("Awaiting initialization of runtime init.") |
250 | | - if err := interopServer.delegate.AwaitInitialized(); err != nil { |
251 | | - // Error cases: ErrInitDoneFailed or ErrInitResetReceived |
252 | | - log.Errorln("Runtime init failed to initialize: " + err.Error() + ". Exiting.") |
253 | | - // NOTE: Sending the error status to LocalStack is handled beforehand in the custom_interop.go through the |
254 | | - // callback SendInitErrorResponse because it contains the correct error response payload. |
255 | | - return |
| 166 | +func slogLevelFromString(logLevel string) slog.Level { |
| 167 | + switch logLevel { |
| 168 | + case "trace", "debug": |
| 169 | + return slog.LevelDebug |
| 170 | + case "info": |
| 171 | + return slog.LevelInfo |
| 172 | + case "warn": |
| 173 | + return slog.LevelWarn |
| 174 | + case "error", "fatal", "panic": |
| 175 | + return slog.LevelError |
| 176 | + default: |
| 177 | + return slog.LevelInfo |
256 | 178 | } |
| 179 | +} |
257 | 180 |
|
258 | | - log.Debugln("Completed initialization of runtime init. Sending status ready to LocalStack.") |
259 | | - if err := interopServer.localStackAdapter.SendStatus(Ready, []byte{}); err != nil { |
260 | | - log.Fatalln("Failed to send status ready to LocalStack " + err.Error() + ". Exiting.") |
| 181 | +func getXRayLogLevel(initLogLevel string) string { |
| 182 | + switch initLogLevel { |
| 183 | + case "trace", "debug": |
| 184 | + return "debug" |
| 185 | + case "warn": |
| 186 | + return "warn" |
| 187 | + case "error", "fatal", "panic": |
| 188 | + return "error" |
| 189 | + default: |
| 190 | + return "info" |
261 | 191 | } |
262 | | - |
263 | | - <-exitChan |
264 | 192 | } |
0 commit comments