lambda/rapidcore/env/environment.go (125 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package env
import (
"fmt"
"os"
"strings"
log "github.com/sirupsen/logrus"
)
const runtimeAPIAddressKey = "AWS_LAMBDA_RUNTIME_API"
const handlerEnvKey = "_HANDLER"
const executionEnvKey = "AWS_EXECUTION_ENV"
const taskRootEnvKey = "LAMBDA_TASK_ROOT"
const runtimeDirEnvKey = "LAMBDA_RUNTIME_DIR"
// Environment holds env vars for runtime, agents, and for
// internal use, parsed during startup and from START msg
type Environment struct {
Customer map[string]string // customer & unreserved platform env vars, set on INIT
rapid map[string]string // env vars req'd internally by RAPID
platform map[string]string // reserved platform env vars as per Lambda docs
runtime map[string]string // reserved runtime env vars as per Lambda docs
platformUnreserved map[string]string // unreserved platform env vars that customers can override
credentials map[string]string // reserved env vars for credentials, set on INIT
runtimeAPISet bool
initEnvVarsSet bool
}
func lookupEnv(keys map[string]bool) map[string]string {
res := map[string]string{}
for key := range keys {
val, ok := os.LookupEnv(key)
if ok {
res[key] = val
}
}
return res
}
// NewEnvironment parses environment variables into an Environment object
func NewEnvironment() *Environment {
return &Environment{
rapid: lookupEnv(predefinedInternalEnvVarKeys()),
platform: lookupEnv(predefinedPlatformEnvVarKeys()),
runtime: lookupEnv(predefinedRuntimeEnvVarKeys()),
platformUnreserved: lookupEnv(predefinedPlatformUnreservedEnvVarKeys()),
Customer: map[string]string{},
credentials: map[string]string{},
runtimeAPISet: false,
initEnvVarsSet: false,
}
}
// StoreRuntimeAPIEnvironmentVariable stores value for AWS_LAMBDA_RUNTIME_API
func (e *Environment) StoreRuntimeAPIEnvironmentVariable(runtimeAPIAddress string) {
e.platform[runtimeAPIAddressKey] = runtimeAPIAddress
e.runtimeAPISet = true
}
// SetHandler sets _HANDLER env variable value for Runtime
func (e *Environment) SetHandler(handler string) {
e.runtime[handlerEnvKey] = handler
}
// GetExecutionEnv returns the current setting for AWS_EXECUTION_ENV
func (e *Environment) GetExecutionEnv() string {
return e.runtime[executionEnvKey]
}
// SetExecutionEnv sets AWS_EXECUTION_ENV variable value for Runtime
func (e *Environment) SetExecutionEnv(executionEnv string) {
e.runtime[executionEnvKey] = executionEnv
}
// SetTaskRoot sets the LAMBDA_TASK_ROOT environment variable for Runtime
func (e *Environment) SetTaskRoot(taskRoot string) {
e.runtime[taskRootEnvKey] = taskRoot
}
// SetRuntimeDir sets the LAMBDA_RUNTIME_DIR environment variable for Runtime
func (e *Environment) SetRuntimeDir(runtimeDir string) {
e.runtime[runtimeDirEnvKey] = runtimeDir
}
// StoreEnvironmentVariablesFromInit sets the environment variables
// for credentials & _HANDLER which are received in the START message
func (e *Environment) StoreEnvironmentVariablesFromInit(customerEnv map[string]string, handler, awsKey, awsSecret, awsSession, funcName, funcVer string) {
e.credentials["AWS_ACCESS_KEY_ID"] = awsKey
e.credentials["AWS_SECRET_ACCESS_KEY"] = awsSecret
e.credentials["AWS_SESSION_TOKEN"] = awsSession
e.storeNonCredentialEnvironmentVariablesFromInit(customerEnv, handler, funcName, funcVer)
}
func (e *Environment) StoreEnvironmentVariablesFromInitForInitCaching(host string, port int, customerEnv map[string]string, handler, funcName, funcVer, token string) {
e.credentials["AWS_CONTAINER_CREDENTIALS_FULL_URI"] = fmt.Sprintf("http://%s:%d/2021-04-23/credentials", host, port)
e.credentials["AWS_CONTAINER_AUTHORIZATION_TOKEN"] = token
e.storeNonCredentialEnvironmentVariablesFromInit(customerEnv, handler, funcName, funcVer)
}
func (e *Environment) storeNonCredentialEnvironmentVariablesFromInit(customerEnv map[string]string, handler, funcName, funcVer string) {
if handler != "" {
e.SetHandler(handler)
}
if funcName != "" {
e.platform["AWS_LAMBDA_FUNCTION_NAME"] = funcName
}
if funcVer != "" {
e.platform["AWS_LAMBDA_FUNCTION_VERSION"] = funcVer
}
e.mergeCustomerEnvironmentVariables(customerEnv) // overrides env vars from CLI options
e.initEnvVarsSet = true
}
// StoreEnvironmentVariablesFromCLIOptions sets the environment
// variables received via a CLI flag, for example LCIS config
func (e *Environment) StoreEnvironmentVariablesFromCLIOptions(envVars map[string]string) {
e.mergeCustomerEnvironmentVariables(envVars)
}
// mergeCustomerEnvironmentVariables appends to customer env vars, overwriting entries if they exist
func (e *Environment) mergeCustomerEnvironmentVariables(envVars map[string]string) {
e.Customer = mapUnion(e.Customer, envVars)
}
// RuntimeExecEnv returns the key=value strings of all environment variables
// passed to runtime process on exec()
func (e *Environment) RuntimeExecEnv() map[string]string {
if !e.initEnvVarsSet || !e.runtimeAPISet {
log.Fatal("credentials, customer and runtime API address must be set")
}
return mapUnion(e.Customer, e.platformUnreserved, e.credentials, e.runtime, e.platform)
}
// AgentExecEnv returns the key=value strings of all environment variables
// passed to agent process on exec()
func (e *Environment) AgentExecEnv() map[string]string {
if !e.initEnvVarsSet || !e.runtimeAPISet {
log.Fatal("credentials, customer and runtime API address must be set")
}
excludedKeys := extensionExcludedKeys()
excludeCondition := func(key string) bool { return excludedKeys[key] || strings.HasPrefix(key, "_") }
return mapExclude(mapUnion(e.Customer, e.credentials, e.platform), excludeCondition)
}
func mapUnion(maps ...map[string]string) map[string]string {
// last maps in argument overwrite values of ones before
union := map[string]string{}
for _, m := range maps {
for key, val := range m {
union[key] = val
}
}
return union
}
func mapExclude(m map[string]string, excludeCondition func(string) bool) map[string]string {
res := map[string]string{}
for key, val := range m {
if !excludeCondition(key) {
res[key] = val
}
}
return res
}