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 }