github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/client/driver/env/env.go (about)

     1  package env
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/hashicorp/nomad/helper"
    11  	hargs "github.com/hashicorp/nomad/helper/args"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  )
    14  
    15  // A set of environment variables that are exported by each driver.
    16  const (
    17  	// AllocDir is the environment variable with the path to the alloc directory
    18  	// that is shared across tasks within a task group.
    19  	AllocDir = "NOMAD_ALLOC_DIR"
    20  
    21  	// TaskLocalDir is the environment variable with the path to the tasks local
    22  	// directory where it can store data that is persisted to the alloc is
    23  	// removed.
    24  	TaskLocalDir = "NOMAD_TASK_DIR"
    25  
    26  	// SecretsDir is the environment variable with the path to the tasks secret
    27  	// directory where it can store sensitive data.
    28  	SecretsDir = "NOMAD_SECRETS_DIR"
    29  
    30  	// MemLimit is the environment variable with the tasks memory limit in MBs.
    31  	MemLimit = "NOMAD_MEMORY_LIMIT"
    32  
    33  	// CpuLimit is the environment variable with the tasks CPU limit in MHz.
    34  	CpuLimit = "NOMAD_CPU_LIMIT"
    35  
    36  	// AllocID is the environment variable for passing the allocation ID.
    37  	AllocID = "NOMAD_ALLOC_ID"
    38  
    39  	// AllocName is the environment variable for passing the allocation name.
    40  	AllocName = "NOMAD_ALLOC_NAME"
    41  
    42  	// TaskName is the environment variable for passing the task name.
    43  	TaskName = "NOMAD_TASK_NAME"
    44  
    45  	// JobName is the environment variable for passing the job name.
    46  	JobName = "NOMAD_JOB_NAME"
    47  
    48  	// AllocIndex is the environment variable for passing the allocation index.
    49  	AllocIndex = "NOMAD_ALLOC_INDEX"
    50  
    51  	// Datacenter is the environment variable for passing the datacenter in which the alloc is running.
    52  	Datacenter = "NOMAD_DC"
    53  
    54  	// Region is the environment variable for passing the region in which the alloc is running.
    55  	Region = "NOMAD_REGION"
    56  
    57  	// AddrPrefix is the prefix for passing both dynamic and static port
    58  	// allocations to tasks.
    59  	// E.g $NOMAD_ADDR_http=127.0.0.1:80
    60  	AddrPrefix = "NOMAD_ADDR_"
    61  
    62  	// IpPrefix is the prefix for passing the IP of a port allocation to a task.
    63  	IpPrefix = "NOMAD_IP_"
    64  
    65  	// PortPrefix is the prefix for passing the port allocation to a task.
    66  	PortPrefix = "NOMAD_PORT_"
    67  
    68  	// HostPortPrefix is the prefix for passing the host port when a portmap is
    69  	// specified.
    70  	HostPortPrefix = "NOMAD_HOST_PORT_"
    71  
    72  	// MetaPrefix is the prefix for passing task meta data.
    73  	MetaPrefix = "NOMAD_META_"
    74  
    75  	// VaultToken is the environment variable for passing the Vault token
    76  	VaultToken = "VAULT_TOKEN"
    77  )
    78  
    79  // The node values that can be interpreted.
    80  const (
    81  	nodeIdKey     = "node.unique.id"
    82  	nodeDcKey     = "node.datacenter"
    83  	nodeRegionKey = "node.region"
    84  	nodeNameKey   = "node.unique.name"
    85  	nodeClassKey  = "node.class"
    86  
    87  	// Prefixes used for lookups.
    88  	nodeAttributePrefix = "attr."
    89  	nodeMetaPrefix      = "meta."
    90  )
    91  
    92  // TaskEnvironment is used to expose information to a task via environment
    93  // variables and provide interpolation of Nomad variables.
    94  type TaskEnvironment struct {
    95  	Env              map[string]string
    96  	TaskMeta         map[string]string
    97  	AllocDir         string
    98  	TaskDir          string
    99  	SecretsDir       string
   100  	CpuLimit         int
   101  	MemLimit         int
   102  	TaskName         string
   103  	AllocIndex       int
   104  	Datacenter       string
   105  	Region           string
   106  	AllocId          string
   107  	AllocName        string
   108  	Node             *structs.Node
   109  	Networks         []*structs.NetworkResource
   110  	PortMap          map[string]int
   111  	VaultToken       string
   112  	InjectVaultToken bool
   113  	JobName          string
   114  	Alloc            *structs.Allocation
   115  
   116  	// taskEnv is the variables that will be set in the tasks environment
   117  	TaskEnv map[string]string
   118  
   119  	// nodeValues is the values that are allowed for interprolation from the
   120  	// node.
   121  	NodeValues map[string]string
   122  }
   123  
   124  func NewTaskEnvironment(node *structs.Node) *TaskEnvironment {
   125  	return &TaskEnvironment{Node: node, AllocIndex: -1}
   126  }
   127  
   128  // ParseAndReplace takes the user supplied args replaces any instance of an
   129  // environment variable or nomad variable in the args with the actual value.
   130  func (t *TaskEnvironment) ParseAndReplace(args []string) []string {
   131  	replaced := make([]string, len(args))
   132  	for i, arg := range args {
   133  		replaced[i] = hargs.ReplaceEnv(arg, t.TaskEnv, t.NodeValues)
   134  	}
   135  
   136  	return replaced
   137  }
   138  
   139  // ReplaceEnv takes an arg and replaces all occurrences of environment variables
   140  // and nomad variables.  If the variable is found in the passed map it is
   141  // replaced, otherwise the original string is returned.
   142  func (t *TaskEnvironment) ReplaceEnv(arg string) string {
   143  	return hargs.ReplaceEnv(arg, t.TaskEnv, t.NodeValues)
   144  }
   145  
   146  // Build must be called after all the tasks environment values have been set.
   147  func (t *TaskEnvironment) Build() *TaskEnvironment {
   148  	t.NodeValues = make(map[string]string)
   149  	t.TaskEnv = make(map[string]string)
   150  
   151  	// Build the meta
   152  	for k, v := range t.TaskMeta {
   153  		t.TaskEnv[fmt.Sprintf("%s%s", MetaPrefix, strings.ToUpper(k))] = v
   154  		t.TaskEnv[fmt.Sprintf("%s%s", MetaPrefix, k)] = v
   155  	}
   156  
   157  	// Build the ports
   158  	for _, network := range t.Networks {
   159  		for label, value := range network.MapLabelToValues(nil) {
   160  			t.TaskEnv[fmt.Sprintf("%s%s", IpPrefix, label)] = network.IP
   161  			t.TaskEnv[fmt.Sprintf("%s%s", HostPortPrefix, label)] = strconv.Itoa(value)
   162  			if forwardedPort, ok := t.PortMap[label]; ok {
   163  				value = forwardedPort
   164  			}
   165  			t.TaskEnv[fmt.Sprintf("%s%s", PortPrefix, label)] = strconv.Itoa(value)
   166  			IPPort := net.JoinHostPort(network.IP, strconv.Itoa(value))
   167  			t.TaskEnv[fmt.Sprintf("%s%s", AddrPrefix, label)] = IPPort
   168  
   169  		}
   170  	}
   171  
   172  	// Build the directories
   173  	if t.AllocDir != "" {
   174  		t.TaskEnv[AllocDir] = t.AllocDir
   175  	}
   176  	if t.TaskDir != "" {
   177  		t.TaskEnv[TaskLocalDir] = t.TaskDir
   178  	}
   179  	if t.SecretsDir != "" {
   180  		t.TaskEnv[SecretsDir] = t.SecretsDir
   181  	}
   182  
   183  	// Build the resource limits
   184  	if t.MemLimit != 0 {
   185  		t.TaskEnv[MemLimit] = strconv.Itoa(t.MemLimit)
   186  	}
   187  	if t.CpuLimit != 0 {
   188  		t.TaskEnv[CpuLimit] = strconv.Itoa(t.CpuLimit)
   189  	}
   190  
   191  	// Build the tasks ids
   192  	if t.AllocId != "" {
   193  		t.TaskEnv[AllocID] = t.AllocId
   194  	}
   195  	if t.AllocName != "" {
   196  		t.TaskEnv[AllocName] = t.AllocName
   197  	}
   198  	if t.AllocIndex != -1 {
   199  		t.TaskEnv[AllocIndex] = strconv.Itoa(t.AllocIndex)
   200  	}
   201  	if t.TaskName != "" {
   202  		t.TaskEnv[TaskName] = t.TaskName
   203  	}
   204  	if t.JobName != "" {
   205  		t.TaskEnv[JobName] = t.JobName
   206  	}
   207  	if t.Datacenter != "" {
   208  		t.TaskEnv[Datacenter] = t.Datacenter
   209  	}
   210  	if t.Region != "" {
   211  		t.TaskEnv[Region] = t.Region
   212  	}
   213  
   214  	// Build the addr of the other tasks
   215  	if t.Alloc != nil {
   216  		for taskName, resources := range t.Alloc.TaskResources {
   217  			if taskName == t.TaskName {
   218  				continue
   219  			}
   220  			for _, nw := range resources.Networks {
   221  				ports := make([]structs.Port, 0, len(nw.ReservedPorts)+len(nw.DynamicPorts))
   222  				for _, port := range nw.ReservedPorts {
   223  					ports = append(ports, port)
   224  				}
   225  				for _, port := range nw.DynamicPorts {
   226  					ports = append(ports, port)
   227  				}
   228  				for _, p := range ports {
   229  					key := fmt.Sprintf("%s%s_%s", AddrPrefix, taskName, p.Label)
   230  					t.TaskEnv[key] = fmt.Sprintf("%s:%d", nw.IP, p.Value)
   231  					key = fmt.Sprintf("%s%s_%s", IpPrefix, taskName, p.Label)
   232  					t.TaskEnv[key] = nw.IP
   233  					key = fmt.Sprintf("%s%s_%s", PortPrefix, taskName, p.Label)
   234  					t.TaskEnv[key] = strconv.Itoa(p.Value)
   235  				}
   236  			}
   237  		}
   238  	}
   239  
   240  	// Build the node
   241  	if t.Node != nil {
   242  		// Set up the node values.
   243  		t.NodeValues[nodeIdKey] = t.Node.ID
   244  		t.NodeValues[nodeDcKey] = t.Node.Datacenter
   245  		t.NodeValues[nodeRegionKey] = t.Region
   246  		t.NodeValues[nodeNameKey] = t.Node.Name
   247  		t.NodeValues[nodeClassKey] = t.Node.NodeClass
   248  
   249  		// Set up the attributes.
   250  		for k, v := range t.Node.Attributes {
   251  			t.NodeValues[fmt.Sprintf("%s%s", nodeAttributePrefix, k)] = v
   252  		}
   253  
   254  		// Set up the meta.
   255  		for k, v := range t.Node.Meta {
   256  			t.NodeValues[fmt.Sprintf("%s%s", nodeMetaPrefix, k)] = v
   257  		}
   258  	}
   259  
   260  	// Build the Vault Token
   261  	if t.InjectVaultToken && t.VaultToken != "" {
   262  		t.TaskEnv[VaultToken] = t.VaultToken
   263  	}
   264  
   265  	// Interpret the environment variables
   266  	interpreted := make(map[string]string, len(t.Env))
   267  	for k, v := range t.Env {
   268  		interpreted[k] = hargs.ReplaceEnv(v, t.NodeValues, t.TaskEnv)
   269  	}
   270  
   271  	for k, v := range interpreted {
   272  		t.TaskEnv[k] = v
   273  	}
   274  
   275  	// Clean keys (see #2405)
   276  	cleanedEnv := make(map[string]string, len(t.TaskEnv))
   277  	for k, v := range t.TaskEnv {
   278  		cleanedK := helper.CleanEnvVar(k, '_')
   279  		cleanedEnv[cleanedK] = v
   280  	}
   281  	t.TaskEnv = cleanedEnv
   282  
   283  	return t
   284  }
   285  
   286  // EnvList returns a list of strings with NAME=value pairs.
   287  func (t *TaskEnvironment) EnvList() []string {
   288  	env := []string{}
   289  	for k, v := range t.TaskEnv {
   290  		env = append(env, fmt.Sprintf("%s=%s", k, v))
   291  	}
   292  
   293  	return env
   294  }
   295  
   296  // EnvMap returns a copy of the tasks environment variables.
   297  func (t *TaskEnvironment) EnvMap() map[string]string {
   298  	m := make(map[string]string, len(t.TaskEnv))
   299  	for k, v := range t.TaskEnv {
   300  		m[k] = v
   301  	}
   302  
   303  	return m
   304  }
   305  
   306  // EnvMapAll returns the environment variables that will be set as well as node
   307  // meta/attrs in the map. This is appropriate for interpolation.
   308  func (t *TaskEnvironment) EnvMapAll() map[string]string {
   309  	m := make(map[string]string, len(t.TaskEnv))
   310  	for k, v := range t.TaskEnv {
   311  		m[k] = v
   312  	}
   313  	for k, v := range t.NodeValues {
   314  		m[k] = v
   315  	}
   316  
   317  	return m
   318  }
   319  
   320  // Builder methods to build the TaskEnvironment
   321  func (t *TaskEnvironment) SetAllocDir(dir string) *TaskEnvironment {
   322  	t.AllocDir = dir
   323  	return t
   324  }
   325  
   326  func (t *TaskEnvironment) ClearAllocDir() *TaskEnvironment {
   327  	t.AllocDir = ""
   328  	return t
   329  }
   330  
   331  func (t *TaskEnvironment) SetTaskLocalDir(dir string) *TaskEnvironment {
   332  	t.TaskDir = dir
   333  	return t
   334  }
   335  
   336  func (t *TaskEnvironment) ClearTaskLocalDir() *TaskEnvironment {
   337  	t.TaskDir = ""
   338  	return t
   339  }
   340  
   341  func (t *TaskEnvironment) SetSecretsDir(dir string) *TaskEnvironment {
   342  	t.SecretsDir = dir
   343  	return t
   344  }
   345  
   346  func (t *TaskEnvironment) ClearSecretsDir() *TaskEnvironment {
   347  	t.SecretsDir = ""
   348  	return t
   349  }
   350  
   351  func (t *TaskEnvironment) SetMemLimit(limit int) *TaskEnvironment {
   352  	t.MemLimit = limit
   353  	return t
   354  }
   355  
   356  func (t *TaskEnvironment) ClearMemLimit() *TaskEnvironment {
   357  	t.MemLimit = 0
   358  	return t
   359  }
   360  
   361  func (t *TaskEnvironment) SetCpuLimit(limit int) *TaskEnvironment {
   362  	t.CpuLimit = limit
   363  	return t
   364  }
   365  
   366  func (t *TaskEnvironment) ClearCpuLimit() *TaskEnvironment {
   367  	t.CpuLimit = 0
   368  	return t
   369  }
   370  
   371  func (t *TaskEnvironment) SetNetworks(networks []*structs.NetworkResource) *TaskEnvironment {
   372  	t.Networks = networks
   373  	return t
   374  }
   375  
   376  func (t *TaskEnvironment) clearNetworks() *TaskEnvironment {
   377  	t.Networks = nil
   378  	return t
   379  }
   380  
   381  func (t *TaskEnvironment) SetPortMap(portMap map[string]int) *TaskEnvironment {
   382  	t.PortMap = portMap
   383  	return t
   384  }
   385  
   386  func (t *TaskEnvironment) clearPortMap() *TaskEnvironment {
   387  	t.PortMap = nil
   388  	return t
   389  }
   390  
   391  // Takes a map of meta values to be passed to the task. The keys are capatilized
   392  // when the environent variable is set.
   393  func (t *TaskEnvironment) SetTaskMeta(m map[string]string) *TaskEnvironment {
   394  	t.TaskMeta = m
   395  	return t
   396  }
   397  
   398  func (t *TaskEnvironment) ClearTaskMeta() *TaskEnvironment {
   399  	t.TaskMeta = nil
   400  	return t
   401  }
   402  
   403  func (t *TaskEnvironment) SetEnvvars(m map[string]string) *TaskEnvironment {
   404  	t.Env = m
   405  	return t
   406  }
   407  
   408  // Appends the given environment variables.
   409  func (t *TaskEnvironment) AppendEnvvars(m map[string]string) *TaskEnvironment {
   410  	if t.Env == nil {
   411  		t.Env = make(map[string]string, len(m))
   412  	}
   413  
   414  	for k, v := range m {
   415  		t.Env[k] = v
   416  	}
   417  	return t
   418  }
   419  
   420  // AppendHostEnvvars adds the host environment variables to the tasks. The
   421  // filter parameter can be use to filter host environment from entering the
   422  // tasks.
   423  func (t *TaskEnvironment) AppendHostEnvvars(filter []string) *TaskEnvironment {
   424  	hostEnv := os.Environ()
   425  	if t.Env == nil {
   426  		t.Env = make(map[string]string, len(hostEnv))
   427  	}
   428  
   429  	// Index the filtered environment variables.
   430  	index := make(map[string]struct{}, len(filter))
   431  	for _, f := range filter {
   432  		index[f] = struct{}{}
   433  	}
   434  
   435  	for _, e := range hostEnv {
   436  		parts := strings.SplitN(e, "=", 2)
   437  		key, value := parts[0], parts[1]
   438  
   439  		// Skip filtered environment variables
   440  		if _, filtered := index[key]; filtered {
   441  			continue
   442  		}
   443  
   444  		// Don't override the tasks environment variables.
   445  		if _, existing := t.Env[key]; !existing {
   446  			t.Env[key] = value
   447  		}
   448  	}
   449  
   450  	return t
   451  }
   452  
   453  func (t *TaskEnvironment) ClearEnvvars() *TaskEnvironment {
   454  	t.Env = nil
   455  	return t
   456  }
   457  
   458  // Helper method for setting all fields from an allocation.
   459  func (t *TaskEnvironment) SetAlloc(alloc *structs.Allocation) *TaskEnvironment {
   460  	t.AllocId = alloc.ID
   461  	t.AllocName = alloc.Name
   462  	t.AllocIndex = alloc.Index()
   463  	t.Alloc = alloc
   464  	return t
   465  }
   466  
   467  // Helper method for clearing all fields from an allocation.
   468  func (t *TaskEnvironment) ClearAlloc(alloc *structs.Allocation) *TaskEnvironment {
   469  	return t.ClearAllocId().ClearAllocName().ClearAllocIndex()
   470  }
   471  
   472  func (t *TaskEnvironment) SetAllocIndex(index int) *TaskEnvironment {
   473  	t.AllocIndex = index
   474  	return t
   475  }
   476  
   477  func (t *TaskEnvironment) ClearAllocIndex() *TaskEnvironment {
   478  	t.AllocIndex = -1
   479  	return t
   480  }
   481  
   482  func (t *TaskEnvironment) SetAllocId(id string) *TaskEnvironment {
   483  	t.AllocId = id
   484  	return t
   485  }
   486  
   487  func (t *TaskEnvironment) ClearAllocId() *TaskEnvironment {
   488  	t.AllocId = ""
   489  	return t
   490  }
   491  
   492  func (t *TaskEnvironment) SetAllocName(name string) *TaskEnvironment {
   493  	t.AllocName = name
   494  	return t
   495  }
   496  
   497  func (t *TaskEnvironment) ClearAllocName() *TaskEnvironment {
   498  	t.AllocName = ""
   499  	return t
   500  }
   501  
   502  func (t *TaskEnvironment) SetTaskName(name string) *TaskEnvironment {
   503  	t.TaskName = name
   504  	return t
   505  }
   506  
   507  func (t *TaskEnvironment) ClearTaskName() *TaskEnvironment {
   508  	t.TaskName = ""
   509  	return t
   510  }
   511  
   512  func (t *TaskEnvironment) SetJobName(name string) *TaskEnvironment {
   513  	t.JobName = name
   514  	return t
   515  }
   516  
   517  func (t *TaskEnvironment) ClearJobName() *TaskEnvironment {
   518  	t.JobName = ""
   519  	return t
   520  }
   521  
   522  func (t *TaskEnvironment) SetDatacenterName(name string) *TaskEnvironment {
   523  	t.Datacenter = name
   524  	return t
   525  }
   526  
   527  func (t *TaskEnvironment) ClearDatacenterName() *TaskEnvironment {
   528  	t.Datacenter = ""
   529  	return t
   530  }
   531  
   532  func (t *TaskEnvironment) SetRegionName(name string) *TaskEnvironment {
   533  	t.Region = name
   534  	return t
   535  }
   536  
   537  func (t *TaskEnvironment) ClearRegionName() *TaskEnvironment {
   538  	t.Region = ""
   539  	return t
   540  }
   541  
   542  func (t *TaskEnvironment) SetVaultToken(token string, inject bool) *TaskEnvironment {
   543  	t.VaultToken = token
   544  	t.InjectVaultToken = inject
   545  	return t
   546  }
   547  
   548  func (t *TaskEnvironment) ClearVaultToken() *TaskEnvironment {
   549  	t.VaultToken = ""
   550  	t.InjectVaultToken = false
   551  	return t
   552  }