1package taskenv 2 3import ( 4 "github.com/hashicorp/nomad/nomad/structs" 5) 6 7// InterpolateServices returns an interpolated copy of services and checks with 8// values from the task's environment. 9func InterpolateServices(taskEnv *TaskEnv, services []*structs.Service) []*structs.Service { 10 // Guard against not having a valid taskEnv. This can be the case if the 11 // PreKilling or Exited hook is run before Poststart. 12 if taskEnv == nil || len(services) == 0 { 13 return nil 14 } 15 16 interpolated := make([]*structs.Service, len(services)) 17 18 for i, origService := range services { 19 // Create a copy as we need to re-interpolate every time the 20 // environment changes. 21 service := origService.Copy() 22 23 for _, check := range service.Checks { 24 check.Name = taskEnv.ReplaceEnv(check.Name) 25 check.Type = taskEnv.ReplaceEnv(check.Type) 26 check.Command = taskEnv.ReplaceEnv(check.Command) 27 check.Args = taskEnv.ParseAndReplace(check.Args) 28 check.Path = taskEnv.ReplaceEnv(check.Path) 29 check.Protocol = taskEnv.ReplaceEnv(check.Protocol) 30 check.PortLabel = taskEnv.ReplaceEnv(check.PortLabel) 31 check.InitialStatus = taskEnv.ReplaceEnv(check.InitialStatus) 32 check.Method = taskEnv.ReplaceEnv(check.Method) 33 check.GRPCService = taskEnv.ReplaceEnv(check.GRPCService) 34 check.Header = interpolateMapStringSliceString(taskEnv, check.Header) 35 } 36 37 service.Name = taskEnv.ReplaceEnv(service.Name) 38 service.PortLabel = taskEnv.ReplaceEnv(service.PortLabel) 39 service.Tags = taskEnv.ParseAndReplace(service.Tags) 40 service.CanaryTags = taskEnv.ParseAndReplace(service.CanaryTags) 41 service.Meta = interpolateMapStringString(taskEnv, service.Meta) 42 service.CanaryMeta = interpolateMapStringString(taskEnv, service.CanaryMeta) 43 interpolateConnect(taskEnv, service.Connect) 44 45 interpolated[i] = service 46 } 47 48 return interpolated 49} 50 51func interpolateMapStringSliceString(taskEnv *TaskEnv, orig map[string][]string) map[string][]string { 52 if len(orig) == 0 { 53 return nil 54 } 55 56 m := make(map[string][]string, len(orig)) 57 for k, vs := range orig { 58 m[taskEnv.ReplaceEnv(k)] = taskEnv.ParseAndReplace(vs) 59 } 60 return m 61} 62 63func interpolateMapStringString(taskEnv *TaskEnv, orig map[string]string) map[string]string { 64 if len(orig) == 0 { 65 return nil 66 } 67 68 m := make(map[string]string, len(orig)) 69 for k, v := range orig { 70 m[taskEnv.ReplaceEnv(k)] = taskEnv.ReplaceEnv(v) 71 } 72 return m 73} 74 75func interpolateMapStringInterface(taskEnv *TaskEnv, orig map[string]interface{}) map[string]interface{} { 76 if len(orig) == 0 { 77 return nil 78 } 79 80 m := make(map[string]interface{}, len(orig)) 81 for k, v := range orig { 82 m[taskEnv.ReplaceEnv(k)] = v 83 } 84 return m 85} 86 87func interpolateConnect(taskEnv *TaskEnv, connect *structs.ConsulConnect) { 88 if connect == nil { 89 return 90 } 91 92 interpolateConnectSidecarService(taskEnv, connect.SidecarService) 93 interpolateConnectSidecarTask(taskEnv, connect.SidecarTask) 94 if connect.Gateway != nil { 95 interpolateConnectGatewayProxy(taskEnv, connect.Gateway.Proxy) 96 interpolateConnectGatewayIngress(taskEnv, connect.Gateway.Ingress) 97 } 98} 99 100func interpolateConnectGatewayProxy(taskEnv *TaskEnv, proxy *structs.ConsulGatewayProxy) { 101 if proxy == nil { 102 return 103 } 104 105 m := make(map[string]*structs.ConsulGatewayBindAddress, len(proxy.EnvoyGatewayBindAddresses)) 106 for k, v := range proxy.EnvoyGatewayBindAddresses { 107 m[taskEnv.ReplaceEnv(k)] = &structs.ConsulGatewayBindAddress{ 108 Address: taskEnv.ReplaceEnv(v.Address), 109 Port: v.Port, 110 } 111 } 112 113 proxy.EnvoyGatewayBindAddresses = m 114 proxy.Config = interpolateMapStringInterface(taskEnv, proxy.Config) 115} 116 117func interpolateConnectGatewayIngress(taskEnv *TaskEnv, ingress *structs.ConsulIngressConfigEntry) { 118 if ingress == nil { 119 return 120 } 121 122 for _, listener := range ingress.Listeners { 123 listener.Protocol = taskEnv.ReplaceEnv(listener.Protocol) 124 for _, service := range listener.Services { 125 service.Name = taskEnv.ReplaceEnv(service.Name) 126 service.Hosts = taskEnv.ParseAndReplace(service.Hosts) 127 } 128 } 129} 130 131func interpolateConnectSidecarService(taskEnv *TaskEnv, sidecar *structs.ConsulSidecarService) { 132 if sidecar == nil { 133 return 134 } 135 136 sidecar.Port = taskEnv.ReplaceEnv(sidecar.Port) 137 sidecar.Tags = taskEnv.ParseAndReplace(sidecar.Tags) 138 if sidecar.Proxy != nil { 139 sidecar.Proxy.LocalServiceAddress = taskEnv.ReplaceEnv(sidecar.Proxy.LocalServiceAddress) 140 if sidecar.Proxy.Expose != nil { 141 for i := 0; i < len(sidecar.Proxy.Expose.Paths); i++ { 142 sidecar.Proxy.Expose.Paths[i].Protocol = taskEnv.ReplaceEnv(sidecar.Proxy.Expose.Paths[i].Protocol) 143 sidecar.Proxy.Expose.Paths[i].ListenerPort = taskEnv.ReplaceEnv(sidecar.Proxy.Expose.Paths[i].ListenerPort) 144 sidecar.Proxy.Expose.Paths[i].Path = taskEnv.ReplaceEnv(sidecar.Proxy.Expose.Paths[i].Path) 145 } 146 } 147 for i := 0; i < len(sidecar.Proxy.Upstreams); i++ { 148 sidecar.Proxy.Upstreams[i].Datacenter = taskEnv.ReplaceEnv(sidecar.Proxy.Upstreams[i].Datacenter) 149 sidecar.Proxy.Upstreams[i].DestinationName = taskEnv.ReplaceEnv(sidecar.Proxy.Upstreams[i].DestinationName) 150 sidecar.Proxy.Upstreams[i].LocalBindAddress = taskEnv.ReplaceEnv(sidecar.Proxy.Upstreams[i].LocalBindAddress) 151 } 152 sidecar.Proxy.Config = interpolateMapStringInterface(taskEnv, sidecar.Proxy.Config) 153 } 154} 155 156func interpolateConnectSidecarTask(taskEnv *TaskEnv, task *structs.SidecarTask) { 157 if task == nil { 158 return 159 } 160 161 task.Driver = taskEnv.ReplaceEnv(task.Driver) 162 task.Config = interpolateMapStringInterface(taskEnv, task.Config) 163 task.Env = interpolateMapStringString(taskEnv, task.Env) 164 task.KillSignal = taskEnv.ReplaceEnv(task.KillSignal) 165 task.Meta = interpolateMapStringString(taskEnv, task.Meta) 166 interpolateTaskResources(taskEnv, task.Resources) 167 task.User = taskEnv.ReplaceEnv(task.User) 168} 169 170func interpolateTaskResources(taskEnv *TaskEnv, resources *structs.Resources) { 171 if resources == nil { 172 return 173 } 174 175 for i := 0; i < len(resources.Devices); i++ { 176 resources.Devices[i].Name = taskEnv.ReplaceEnv(resources.Devices[i].Name) 177 // do not interpolate constraints & affinities 178 } 179 180 for i := 0; i < len(resources.Networks); i++ { 181 resources.Networks[i].CIDR = taskEnv.ReplaceEnv(resources.Networks[i].CIDR) 182 resources.Networks[i].Device = taskEnv.ReplaceEnv(resources.Networks[i].Device) 183 resources.Networks[i].IP = taskEnv.ReplaceEnv(resources.Networks[i].IP) 184 resources.Networks[i].Mode = taskEnv.ReplaceEnv(resources.Networks[i].Mode) 185 186 if resources.Networks[i].DNS != nil { 187 resources.Networks[i].DNS.Options = taskEnv.ParseAndReplace(resources.Networks[i].DNS.Options) 188 resources.Networks[i].DNS.Searches = taskEnv.ParseAndReplace(resources.Networks[i].DNS.Searches) 189 resources.Networks[i].DNS.Servers = taskEnv.ParseAndReplace(resources.Networks[i].DNS.Servers) 190 } 191 192 for p := 0; p < len(resources.Networks[i].DynamicPorts); p++ { 193 resources.Networks[i].DynamicPorts[p].HostNetwork = taskEnv.ReplaceEnv(resources.Networks[i].DynamicPorts[p].HostNetwork) 194 resources.Networks[i].DynamicPorts[p].Label = taskEnv.ReplaceEnv(resources.Networks[i].DynamicPorts[p].Label) 195 } 196 197 for p := 0; p < len(resources.Networks[i].ReservedPorts); p++ { 198 resources.Networks[i].ReservedPorts[p].HostNetwork = taskEnv.ReplaceEnv(resources.Networks[i].ReservedPorts[p].HostNetwork) 199 resources.Networks[i].ReservedPorts[p].Label = taskEnv.ReplaceEnv(resources.Networks[i].ReservedPorts[p].Label) 200 } 201 } 202} 203