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