mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
202 lines
8.6 KiB
Go
202 lines
8.6 KiB
Go
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// Config specifies various settings for an agent
|
|
type Config struct {
|
|
MinDockerVersion string `json:"min_docker_version"`
|
|
DockerNetworks string `json:"docker_networks"`
|
|
DockerLoadFile string `json:"docker_load_file"`
|
|
FreezeIdle time.Duration `json:"freeze_idle_msecs"`
|
|
EjectIdle time.Duration `json:"eject_idle_msecs"`
|
|
HotPoll time.Duration `json:"hot_poll_msecs"`
|
|
HotLauncherTimeout time.Duration `json:"hot_launcher_timeout_msecs"`
|
|
AsyncChewPoll time.Duration `json:"async_chew_poll_msecs"`
|
|
CallEndTimeout time.Duration `json:"call_end_timeout"`
|
|
MaxCallEndStacking uint64 `json:"max_call_end_stacking"`
|
|
MaxResponseSize uint64 `json:"max_response_size_bytes"`
|
|
MaxRequestSize uint64 `json:"max_request_size_bytes"`
|
|
MaxLogSize uint64 `json:"max_log_size_bytes"`
|
|
MaxTotalCPU uint64 `json:"max_total_cpu_mcpus"`
|
|
MaxTotalMemory uint64 `json:"max_total_memory_bytes"`
|
|
MaxFsSize uint64 `json:"max_fs_size_mb"`
|
|
PreForkPoolSize uint64 `json:"pre_fork_pool_size"`
|
|
PreForkImage string `json:"pre_fork_image"`
|
|
PreForkCmd string `json:"pre_fork_pool_cmd"`
|
|
PreForkUseOnce uint64 `json:"pre_fork_use_once"`
|
|
PreForkNetworks string `json:"pre_fork_networks"`
|
|
EnableNBResourceTracker bool `json:"enable_nb_resource_tracker"`
|
|
MaxTmpFsInodes uint64 `json:"max_tmpfs_inodes"`
|
|
DisableReadOnlyRootFs bool `json:"disable_readonly_rootfs"`
|
|
}
|
|
|
|
const (
|
|
// EnvDockerNetworks is a comma separated list of networks to attach to each container started
|
|
EnvDockerNetworks = "FN_DOCKER_NETWORKS"
|
|
// EnvDockerLoadFile is a file location for a file that contains a tarball of a docker image to load on startup
|
|
EnvDockerLoadFile = "FN_DOCKER_LOAD_FILE"
|
|
// EnvFreezeIdle is the delay between a container being last used and being frozen
|
|
EnvFreezeIdle = "FN_FREEZE_IDLE_MSECS"
|
|
// EnvEjectIdle is the delay before allowing an idle container to be evictable if another container
|
|
// requests the space for itself
|
|
EnvEjectIdle = "FN_EJECT_IDLE_MSECS"
|
|
// EnvHotPoll is the interval to ping for a slot manager thread to check if a container should be
|
|
// launched for a given function
|
|
EnvHotPoll = "FN_HOT_POLL_MSECS"
|
|
// EnvHotLauncherTimeout is the timeout for a hot container to become available for use
|
|
EnvHotLauncherTimeout = "FN_HOT_LAUNCHER_TIMEOUT_MSECS"
|
|
// EnvAsyncChewPoll is the interval to poll the queue that contains async function invocations
|
|
EnvAsyncChewPoll = "FN_ASYNC_CHEW_POLL_MSECS"
|
|
// EnvCallEndTimeout is the timeout after a call is completed to store information about that invocation
|
|
EnvCallEndTimeout = "FN_CALL_END_TIMEOUT_MSECS"
|
|
// EnvMaxCallEndStacking is the maximum number of concurrent calls in call.End storing info
|
|
EnvMaxCallEndStacking = "FN_MAX_CALL_END_STACKING"
|
|
// EnvMaxResponseSize is the maximum number of bytes that a function may return from an invocation
|
|
EnvMaxResponseSize = "FN_MAX_RESPONSE_SIZE"
|
|
// EnvMaxRequestSize is the maximum request size that may be passed to an agent TODO kill me from here
|
|
EnvMaxRequestSize = "FN_MAX_REQUEST_SIZE"
|
|
// EnvMaxLogSize is the maximum size that a function's log may reach
|
|
EnvMaxLogSize = "FN_MAX_LOG_SIZE_BYTES"
|
|
// EnvMaxTotalCPU is the maximum CPU that will be reserved across all containers
|
|
EnvMaxTotalCPU = "FN_MAX_TOTAL_CPU_MCPUS"
|
|
// EnvMaxTotalMemory is the maximum memory that will be reserved across all containers
|
|
EnvMaxTotalMemory = "FN_MAX_TOTAL_MEMORY_BYTES"
|
|
// EnvMaxFsSize is the maximum filesystem size that a function may use
|
|
EnvMaxFsSize = "FN_MAX_FS_SIZE_MB"
|
|
// EnvPreForkPoolSize is the number of containers pooled to steal network from, this may reduce latency
|
|
EnvPreForkPoolSize = "FN_EXPERIMENTAL_PREFORK_POOL_SIZE"
|
|
// EnvPreForkImage is the image to use for the pre-fork pool
|
|
EnvPreForkImage = "FN_EXPERIMENTAL_PREFORK_IMAGE"
|
|
// EnvPreForkCmd is the command to run for images in the pre-fork pool, it should run for a long time
|
|
EnvPreForkCmd = "FN_EXPERIMENTAL_PREFORK_CMD"
|
|
// EnvPreForkUseOnce limits the number of times a pre-fork pool container may be used to one, they are otherwise recycled
|
|
EnvPreForkUseOnce = "FN_EXPERIMENTAL_PREFORK_USE_ONCE"
|
|
// EnvPreForkNetworks is the equivalent of EnvDockerNetworks but for pre-fork pool containers
|
|
EnvPreForkNetworks = "FN_EXPERIMENTAL_PREFORK_NETWORKS"
|
|
// EnvEnableNBResourceTracker makes every request to the resource tracker non-blocking, meaning the resources are either
|
|
// available or it will return an error immediately
|
|
EnvEnableNBResourceTracker = "FN_ENABLE_NB_RESOURCE_TRACKER"
|
|
// EnvMaxTmpFsInodes is the maximum number of inodes for /tmp in a container
|
|
EnvMaxTmpFsInodes = "FN_MAX_TMPFS_INODES"
|
|
// EnvDisableReadOnlyRootFs makes the root fs for a container have rw permissions, by default it is read only
|
|
EnvDisableReadOnlyRootFs = "FN_DISABLE_READONLY_ROOTFS"
|
|
|
|
// MaxMsDisabled is used to determine whether mr freeze is lying in wait. TODO remove this manuever
|
|
MaxMsDisabled = time.Duration(math.MaxInt64)
|
|
|
|
// defaults
|
|
|
|
// DefaultHotPoll is the default value for EnvHotPoll
|
|
DefaultHotPoll = 200 * time.Millisecond
|
|
)
|
|
|
|
// NewConfig returns a config set from env vars, plus defaults
|
|
func NewConfig() (*Config, error) {
|
|
|
|
cfg := &Config{
|
|
MinDockerVersion: "17.10.0-ce",
|
|
MaxLogSize: 1 * 1024 * 1024,
|
|
MaxCallEndStacking: 8192,
|
|
PreForkImage: "busybox",
|
|
PreForkCmd: "tail -f /dev/null",
|
|
}
|
|
|
|
var err error
|
|
|
|
err = setEnvMsecs(err, EnvFreezeIdle, &cfg.FreezeIdle, 50*time.Millisecond)
|
|
err = setEnvMsecs(err, EnvEjectIdle, &cfg.EjectIdle, 1000*time.Millisecond)
|
|
err = setEnvMsecs(err, EnvHotPoll, &cfg.HotPoll, DefaultHotPoll)
|
|
err = setEnvMsecs(err, EnvHotLauncherTimeout, &cfg.HotLauncherTimeout, time.Duration(60)*time.Minute)
|
|
err = setEnvMsecs(err, EnvAsyncChewPoll, &cfg.AsyncChewPoll, time.Duration(60)*time.Second)
|
|
err = setEnvMsecs(err, EnvCallEndTimeout, &cfg.CallEndTimeout, time.Duration(10)*time.Minute)
|
|
err = setEnvUint(err, EnvMaxResponseSize, &cfg.MaxResponseSize)
|
|
err = setEnvUint(err, EnvMaxRequestSize, &cfg.MaxRequestSize)
|
|
err = setEnvUint(err, EnvMaxLogSize, &cfg.MaxLogSize)
|
|
err = setEnvUint(err, EnvMaxTotalCPU, &cfg.MaxTotalCPU)
|
|
err = setEnvUint(err, EnvMaxTotalMemory, &cfg.MaxTotalMemory)
|
|
err = setEnvUint(err, EnvMaxFsSize, &cfg.MaxFsSize)
|
|
err = setEnvUint(err, EnvPreForkPoolSize, &cfg.PreForkPoolSize)
|
|
err = setEnvUint(err, EnvMaxCallEndStacking, &cfg.MaxCallEndStacking)
|
|
err = setEnvStr(err, EnvPreForkImage, &cfg.PreForkImage)
|
|
err = setEnvStr(err, EnvPreForkCmd, &cfg.PreForkCmd)
|
|
err = setEnvUint(err, EnvPreForkUseOnce, &cfg.PreForkUseOnce)
|
|
err = setEnvStr(err, EnvPreForkNetworks, &cfg.PreForkNetworks)
|
|
err = setEnvStr(err, EnvDockerNetworks, &cfg.DockerNetworks)
|
|
err = setEnvStr(err, EnvDockerLoadFile, &cfg.DockerLoadFile)
|
|
err = setEnvUint(err, EnvMaxTmpFsInodes, &cfg.MaxTmpFsInodes)
|
|
|
|
if err != nil {
|
|
return cfg, err
|
|
}
|
|
|
|
if _, ok := os.LookupEnv(EnvEnableNBResourceTracker); ok {
|
|
cfg.EnableNBResourceTracker = true
|
|
}
|
|
if _, ok := os.LookupEnv(EnvDisableReadOnlyRootFs); ok {
|
|
cfg.DisableReadOnlyRootFs = true
|
|
}
|
|
|
|
if cfg.EjectIdle == time.Duration(0) {
|
|
return cfg, fmt.Errorf("error %s cannot be zero", EnvEjectIdle)
|
|
}
|
|
if cfg.MaxLogSize > math.MaxInt64 {
|
|
// for safety during uint64 to int conversions in Write()/Read(), etc.
|
|
return cfg, fmt.Errorf("error invalid %s %v > %v", EnvMaxLogSize, cfg.MaxLogSize, math.MaxInt64)
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func setEnvStr(err error, name string, dst *string) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tmp, ok := os.LookupEnv(name); ok {
|
|
*dst = tmp
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setEnvUint(err error, name string, dst *uint64) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tmp := os.Getenv(name); tmp != "" {
|
|
val, err := strconv.ParseUint(tmp, 10, 64)
|
|
if err != nil {
|
|
return fmt.Errorf("error invalid %s=%s", name, tmp)
|
|
}
|
|
*dst = val
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func setEnvMsecs(err error, name string, dst *time.Duration, defaultVal time.Duration) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*dst = defaultVal
|
|
|
|
if dur := os.Getenv(name); dur != "" {
|
|
durInt, err := strconv.ParseInt(dur, 10, 64)
|
|
if err != nil {
|
|
return fmt.Errorf("error invalid %s=%s err=%s", name, dur, err)
|
|
}
|
|
// disable if negative or set to msecs specified.
|
|
if durInt < 0 || time.Duration(durInt) >= MaxMsDisabled/time.Millisecond {
|
|
*dst = MaxMsDisabled
|
|
} else {
|
|
*dst = time.Duration(durInt) * time.Millisecond
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|