github.com/bigcommerce/nomad@v0.9.3-bc/client/taskenv/env.go (about) 1 package taskenv 2 3 import ( 4 "fmt" 5 "net" 6 "os" 7 "strconv" 8 "strings" 9 "sync" 10 11 "github.com/hashicorp/nomad/helper" 12 hargs "github.com/hashicorp/nomad/helper/args" 13 "github.com/hashicorp/nomad/nomad/structs" 14 "github.com/hashicorp/nomad/plugins/drivers" 15 "github.com/zclconf/go-cty/cty" 16 ) 17 18 // A set of environment variables that are exported by each driver. 19 const ( 20 // AllocDir is the environment variable with the path to the alloc directory 21 // that is shared across tasks within a task group. 22 AllocDir = "NOMAD_ALLOC_DIR" 23 24 // TaskLocalDir is the environment variable with the path to the tasks local 25 // directory where it can store data that is persisted to the alloc is 26 // removed. 27 TaskLocalDir = "NOMAD_TASK_DIR" 28 29 // SecretsDir is the environment variable with the path to the tasks secret 30 // directory where it can store sensitive data. 31 SecretsDir = "NOMAD_SECRETS_DIR" 32 33 // MemLimit is the environment variable with the tasks memory limit in MBs. 34 MemLimit = "NOMAD_MEMORY_LIMIT" 35 36 // CpuLimit is the environment variable with the tasks CPU limit in MHz. 37 CpuLimit = "NOMAD_CPU_LIMIT" 38 39 // AllocID is the environment variable for passing the allocation ID. 40 AllocID = "NOMAD_ALLOC_ID" 41 42 // AllocName is the environment variable for passing the allocation name. 43 AllocName = "NOMAD_ALLOC_NAME" 44 45 // TaskName is the environment variable for passing the task name. 46 TaskName = "NOMAD_TASK_NAME" 47 48 // GroupName is the environment variable for passing the task group name. 49 GroupName = "NOMAD_GROUP_NAME" 50 51 // JobName is the environment variable for passing the job name. 52 JobName = "NOMAD_JOB_NAME" 53 54 // AllocIndex is the environment variable for passing the allocation index. 55 AllocIndex = "NOMAD_ALLOC_INDEX" 56 57 // Datacenter is the environment variable for passing the datacenter in which the alloc is running. 58 Datacenter = "NOMAD_DC" 59 60 // Region is the environment variable for passing the region in which the alloc is running. 61 Region = "NOMAD_REGION" 62 63 // AddrPrefix is the prefix for passing both dynamic and static port 64 // allocations to tasks. 65 // E.g $NOMAD_ADDR_http=127.0.0.1:80 66 // 67 // The ip:port are always the host's. 68 AddrPrefix = "NOMAD_ADDR_" 69 70 // IpPrefix is the prefix for passing the host IP of a port allocation 71 // to a task. 72 IpPrefix = "NOMAD_IP_" 73 74 // PortPrefix is the prefix for passing the port allocation to a task. 75 // It will be the task's port if a port map is specified. Task's should 76 // bind to this port. 77 PortPrefix = "NOMAD_PORT_" 78 79 // HostPortPrefix is the prefix for passing the host port when a port 80 // map is specified. 81 HostPortPrefix = "NOMAD_HOST_PORT_" 82 83 // MetaPrefix is the prefix for passing task meta data. 84 MetaPrefix = "NOMAD_META_" 85 86 // VaultToken is the environment variable for passing the Vault token 87 VaultToken = "VAULT_TOKEN" 88 89 // VaultNamespace is the environment variable for passing the Vault namespace, if applicable 90 VaultNamespace = "VAULT_NAMESPACE" 91 ) 92 93 // The node values that can be interpreted. 94 const ( 95 nodeIdKey = "node.unique.id" 96 nodeDcKey = "node.datacenter" 97 nodeRegionKey = "node.region" 98 nodeNameKey = "node.unique.name" 99 nodeClassKey = "node.class" 100 101 // Prefixes used for lookups. 102 nodeAttributePrefix = "attr." 103 nodeMetaPrefix = "meta." 104 ) 105 106 // TaskEnv is a task's environment as well as node attribute's for 107 // interpolation. 108 type TaskEnv struct { 109 // NodeAttrs is the map of node attributes for interpolation 110 NodeAttrs map[string]string 111 112 // EnvMap is the map of environment variables 113 EnvMap map[string]string 114 115 // deviceEnv is the environment variables populated from the device hooks. 116 deviceEnv map[string]string 117 118 // envList is a memoized list created by List() 119 envList []string 120 } 121 122 // NewTaskEnv creates a new task environment with the given environment, device 123 // environment and node attribute maps. 124 func NewTaskEnv(env, deviceEnv, node map[string]string) *TaskEnv { 125 return &TaskEnv{ 126 NodeAttrs: node, 127 deviceEnv: deviceEnv, 128 EnvMap: env, 129 } 130 } 131 132 // NewEmptyTaskEnv creates a new empty task environment. 133 func NewEmptyTaskEnv() *TaskEnv { 134 return &TaskEnv{ 135 NodeAttrs: make(map[string]string), 136 deviceEnv: make(map[string]string), 137 EnvMap: make(map[string]string), 138 } 139 } 140 141 // List returns the task's environment as a slice of NAME=value pair strings. 142 func (t *TaskEnv) List() []string { 143 if t.envList != nil { 144 return t.envList 145 } 146 147 env := []string{} 148 for k, v := range t.EnvMap { 149 env = append(env, fmt.Sprintf("%s=%s", k, v)) 150 } 151 152 return env 153 } 154 155 // DeviceEnv returns the task's environment variables set by device hooks. 156 func (t *TaskEnv) DeviceEnv() map[string]string { 157 m := make(map[string]string, len(t.deviceEnv)) 158 for k, v := range t.deviceEnv { 159 m[k] = v 160 } 161 162 return m 163 } 164 165 // Map of the task's environment variables. 166 func (t *TaskEnv) Map() map[string]string { 167 m := make(map[string]string, len(t.EnvMap)) 168 for k, v := range t.EnvMap { 169 m[k] = v 170 } 171 172 return m 173 } 174 175 // All of the task's environment variables and the node's attributes in a 176 // single map. 177 func (t *TaskEnv) All() map[string]string { 178 m := make(map[string]string, len(t.EnvMap)+len(t.NodeAttrs)) 179 for k, v := range t.EnvMap { 180 m[k] = v 181 } 182 for k, v := range t.NodeAttrs { 183 m[k] = v 184 } 185 186 return m 187 } 188 189 // AllValues is a map of the task's environment variables and the node's 190 // attributes with cty.Value (String) values. Errors including keys are 191 // returned in a map by key name. 192 // 193 // In the rare case of a fatal error, only an error value is returned. This is 194 // likely a programming error as user input should not be able to cause a fatal 195 // error. 196 func (t *TaskEnv) AllValues() (map[string]cty.Value, map[string]error, error) { 197 errs := make(map[string]error) 198 199 // Intermediate map for building up nested go types 200 allMap := make(map[string]interface{}, len(t.EnvMap)+len(t.NodeAttrs)) 201 202 // Intermediate map for all env vars including those whose keys that 203 // cannot be nested (eg foo...bar) 204 envMap := make(map[string]cty.Value, len(t.EnvMap)) 205 206 // Prepare job-based variables (eg job.meta, job.group.task.env, etc) 207 for k, v := range t.EnvMap { 208 if err := addNestedKey(allMap, k, v); err != nil { 209 errs[k] = err 210 } 211 envMap[k] = cty.StringVal(v) 212 } 213 214 // Prepare node-based variables (eg node.*, attr.*, meta.*) 215 for k, v := range t.NodeAttrs { 216 if err := addNestedKey(allMap, k, v); err != nil { 217 errs[k] = err 218 } 219 } 220 221 // Add flat envMap as a Map to allMap so users can access any key via 222 // HCL2's indexing syntax: ${env["foo...bar"]} 223 allMap["env"] = cty.MapVal(envMap) 224 225 // Add meta and attr to node if they exist to properly namespace things 226 // a bit. 227 nodeMapI, ok := allMap["node"] 228 if !ok { 229 return nil, nil, fmt.Errorf("missing node variable") 230 } 231 nodeMap, ok := nodeMapI.(map[string]interface{}) 232 if !ok { 233 return nil, nil, fmt.Errorf("invalid type for node variable: %T", nodeMapI) 234 } 235 if attrMap, ok := allMap["attr"]; ok { 236 nodeMap["attr"] = attrMap 237 } 238 if metaMap, ok := allMap["meta"]; ok { 239 nodeMap["meta"] = metaMap 240 } 241 242 // ctyify the entire tree of strings and maps 243 tree, err := ctyify(allMap) 244 if err != nil { 245 // This should not be possible and is likely a programming 246 // error. Invalid user input should be cleaned earlier. 247 return nil, nil, err 248 } 249 250 return tree, errs, nil 251 } 252 253 // ParseAndReplace takes the user supplied args replaces any instance of an 254 // environment variable or Nomad variable in the args with the actual value. 255 func (t *TaskEnv) ParseAndReplace(args []string) []string { 256 if args == nil { 257 return nil 258 } 259 260 replaced := make([]string, len(args)) 261 for i, arg := range args { 262 replaced[i] = hargs.ReplaceEnv(arg, t.EnvMap, t.NodeAttrs) 263 } 264 265 return replaced 266 } 267 268 // ReplaceEnv takes an arg and replaces all occurrences of environment variables 269 // and Nomad variables. If the variable is found in the passed map it is 270 // replaced, otherwise the original string is returned. 271 func (t *TaskEnv) ReplaceEnv(arg string) string { 272 return hargs.ReplaceEnv(arg, t.EnvMap, t.NodeAttrs) 273 } 274 275 // Builder is used to build task environment's and is safe for concurrent use. 276 type Builder struct { 277 // envvars are custom set environment variables 278 envvars map[string]string 279 280 // templateEnv are env vars set from templates 281 templateEnv map[string]string 282 283 // hostEnv are environment variables filtered from the host 284 hostEnv map[string]string 285 286 // nodeAttrs are Node attributes and metadata 287 nodeAttrs map[string]string 288 289 // taskMeta are the meta attributes on the task 290 taskMeta map[string]string 291 292 // allocDir from task's perspective; eg /alloc 293 allocDir string 294 295 // localDir from task's perspective; eg /local 296 localDir string 297 298 // secretsDir from task's perspective; eg /secrets 299 secretsDir string 300 301 cpuLimit int64 302 memLimit int64 303 taskName string 304 allocIndex int 305 datacenter string 306 region string 307 allocId string 308 allocName string 309 groupName string 310 vaultToken string 311 vaultNamespace string 312 injectVaultToken bool 313 jobName string 314 315 // otherPorts for tasks in the same alloc 316 otherPorts map[string]string 317 318 // driverNetwork is the network defined by the driver (or nil if none 319 // was defined). 320 driverNetwork *drivers.DriverNetwork 321 322 // network resources from the task; must be lazily turned into env vars 323 // because portMaps and advertiseIP can change after builder creation 324 // and affect network env vars. 325 networks []*structs.NetworkResource 326 327 // hookEnvs are env vars set by hooks and stored by hook name to 328 // support adding/removing vars from multiple hooks (eg HookA adds A:1, 329 // HookB adds A:2, HookA removes A, A should equal 2) 330 hookEnvs map[string]map[string]string 331 332 // hookNames is a slice of hooks in hookEnvs to apply hookEnvs in the 333 // order the hooks are run. 334 hookNames []string 335 336 // deviceHookName is the device hook name. It is set only if device hooks 337 // are set. While a bit round about, this enables us to return device hook 338 // environment variables without having to hardcode the name of the hook. 339 deviceHookName string 340 341 mu *sync.RWMutex 342 } 343 344 // NewBuilder creates a new task environment builder. 345 func NewBuilder(node *structs.Node, alloc *structs.Allocation, task *structs.Task, region string) *Builder { 346 b := NewEmptyBuilder() 347 b.region = region 348 return b.setTask(task).setAlloc(alloc).setNode(node) 349 } 350 351 // NewEmptyBuilder creates a new environment builder. 352 func NewEmptyBuilder() *Builder { 353 return &Builder{ 354 mu: &sync.RWMutex{}, 355 hookEnvs: map[string]map[string]string{}, 356 envvars: make(map[string]string), 357 } 358 } 359 360 // Build must be called after all the tasks environment values have been set. 361 func (b *Builder) Build() *TaskEnv { 362 nodeAttrs := make(map[string]string) 363 envMap := make(map[string]string) 364 var deviceEnvs map[string]string 365 366 b.mu.RLock() 367 defer b.mu.RUnlock() 368 369 // Add the directories 370 if b.allocDir != "" { 371 envMap[AllocDir] = b.allocDir 372 } 373 if b.localDir != "" { 374 envMap[TaskLocalDir] = b.localDir 375 } 376 if b.secretsDir != "" { 377 envMap[SecretsDir] = b.secretsDir 378 } 379 380 // Add the resource limits 381 if b.memLimit != 0 { 382 envMap[MemLimit] = strconv.FormatInt(b.memLimit, 10) 383 } 384 if b.cpuLimit != 0 { 385 envMap[CpuLimit] = strconv.FormatInt(b.cpuLimit, 10) 386 } 387 388 // Add the task metadata 389 if b.allocId != "" { 390 envMap[AllocID] = b.allocId 391 } 392 if b.allocName != "" { 393 envMap[AllocName] = b.allocName 394 } 395 if b.groupName != "" { 396 envMap[GroupName] = b.groupName 397 } 398 if b.allocIndex != -1 { 399 envMap[AllocIndex] = strconv.Itoa(b.allocIndex) 400 } 401 if b.taskName != "" { 402 envMap[TaskName] = b.taskName 403 } 404 if b.jobName != "" { 405 envMap[JobName] = b.jobName 406 } 407 if b.datacenter != "" { 408 envMap[Datacenter] = b.datacenter 409 } 410 if b.region != "" { 411 envMap[Region] = b.region 412 413 // Copy region over to node attrs 414 nodeAttrs[nodeRegionKey] = b.region 415 } 416 417 // Build the network related env vars 418 buildNetworkEnv(envMap, b.networks, b.driverNetwork) 419 420 // Build the addr of the other tasks 421 for k, v := range b.otherPorts { 422 envMap[k] = v 423 } 424 425 // Build the Vault Token 426 if b.injectVaultToken && b.vaultToken != "" { 427 envMap[VaultToken] = b.vaultToken 428 } 429 430 // Build the Vault Namespace 431 if b.injectVaultToken && b.vaultNamespace != "" { 432 envMap[VaultNamespace] = b.vaultNamespace 433 } 434 435 // Copy task meta 436 for k, v := range b.taskMeta { 437 envMap[k] = v 438 } 439 440 // Copy node attributes 441 for k, v := range b.nodeAttrs { 442 nodeAttrs[k] = v 443 } 444 445 // Interpolate and add environment variables 446 for k, v := range b.hostEnv { 447 envMap[k] = hargs.ReplaceEnv(v, nodeAttrs, envMap) 448 } 449 450 // Copy interpolated task env vars second as they override host env vars 451 for k, v := range b.envvars { 452 envMap[k] = hargs.ReplaceEnv(v, nodeAttrs, envMap) 453 } 454 455 // Copy hook env vars in the order the hooks were run 456 for _, h := range b.hookNames { 457 for k, v := range b.hookEnvs[h] { 458 e := hargs.ReplaceEnv(v, nodeAttrs, envMap) 459 envMap[k] = e 460 461 if h == b.deviceHookName { 462 if deviceEnvs == nil { 463 deviceEnvs = make(map[string]string, len(b.hookEnvs[h])) 464 } 465 466 deviceEnvs[k] = e 467 } 468 } 469 } 470 471 // Copy template env vars as they override task env vars 472 for k, v := range b.templateEnv { 473 envMap[k] = v 474 } 475 476 // Clean keys (see #2405) 477 cleanedEnv := make(map[string]string, len(envMap)) 478 for k, v := range envMap { 479 cleanedK := helper.CleanEnvVar(k, '_') 480 cleanedEnv[cleanedK] = v 481 } 482 483 var cleanedDeviceEnvs map[string]string 484 if deviceEnvs != nil { 485 cleanedDeviceEnvs = make(map[string]string, len(deviceEnvs)) 486 for k, v := range deviceEnvs { 487 cleanedK := helper.CleanEnvVar(k, '_') 488 cleanedDeviceEnvs[cleanedK] = v 489 } 490 } 491 492 return NewTaskEnv(cleanedEnv, cleanedDeviceEnvs, nodeAttrs) 493 } 494 495 // Update task updates the environment based on a new alloc and task. 496 func (b *Builder) UpdateTask(alloc *structs.Allocation, task *structs.Task) *Builder { 497 b.mu.Lock() 498 defer b.mu.Unlock() 499 return b.setTask(task).setAlloc(alloc) 500 } 501 502 // SetHookEnv sets environment variables from a hook. Variables are 503 // Last-Write-Wins, so if a hook writes a variable that's also written by a 504 // later hook, the later hooks value always gets used. 505 func (b *Builder) SetHookEnv(hook string, envs map[string]string) *Builder { 506 b.mu.Lock() 507 defer b.mu.Unlock() 508 return b.setHookEnvLocked(hook, envs) 509 } 510 511 // setHookEnvLocked is the implementation of setting hook environment variables 512 // and should be called with the lock held 513 func (b *Builder) setHookEnvLocked(hook string, envs map[string]string) *Builder { 514 if _, exists := b.hookEnvs[hook]; !exists { 515 b.hookNames = append(b.hookNames, hook) 516 } 517 b.hookEnvs[hook] = envs 518 519 return b 520 } 521 522 // SetDeviceHookEnv sets environment variables from a device hook. Variables are 523 // Last-Write-Wins, so if a hook writes a variable that's also written by a 524 // later hook, the later hooks value always gets used. 525 func (b *Builder) SetDeviceHookEnv(hookName string, envs map[string]string) *Builder { 526 b.mu.Lock() 527 defer b.mu.Unlock() 528 529 // Store the device hook name 530 b.deviceHookName = hookName 531 return b.setHookEnvLocked(hookName, envs) 532 } 533 534 // setTask is called from NewBuilder to populate task related environment 535 // variables. 536 func (b *Builder) setTask(task *structs.Task) *Builder { 537 b.taskName = task.Name 538 b.envvars = make(map[string]string, len(task.Env)) 539 for k, v := range task.Env { 540 b.envvars[k] = v 541 } 542 543 // COMPAT(0.11): Remove in 0.11 544 if task.Resources == nil { 545 b.memLimit = 0 546 b.cpuLimit = 0 547 } else { 548 b.memLimit = int64(task.Resources.MemoryMB) 549 b.cpuLimit = int64(task.Resources.CPU) 550 } 551 return b 552 } 553 554 // setAlloc is called from NewBuilder to populate alloc related environment 555 // variables. 556 func (b *Builder) setAlloc(alloc *structs.Allocation) *Builder { 557 b.allocId = alloc.ID 558 b.allocName = alloc.Name 559 b.groupName = alloc.TaskGroup 560 b.allocIndex = int(alloc.Index()) 561 b.jobName = alloc.Job.Name 562 563 // Set meta 564 combined := alloc.Job.CombinedTaskMeta(alloc.TaskGroup, b.taskName) 565 // taskMetaSize is double to total meta keys to account for given and upper 566 // cased values 567 taskMetaSize := len(combined) * 2 568 569 // if job is parameterized initialize optional meta to empty strings 570 if alloc.Job.Dispatched { 571 optionalMetaCount := len(alloc.Job.ParameterizedJob.MetaOptional) 572 b.taskMeta = make(map[string]string, taskMetaSize+optionalMetaCount*2) 573 574 for _, k := range alloc.Job.ParameterizedJob.MetaOptional { 575 b.taskMeta[fmt.Sprintf("%s%s", MetaPrefix, strings.ToUpper(k))] = "" 576 b.taskMeta[fmt.Sprintf("%s%s", MetaPrefix, k)] = "" 577 } 578 } else { 579 b.taskMeta = make(map[string]string, taskMetaSize) 580 } 581 582 for k, v := range combined { 583 b.taskMeta[fmt.Sprintf("%s%s", MetaPrefix, strings.ToUpper(k))] = v 584 b.taskMeta[fmt.Sprintf("%s%s", MetaPrefix, k)] = v 585 } 586 587 // COMPAT(0.11): Remove in 0.11 588 b.otherPorts = make(map[string]string, len(alloc.Job.LookupTaskGroup(alloc.TaskGroup).Tasks)*2) 589 if alloc.AllocatedResources != nil { 590 // Populate task resources 591 if tr, ok := alloc.AllocatedResources.Tasks[b.taskName]; ok { 592 b.cpuLimit = tr.Cpu.CpuShares 593 b.memLimit = tr.Memory.MemoryMB 594 595 // Copy networks to prevent sharing 596 b.networks = make([]*structs.NetworkResource, len(tr.Networks)) 597 for i, n := range tr.Networks { 598 b.networks[i] = n.Copy() 599 } 600 } 601 602 // Add ports from other tasks 603 for taskName, resources := range alloc.AllocatedResources.Tasks { 604 // Add ports from other tasks 605 if taskName == b.taskName { 606 continue 607 } 608 609 for _, nw := range resources.Networks { 610 for _, p := range nw.ReservedPorts { 611 addPort(b.otherPorts, taskName, nw.IP, p.Label, p.Value) 612 } 613 for _, p := range nw.DynamicPorts { 614 addPort(b.otherPorts, taskName, nw.IP, p.Label, p.Value) 615 } 616 } 617 } 618 } else if alloc.TaskResources != nil { 619 if tr, ok := alloc.TaskResources[b.taskName]; ok { 620 // Copy networks to prevent sharing 621 b.networks = make([]*structs.NetworkResource, len(tr.Networks)) 622 for i, n := range tr.Networks { 623 b.networks[i] = n.Copy() 624 } 625 626 } 627 628 for taskName, resources := range alloc.TaskResources { 629 // Add ports from other tasks 630 if taskName == b.taskName { 631 continue 632 } 633 for _, nw := range resources.Networks { 634 for _, p := range nw.ReservedPorts { 635 addPort(b.otherPorts, taskName, nw.IP, p.Label, p.Value) 636 } 637 for _, p := range nw.DynamicPorts { 638 addPort(b.otherPorts, taskName, nw.IP, p.Label, p.Value) 639 } 640 } 641 } 642 } 643 return b 644 } 645 646 // setNode is called from NewBuilder to populate node attributes. 647 func (b *Builder) setNode(n *structs.Node) *Builder { 648 b.nodeAttrs = make(map[string]string, 4+len(n.Attributes)+len(n.Meta)) 649 b.nodeAttrs[nodeIdKey] = n.ID 650 b.nodeAttrs[nodeNameKey] = n.Name 651 b.nodeAttrs[nodeClassKey] = n.NodeClass 652 b.nodeAttrs[nodeDcKey] = n.Datacenter 653 b.datacenter = n.Datacenter 654 655 // Set up the attributes. 656 for k, v := range n.Attributes { 657 b.nodeAttrs[fmt.Sprintf("%s%s", nodeAttributePrefix, k)] = v 658 } 659 660 // Set up the meta. 661 for k, v := range n.Meta { 662 b.nodeAttrs[fmt.Sprintf("%s%s", nodeMetaPrefix, k)] = v 663 } 664 return b 665 } 666 667 func (b *Builder) SetAllocDir(dir string) *Builder { 668 b.mu.Lock() 669 b.allocDir = dir 670 b.mu.Unlock() 671 return b 672 } 673 674 func (b *Builder) SetTaskLocalDir(dir string) *Builder { 675 b.mu.Lock() 676 b.localDir = dir 677 b.mu.Unlock() 678 return b 679 } 680 681 func (b *Builder) SetSecretsDir(dir string) *Builder { 682 b.mu.Lock() 683 b.secretsDir = dir 684 b.mu.Unlock() 685 return b 686 } 687 688 // SetDriverNetwork defined by the driver. 689 func (b *Builder) SetDriverNetwork(n *drivers.DriverNetwork) *Builder { 690 ncopy := n.Copy() 691 b.mu.Lock() 692 b.driverNetwork = ncopy 693 b.mu.Unlock() 694 return b 695 } 696 697 // buildNetworkEnv env vars in the given map. 698 // 699 // Auto: NOMAD_PORT_<label> 700 // Host: NOMAD_IP_<label>, NOMAD_ADDR_<label>, NOMAD_HOST_PORT_<label> 701 // 702 // Handled by setAlloc -> otherPorts: 703 // 704 // Task: NOMAD_TASK_{IP,PORT,ADDR}_<task>_<label> # Always host values 705 // 706 func buildNetworkEnv(envMap map[string]string, nets structs.Networks, driverNet *drivers.DriverNetwork) { 707 for _, n := range nets { 708 for _, p := range n.ReservedPorts { 709 buildPortEnv(envMap, p, n.IP, driverNet) 710 } 711 for _, p := range n.DynamicPorts { 712 buildPortEnv(envMap, p, n.IP, driverNet) 713 } 714 } 715 } 716 717 func buildPortEnv(envMap map[string]string, p structs.Port, ip string, driverNet *drivers.DriverNetwork) { 718 // Host IP, port, and address 719 portStr := strconv.Itoa(p.Value) 720 envMap[IpPrefix+p.Label] = ip 721 envMap[HostPortPrefix+p.Label] = portStr 722 envMap[AddrPrefix+p.Label] = net.JoinHostPort(ip, portStr) 723 724 // Set Port to task's value if there's a port map 725 if driverNet != nil && driverNet.PortMap[p.Label] != 0 { 726 envMap[PortPrefix+p.Label] = strconv.Itoa(driverNet.PortMap[p.Label]) 727 } else { 728 // Default to host's 729 envMap[PortPrefix+p.Label] = portStr 730 } 731 } 732 733 // SetHostEnvvars adds the host environment variables to the tasks. The filter 734 // parameter can be use to filter host environment from entering the tasks. 735 func (b *Builder) SetHostEnvvars(filter []string) *Builder { 736 filterMap := make(map[string]struct{}, len(filter)) 737 for _, f := range filter { 738 filterMap[f] = struct{}{} 739 } 740 741 fullHostEnv := os.Environ() 742 filteredHostEnv := make(map[string]string, len(fullHostEnv)) 743 for _, e := range fullHostEnv { 744 parts := strings.SplitN(e, "=", 2) 745 key, value := parts[0], parts[1] 746 747 // Skip filtered environment variables 748 if _, filtered := filterMap[key]; filtered { 749 continue 750 } 751 752 filteredHostEnv[key] = value 753 } 754 755 b.mu.Lock() 756 b.hostEnv = filteredHostEnv 757 b.mu.Unlock() 758 return b 759 } 760 761 func (b *Builder) SetTemplateEnv(m map[string]string) *Builder { 762 b.mu.Lock() 763 b.templateEnv = m 764 b.mu.Unlock() 765 return b 766 } 767 768 func (b *Builder) SetVaultToken(token, namespace string, inject bool) *Builder { 769 b.mu.Lock() 770 b.vaultToken = token 771 b.vaultNamespace = namespace 772 b.injectVaultToken = inject 773 b.mu.Unlock() 774 return b 775 } 776 777 // addPort keys and values for other tasks to an env var map 778 func addPort(m map[string]string, taskName, ip, portLabel string, port int) { 779 key := fmt.Sprintf("%s%s_%s", AddrPrefix, taskName, portLabel) 780 m[key] = fmt.Sprintf("%s:%d", ip, port) 781 key = fmt.Sprintf("%s%s_%s", IpPrefix, taskName, portLabel) 782 m[key] = ip 783 key = fmt.Sprintf("%s%s_%s", PortPrefix, taskName, portLabel) 784 m[key] = strconv.Itoa(port) 785 }