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