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