wings/environment/settings.go
Dane Everitt cc52954a2a
Refactor environment handling logic to separate a server from the environment handler itself
This change makes the environment handling logic execute independent of the server itself and should make it much easier for people to contribute changes and additional environment handlers down the road without polluting the server object even more.

There is still a lot of work to do on this front to make things easier to work with, and there are some questionable design decisions at play I'm sure.

Welcome to additional modifications and cleanup to make this code easier to reason about and work with.
2020-08-10 21:38:42 -07:00

125 lines
4.2 KiB
Go

package environment
import (
"fmt"
"math"
"strconv"
)
type Mount struct {
// In Docker environments this makes no difference, however in a non-Docker environment you
// should treat the "Default" mount as the root directory for the server. All other mounts
// are just in addition to that one, and generally things like shared maps or timezone data.
Default bool `json:"-"`
// The target path on the system. This is "/home/container" for all server's Default mount
// but in non-container environments you can likely ignore the target and just work with the
// source.
Target string `json:"target"`
// The directory from which the files will be read. In Docker environments this is the directory
// that we're mounting into the container at the Target location.
Source string `json:"source"`
// Wether or not the directory is being mounted as read-only. It is up to the environment to
// handle this value correctly and ensure security expectations are met with its usage.
ReadOnly bool `json:"read_only"`
}
// The build settings for a given server that impact docker container creation and
// resource limits for a server instance.
type Limits struct {
// The total amount of memory in megabytes that this server is allowed to
// use on the host system.
MemoryLimit int64 `json:"memory_limit"`
// The amount of additional swap space to be provided to a container instance.
Swap int64 `json:"swap"`
// The relative weight for IO operations in a container. This is relative to other
// containers on the system and should be a value between 10 and 1000.
IoWeight uint16 `json:"io_weight"`
// The percentage of CPU that this instance is allowed to consume relative to
// the host. A value of 200% represents complete utilization of two cores. This
// should be a value between 1 and THREAD_COUNT * 100.
CpuLimit int64 `json:"cpu_limit"`
// The amount of disk space in megabytes that a server is allowed to use.
DiskSpace int64 `json:"disk_space"`
// Sets which CPU threads can be used by the docker instance.
Threads string `json:"threads"`
OOMDisabled bool `json:"oom_disabled"`
}
// Converts the CPU limit for a server build into a number that can be better understood
// by the Docker environment. If there is no limit set, return -1 which will indicate to
// Docker that it has unlimited CPU quota.
func (r *Limits) ConvertedCpuLimit() int64 {
if r.CpuLimit == 0 {
return -1
}
return r.CpuLimit * 1000
}
// Set the hard limit for memory usage to be 5% more than the amount of memory assigned to
// the server. If the memory limit for the server is < 4G, use 10%, if less than 2G use
// 15%. This avoids unexpected crashes from processes like Java which run over the limit.
func (r *Limits) MemoryOverheadMultiplier() float64 {
if r.MemoryLimit <= 2048 {
return 1.15
} else if r.MemoryLimit <= 4096 {
return 1.10
}
return 1.05
}
func (r *Limits) BoundedMemoryLimit() int64 {
return int64(math.Round(float64(r.MemoryLimit) * r.MemoryOverheadMultiplier() * 1_000_000))
}
// Returns the amount of swap available as a total in bytes. This is returned as the amount
// of memory available to the server initially, PLUS the amount of additional swap to include
// which is the format used by Docker.
func (r *Limits) ConvertedSwap() int64 {
if r.Swap < 0 {
return -1
}
return (r.Swap * 1_000_000) + r.BoundedMemoryLimit()
}
type Variables map[string]interface{}
// Ugly hacky function to handle environment variables that get passed through as not-a-string
// from the Panel. Ideally we'd just say only pass strings, but that is a fragile idea and if a
// string wasn't passed through you'd cause a crash or the server to become unavailable. For now
// try to handle the most likely values from the JSON and hope for the best.
func (v Variables) Get(key string) string {
val, ok := v[key]
if !ok {
return ""
}
switch val.(type) {
case int:
return strconv.Itoa(val.(int))
case int32:
return strconv.FormatInt(val.(int64), 10)
case int64:
return strconv.FormatInt(val.(int64), 10)
case float32:
return fmt.Sprintf("%f", val.(float32))
case float64:
return fmt.Sprintf("%f", val.(float64))
case bool:
return strconv.FormatBool(val.(bool))
}
return val.(string)
}