github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/client/driver/env/env.go (about)

     1  package env
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strconv"
     7  	"strings"
     8  
     9  	hargs "github.com/hashicorp/nomad/helper/args"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  )
    12  
    13  // A set of environment variables that are exported by each driver.
    14  const (
    15  	// AllocDir is the environment variable with the path to the alloc directory
    16  	// that is shared across tasks within a task group.
    17  	AllocDir = "NOMAD_ALLOC_DIR"
    18  
    19  	// TaskLocalDir is the environment variable with the path to the tasks local
    20  	// directory where it can store data that is persisted to the alloc is
    21  	// removed.
    22  	TaskLocalDir = "NOMAD_TASK_DIR"
    23  
    24  	// MemLimit is the environment variable with the tasks memory limit in MBs.
    25  	MemLimit = "NOMAD_MEMORY_LIMIT"
    26  
    27  	// CpuLimit is the environment variable with the tasks CPU limit in MHz.
    28  	CpuLimit = "NOMAD_CPU_LIMIT"
    29  
    30  	// AllocID is the environment variable for passing the allocation ID.
    31  	AllocID = "NOMAD_ALLOC_ID"
    32  
    33  	// AllocName is the environment variable for passing the allocation name.
    34  	AllocName = "NOMAD_ALLOC_NAME"
    35  
    36  	// TaskName is the environment variable for passing the task name.
    37  	TaskName = "NOMAD_TASK_NAME"
    38  
    39  	// AllocIndex is the environment variable for passing the allocation index.
    40  	AllocIndex = "NOMAD_ALLOC_INDEX"
    41  
    42  	// AddrPrefix is the prefix for passing both dynamic and static port
    43  	// allocations to tasks.
    44  	// E.g$NOMAD_ADDR_http=127.0.0.1:80
    45  	AddrPrefix = "NOMAD_ADDR_"
    46  
    47  	// IpPrefix is the prefix for passing the IP of a port allocation to a task.
    48  	IpPrefix = "NOMAD_IP_"
    49  
    50  	// PortPrefix is the prefix for passing the port allocation to a task.
    51  	PortPrefix = "NOMAD_PORT_"
    52  
    53  	// HostPortPrefix is the prefix for passing the host port when a portmap is
    54  	// specified.
    55  	HostPortPrefix = "NOMAD_HOST_PORT_"
    56  
    57  	// MetaPrefix is the prefix for passing task meta data.
    58  	MetaPrefix = "NOMAD_META_"
    59  )
    60  
    61  // The node values that can be interpreted.
    62  const (
    63  	nodeIdKey    = "node.unique.id"
    64  	nodeDcKey    = "node.datacenter"
    65  	nodeNameKey  = "node.unique.name"
    66  	nodeClassKey = "node.class"
    67  
    68  	// Prefixes used for lookups.
    69  	nodeAttributePrefix = "attr."
    70  	nodeMetaPrefix      = "meta."
    71  )
    72  
    73  // TaskEnvironment is used to expose information to a task via environment
    74  // variables and provide interpolation of Nomad variables.
    75  type TaskEnvironment struct {
    76  	Env           map[string]string
    77  	TaskMeta      map[string]string
    78  	TaskGroupMeta map[string]string
    79  	JobMeta       map[string]string
    80  	AllocDir      string
    81  	TaskDir       string
    82  	CpuLimit      int
    83  	MemLimit      int
    84  	TaskName      string
    85  	AllocIndex    int
    86  	AllocId       string
    87  	AllocName     string
    88  	Node          *structs.Node
    89  	Networks      []*structs.NetworkResource
    90  	PortMap       map[string]int
    91  
    92  	// taskEnv is the variables that will be set in the tasks environment
    93  	TaskEnv map[string]string
    94  
    95  	// nodeValues is the values that are allowed for interprolation from the
    96  	// node.
    97  	NodeValues map[string]string
    98  }
    99  
   100  func NewTaskEnvironment(node *structs.Node) *TaskEnvironment {
   101  	return &TaskEnvironment{Node: node, AllocIndex: -1}
   102  }
   103  
   104  // ParseAndReplace takes the user supplied args replaces any instance of an
   105  // environment variable or nomad variable in the args with the actual value.
   106  func (t *TaskEnvironment) ParseAndReplace(args []string) []string {
   107  	replaced := make([]string, len(args))
   108  	for i, arg := range args {
   109  		replaced[i] = hargs.ReplaceEnv(arg, t.TaskEnv, t.NodeValues)
   110  	}
   111  
   112  	return replaced
   113  }
   114  
   115  // ReplaceEnv takes an arg and replaces all occurrences of environment variables
   116  // and nomad variables.  If the variable is found in the passed map it is
   117  // replaced, otherwise the original string is returned.
   118  func (t *TaskEnvironment) ReplaceEnv(arg string) string {
   119  	return hargs.ReplaceEnv(arg, t.TaskEnv, t.NodeValues)
   120  }
   121  
   122  // Build must be called after all the tasks environment values have been set.
   123  func (t *TaskEnvironment) Build() *TaskEnvironment {
   124  	t.NodeValues = make(map[string]string)
   125  	t.TaskEnv = make(map[string]string)
   126  
   127  	// Build the meta with the following precedence: task, task group, job.
   128  	for _, meta := range []map[string]string{t.JobMeta, t.TaskGroupMeta, t.TaskMeta} {
   129  		for k, v := range meta {
   130  			t.TaskEnv[fmt.Sprintf("%s%s", MetaPrefix, strings.ToUpper(k))] = v
   131  		}
   132  	}
   133  
   134  	// Build the ports
   135  	for _, network := range t.Networks {
   136  		for label, value := range network.MapLabelToValues(t.PortMap) {
   137  			IPPort := fmt.Sprintf("%s:%d", network.IP, value)
   138  			t.TaskEnv[fmt.Sprintf("%s%s", AddrPrefix, label)] = IPPort
   139  			t.TaskEnv[fmt.Sprintf("%s%s", IpPrefix, label)] = network.IP
   140  			t.TaskEnv[fmt.Sprintf("%s%s", PortPrefix, label)] = fmt.Sprintf("%d", value)
   141  
   142  			// Pass an explicit port mapping to the environment
   143  			if port, ok := t.PortMap[label]; ok {
   144  				t.TaskEnv[fmt.Sprintf("%s%s", HostPortPrefix, label)] = strconv.Itoa(port)
   145  			}
   146  		}
   147  	}
   148  
   149  	// Build the directories
   150  	if t.AllocDir != "" {
   151  		t.TaskEnv[AllocDir] = t.AllocDir
   152  	}
   153  	if t.TaskDir != "" {
   154  		t.TaskEnv[TaskLocalDir] = t.TaskDir
   155  	}
   156  
   157  	// Build the resource limits
   158  	if t.MemLimit != 0 {
   159  		t.TaskEnv[MemLimit] = strconv.Itoa(t.MemLimit)
   160  	}
   161  	if t.CpuLimit != 0 {
   162  		t.TaskEnv[CpuLimit] = strconv.Itoa(t.CpuLimit)
   163  	}
   164  
   165  	// Build the tasks ids
   166  	if t.AllocId != "" {
   167  		t.TaskEnv[AllocID] = t.AllocId
   168  	}
   169  	if t.AllocName != "" {
   170  		t.TaskEnv[AllocName] = t.AllocName
   171  	}
   172  	if t.AllocIndex != -1 {
   173  		t.TaskEnv[AllocIndex] = strconv.Itoa(t.AllocIndex)
   174  	}
   175  	if t.TaskName != "" {
   176  		t.TaskEnv[TaskName] = t.TaskName
   177  	}
   178  
   179  	// Build the node
   180  	if t.Node != nil {
   181  		// Set up the node values.
   182  		t.NodeValues[nodeIdKey] = t.Node.ID
   183  		t.NodeValues[nodeDcKey] = t.Node.Datacenter
   184  		t.NodeValues[nodeNameKey] = t.Node.Name
   185  		t.NodeValues[nodeClassKey] = t.Node.NodeClass
   186  
   187  		// Set up the attributes.
   188  		for k, v := range t.Node.Attributes {
   189  			t.NodeValues[fmt.Sprintf("%s%s", nodeAttributePrefix, k)] = v
   190  		}
   191  
   192  		// Set up the meta.
   193  		for k, v := range t.Node.Meta {
   194  			t.NodeValues[fmt.Sprintf("%s%s", nodeMetaPrefix, k)] = v
   195  		}
   196  	}
   197  
   198  	// Interpret the environment variables
   199  	interpreted := make(map[string]string, len(t.Env))
   200  	for k, v := range t.Env {
   201  		interpreted[k] = hargs.ReplaceEnv(v, t.NodeValues, t.TaskEnv)
   202  	}
   203  
   204  	for k, v := range interpreted {
   205  		t.TaskEnv[k] = v
   206  	}
   207  
   208  	return t
   209  }
   210  
   211  // EnvList returns a list of strings with NAME=value pairs.
   212  func (t *TaskEnvironment) EnvList() []string {
   213  	env := []string{}
   214  	for k, v := range t.TaskEnv {
   215  		env = append(env, fmt.Sprintf("%s=%s", k, v))
   216  	}
   217  
   218  	return env
   219  }
   220  
   221  // EnvMap returns a copy of the tasks environment variables.
   222  func (t *TaskEnvironment) EnvMap() map[string]string {
   223  	m := make(map[string]string, len(t.TaskEnv))
   224  	for k, v := range t.TaskEnv {
   225  		m[k] = v
   226  	}
   227  
   228  	return m
   229  }
   230  
   231  // Builder methods to build the TaskEnvironment
   232  func (t *TaskEnvironment) SetAllocDir(dir string) *TaskEnvironment {
   233  	t.AllocDir = dir
   234  	return t
   235  }
   236  
   237  func (t *TaskEnvironment) ClearAllocDir() *TaskEnvironment {
   238  	t.AllocDir = ""
   239  	return t
   240  }
   241  
   242  func (t *TaskEnvironment) SetTaskLocalDir(dir string) *TaskEnvironment {
   243  	t.TaskDir = dir
   244  	return t
   245  }
   246  
   247  func (t *TaskEnvironment) ClearTaskLocalDir() *TaskEnvironment {
   248  	t.TaskDir = ""
   249  	return t
   250  }
   251  
   252  func (t *TaskEnvironment) SetMemLimit(limit int) *TaskEnvironment {
   253  	t.MemLimit = limit
   254  	return t
   255  }
   256  
   257  func (t *TaskEnvironment) ClearMemLimit() *TaskEnvironment {
   258  	t.MemLimit = 0
   259  	return t
   260  }
   261  
   262  func (t *TaskEnvironment) SetCpuLimit(limit int) *TaskEnvironment {
   263  	t.CpuLimit = limit
   264  	return t
   265  }
   266  
   267  func (t *TaskEnvironment) ClearCpuLimit() *TaskEnvironment {
   268  	t.CpuLimit = 0
   269  	return t
   270  }
   271  
   272  func (t *TaskEnvironment) SetNetworks(networks []*structs.NetworkResource) *TaskEnvironment {
   273  	t.Networks = networks
   274  	return t
   275  }
   276  
   277  func (t *TaskEnvironment) clearNetworks() *TaskEnvironment {
   278  	t.Networks = nil
   279  	return t
   280  }
   281  
   282  func (t *TaskEnvironment) SetPortMap(portMap map[string]int) *TaskEnvironment {
   283  	t.PortMap = portMap
   284  	return t
   285  }
   286  
   287  func (t *TaskEnvironment) clearPortMap() *TaskEnvironment {
   288  	t.PortMap = nil
   289  	return t
   290  }
   291  
   292  // Takes a map of meta values to be passed to the task. The keys are capatilized
   293  // when the environent variable is set.
   294  func (t *TaskEnvironment) SetTaskMeta(m map[string]string) *TaskEnvironment {
   295  	t.TaskMeta = m
   296  	return t
   297  }
   298  
   299  func (t *TaskEnvironment) ClearTaskMeta() *TaskEnvironment {
   300  	t.TaskMeta = nil
   301  	return t
   302  }
   303  
   304  func (t *TaskEnvironment) SetTaskGroupMeta(m map[string]string) *TaskEnvironment {
   305  	t.TaskGroupMeta = m
   306  	return t
   307  }
   308  
   309  func (t *TaskEnvironment) ClearTaskGroupMeta() *TaskEnvironment {
   310  	t.TaskGroupMeta = nil
   311  	return t
   312  }
   313  
   314  func (t *TaskEnvironment) SetJobMeta(m map[string]string) *TaskEnvironment {
   315  	t.JobMeta = m
   316  	return t
   317  }
   318  
   319  func (t *TaskEnvironment) ClearJobMeta() *TaskEnvironment {
   320  	t.JobMeta = nil
   321  	return t
   322  }
   323  
   324  func (t *TaskEnvironment) SetEnvvars(m map[string]string) *TaskEnvironment {
   325  	t.Env = m
   326  	return t
   327  }
   328  
   329  // Appends the given environment variables.
   330  func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment {
   331  	if t.Env == nil {
   332  		t.Env = make(map[string]string, len(m))
   333  	}
   334  
   335  	for k, v := range m {
   336  		t.Env[k] = v
   337  	}
   338  	return t
   339  }
   340  
   341  // AppendHostEnvvars adds the host environment variables to the tasks. The
   342  // filter parameter can be use to filter host environment from entering the
   343  // tasks.
   344  func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment {
   345  	hostEnv := os.Environ()
   346  	if t.Env == nil {
   347  		t.Env = make(map[string]string, len(hostEnv))
   348  	}
   349  
   350  	// Index the filtered environment variables.
   351  	index := make(map[string]struct{}, len(filter))
   352  	for _, f := range filter {
   353  		index[f] = struct{}{}
   354  	}
   355  
   356  	for _, e := range hostEnv {
   357  		parts := strings.SplitN(e, "=", 2)
   358  		key, value := parts[0], parts[1]
   359  
   360  		// Skip filtered environment variables
   361  		if _, filtered := index[key]; filtered {
   362  			continue
   363  		}
   364  
   365  		// Don't override the tasks environment variables.
   366  		if _, existing := t.Env[key]; !existing {
   367  			t.Env[key] = value
   368  		}
   369  	}
   370  
   371  	return t
   372  }
   373  
   374  func (t *TaskEnvironment) ClearEnvvars() *TaskEnvironment {
   375  	t.Env = nil
   376  	return t
   377  }
   378  
   379  // Helper method for setting all fields from an allocation.
   380  func (t *TaskEnvironment) SetAlloc(alloc *structs.Allocation) *TaskEnvironment {
   381  	t.AllocId = alloc.ID
   382  	t.AllocName = alloc.Name
   383  	t.AllocIndex = alloc.Index()
   384  	return t
   385  }
   386  
   387  // Helper method for clearing all fields from an allocation.
   388  func (t *TaskEnvironment) ClearAlloc(alloc *structs.Allocation) *TaskEnvironment {
   389  	return t.ClearAllocId().ClearAllocName().ClearAllocIndex()
   390  }
   391  
   392  func (t *TaskEnvironment) SetAllocIndex(index int) *TaskEnvironment {
   393  	t.AllocIndex = index
   394  	return t
   395  }
   396  
   397  func (t *TaskEnvironment) ClearAllocIndex() *TaskEnvironment {
   398  	t.AllocIndex = -1
   399  	return t
   400  }
   401  
   402  func (t *TaskEnvironment) SetAllocId(id string) *TaskEnvironment {
   403  	t.AllocId = id
   404  	return t
   405  }
   406  
   407  func (t *TaskEnvironment) ClearAllocId() *TaskEnvironment {
   408  	t.AllocId = ""
   409  	return t
   410  }
   411  
   412  func (t *TaskEnvironment) SetAllocName(name string) *TaskEnvironment {
   413  	t.AllocName = name
   414  	return t
   415  }
   416  
   417  func (t *TaskEnvironment) ClearAllocName() *TaskEnvironment {
   418  	t.AllocName = ""
   419  	return t
   420  }
   421  
   422  func (t *TaskEnvironment) SetTaskName(name string) *TaskEnvironment {
   423  	t.TaskName = name
   424  	return t
   425  }
   426  
   427  func (t *TaskEnvironment) ClearTaskName() *TaskEnvironment {
   428  	t.TaskName = ""
   429  	return t
   430  }