open-nomad/client/driver/env/env.go

283 lines
6.8 KiB
Go

package env
import (
"fmt"
"strconv"
"strings"
hargs "github.com/hashicorp/nomad/helper/args"
"github.com/hashicorp/nomad/nomad/structs"
)
// A set of environment variables that are exported by each driver.
const (
// The path to the alloc directory that is shared across tasks within a task
// group.
AllocDir = "NOMAD_ALLOC_DIR"
// The path to the tasks local directory where it can store data that is
// persisted to the alloc is removed.
TaskLocalDir = "NOMAD_TASK_DIR"
// The tasks memory limit in MBs.
MemLimit = "NOMAD_MEMORY_LIMIT"
// The tasks limit in MHz.
CpuLimit = "NOMAD_CPU_LIMIT"
// The IP address for the task.
TaskIP = "NOMAD_IP"
// Prefix for passing both dynamic and static port allocations to
// tasks.
// E.g. $NOMAD_IP_1=127.0.0.1:1 or $NOMAD_IP_http=127.0.0.1:80
AddrPrefix = "NOMAD_ADDR_"
// Prefix for passing the host port when a portmap is specified.
HostPortPrefix = "NOMAD_HOST_PORT_"
// Prefix for passing task meta data.
MetaPrefix = "NOMAD_META_"
)
// The node values that can be interpreted.
const (
nodeIdKey = "node.unique.id"
nodeDcKey = "node.datacenter"
nodeNameKey = "node.unique.name"
nodeClassKey = "node.class"
// Prefixes used for lookups.
nodeAttributePrefix = "attr."
nodeMetaPrefix = "meta."
)
// TaskEnvironment is used to expose information to a task via environment
// variables and provide interpolation of Nomad variables.
type TaskEnvironment struct {
env map[string]string
meta map[string]string
allocDir string
taskDir string
cpuLimit int
memLimit int
node *structs.Node
networks []*structs.NetworkResource
portMap map[string]int
// taskEnv is the variables that will be set in the tasks environment
taskEnv map[string]string
// nodeValues is the values that are allowed for interprolation from the
// node.
nodeValues map[string]string
}
func NewTaskEnvironment(node *structs.Node) *TaskEnvironment {
return &TaskEnvironment{node: node}
}
// ParseAndReplace takes the user supplied args replaces any instance of an
// environment variable or nomad variable in the args with the actual value.
func (t *TaskEnvironment) ParseAndReplace(args []string) []string {
replaced := make([]string, len(args))
for i, arg := range args {
replaced[i] = hargs.ReplaceEnv(arg, t.taskEnv, t.nodeValues)
}
return replaced
}
// ReplaceEnv takes an arg and replaces all occurences of environment variables
// and nomad variables. If the variable is found in the passed map it is
// replaced, otherwise the original string is returned.
func (t *TaskEnvironment) ReplaceEnv(arg string) string {
return hargs.ReplaceEnv(arg, t.taskEnv, t.nodeValues)
}
// Build must be called after all the tasks environment values have been set.
func (t *TaskEnvironment) Build() *TaskEnvironment {
t.nodeValues = make(map[string]string)
t.taskEnv = make(map[string]string)
// Build the task metadata
for k, v := range t.meta {
t.taskEnv[fmt.Sprintf("%s%s", MetaPrefix, strings.ToUpper(k))] = v
}
// Build the ports
for _, network := range t.networks {
for label, value := range network.MapLabelToValues(t.portMap) {
IPPort := fmt.Sprintf("%s:%d", network.IP, value)
t.taskEnv[fmt.Sprintf("%s%s", AddrPrefix, label)] = IPPort
// Pass an explicit port mapping to the environment
if port, ok := t.portMap[label]; ok {
t.taskEnv[fmt.Sprintf("%s%s", HostPortPrefix, label)] = strconv.Itoa(port)
}
}
}
// Build the directories
if t.allocDir != "" {
t.taskEnv[AllocDir] = t.allocDir
}
if t.taskDir != "" {
t.taskEnv[TaskLocalDir] = t.taskDir
}
// Build the resource limits
if t.memLimit != 0 {
t.taskEnv[MemLimit] = strconv.Itoa(t.memLimit)
}
if t.cpuLimit != 0 {
t.taskEnv[CpuLimit] = strconv.Itoa(t.cpuLimit)
}
// Build the node
if t.node != nil {
// Set up the node values.
t.nodeValues[nodeIdKey] = t.node.ID
t.nodeValues[nodeDcKey] = t.node.Datacenter
t.nodeValues[nodeNameKey] = t.node.Name
t.nodeValues[nodeClassKey] = t.node.NodeClass
// Set up the attributes.
for k, v := range t.node.Attributes {
t.nodeValues[fmt.Sprintf("%s%s", nodeAttributePrefix, k)] = v
}
// Set up the meta.
for k, v := range t.node.Meta {
t.nodeValues[fmt.Sprintf("%s%s", nodeMetaPrefix, k)] = v
}
}
// Interpret the environment variables
interpreted := make(map[string]string, len(t.env))
for k, v := range t.env {
interpreted[k] = hargs.ReplaceEnv(v, t.nodeValues, t.taskEnv)
}
for k, v := range interpreted {
t.taskEnv[k] = v
}
return t
}
// EnvList returns a list of strings with NAME=value pairs.
func (t *TaskEnvironment) EnvList() []string {
env := []string{}
for k, v := range t.taskEnv {
env = append(env, fmt.Sprintf("%s=%s", k, v))
}
return env
}
// EnvMap returns a copy of the tasks environment variables.
func (t *TaskEnvironment) EnvMap() map[string]string {
m := make(map[string]string, len(t.taskEnv))
for k, v := range t.taskEnv {
m[k] = v
}
return m
}
// Builder methods to build the TaskEnvironment
func (t *TaskEnvironment) SetAllocDir(dir string) *TaskEnvironment {
t.allocDir = dir
return t
}
func (t *TaskEnvironment) ClearAllocDir() *TaskEnvironment {
t.allocDir = ""
return t
}
func (t *TaskEnvironment) SetTaskLocalDir(dir string) *TaskEnvironment {
t.taskDir = dir
return t
}
func (t *TaskEnvironment) ClearTaskLocalDir() *TaskEnvironment {
t.taskDir = ""
return t
}
func (t *TaskEnvironment) SetMemLimit(limit int) *TaskEnvironment {
t.memLimit = limit
return t
}
func (t *TaskEnvironment) ClearMemLimit() *TaskEnvironment {
t.memLimit = 0
return t
}
func (t *TaskEnvironment) SetCpuLimit(limit int) *TaskEnvironment {
t.cpuLimit = limit
return t
}
func (t *TaskEnvironment) ClearCpuLimit() *TaskEnvironment {
t.cpuLimit = 0
return t
}
func (t *TaskEnvironment) SetNetworks(networks []*structs.NetworkResource) *TaskEnvironment {
t.networks = networks
return t
}
func (t *TaskEnvironment) clearNetworks() *TaskEnvironment {
t.networks = nil
return t
}
func (t *TaskEnvironment) SetPortMap(portMap map[string]int) *TaskEnvironment {
t.portMap = portMap
return t
}
func (t *TaskEnvironment) clearPortMap() *TaskEnvironment {
t.portMap = nil
return t
}
// Takes a map of meta values to be passed to the task. The keys are capatilized
// when the environent variable is set.
func (t *TaskEnvironment) SetMeta(m map[string]string) *TaskEnvironment {
t.meta = m
return t
}
func (t *TaskEnvironment) ClearMeta() *TaskEnvironment {
t.meta = nil
return t
}
func (t *TaskEnvironment) SetEnvvars(m map[string]string) *TaskEnvironment {
t.env = m
return t
}
// Appends the given environment variables.
func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment {
if t.env == nil {
t.env = make(map[string]string, len(m))
}
for k, v := range m {
t.env[k] = v
}
return t
}
func (t *TaskEnvironment) ClearEnvvars() *TaskEnvironment {
t.env = nil
return t
}