github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/client/driver/env/env_test.go (about) 1 package env 2 3 import ( 4 "fmt" 5 "os" 6 "reflect" 7 "sort" 8 "strings" 9 "testing" 10 11 "github.com/ncodes/nomad/nomad/mock" 12 "github.com/ncodes/nomad/nomad/structs" 13 ) 14 15 const ( 16 // Node values that tests can rely on 17 metaKey = "instance" 18 metaVal = "t2-micro" 19 attrKey = "arch" 20 attrVal = "amd64" 21 nodeName = "test node" 22 nodeClass = "test class" 23 24 // Environment variable values that tests can rely on 25 envOneKey = "NOMAD_IP" 26 envOneVal = "127.0.0.1" 27 envTwoKey = "NOMAD_PORT_WEB" 28 envTwoVal = ":80" 29 ) 30 31 var ( 32 // Networks that tests can rely on 33 networks = []*structs.NetworkResource{ 34 &structs.NetworkResource{ 35 IP: "127.0.0.1", 36 ReservedPorts: []structs.Port{{Label: "http", Value: 80}}, 37 DynamicPorts: []structs.Port{{Label: "https", Value: 8080}}, 38 }, 39 } 40 portMap = map[string]int{ 41 "https": 443, 42 } 43 ) 44 45 func testTaskEnvironment() *TaskEnvironment { 46 n := mock.Node() 47 n.Attributes = map[string]string{ 48 attrKey: attrVal, 49 } 50 n.Meta = map[string]string{ 51 metaKey: metaVal, 52 } 53 n.Name = nodeName 54 n.NodeClass = nodeClass 55 56 envvars := map[string]string{ 57 envOneKey: envOneVal, 58 envTwoKey: envTwoVal, 59 } 60 return NewTaskEnvironment(n).SetEnvvars(envvars).Build() 61 } 62 63 func TestEnvironment_ParseAndReplace_Env(t *testing.T) { 64 env := testTaskEnvironment() 65 66 input := []string{fmt.Sprintf(`"${%v}"!`, envOneKey), fmt.Sprintf("${%s}${%s}", envOneKey, envTwoKey)} 67 act := env.ParseAndReplace(input) 68 exp := []string{fmt.Sprintf(`"%s"!`, envOneVal), fmt.Sprintf("%s%s", envOneVal, envTwoVal)} 69 70 if !reflect.DeepEqual(act, exp) { 71 t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp) 72 } 73 } 74 75 func TestEnvironment_ParseAndReplace_Meta(t *testing.T) { 76 input := []string{fmt.Sprintf("${%v%v}", nodeMetaPrefix, metaKey)} 77 exp := []string{metaVal} 78 env := testTaskEnvironment() 79 act := env.ParseAndReplace(input) 80 81 if !reflect.DeepEqual(act, exp) { 82 t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp) 83 } 84 } 85 86 func TestEnvironment_ParseAndReplace_Attr(t *testing.T) { 87 input := []string{fmt.Sprintf("${%v%v}", nodeAttributePrefix, attrKey)} 88 exp := []string{attrVal} 89 env := testTaskEnvironment() 90 act := env.ParseAndReplace(input) 91 92 if !reflect.DeepEqual(act, exp) { 93 t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp) 94 } 95 } 96 97 func TestEnvironment_ParseAndReplace_Node(t *testing.T) { 98 input := []string{fmt.Sprintf("${%v}", nodeNameKey), fmt.Sprintf("${%v}", nodeClassKey)} 99 exp := []string{nodeName, nodeClass} 100 env := testTaskEnvironment() 101 act := env.ParseAndReplace(input) 102 103 if !reflect.DeepEqual(act, exp) { 104 t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp) 105 } 106 } 107 108 func TestEnvironment_ParseAndReplace_Mixed(t *testing.T) { 109 input := []string{ 110 fmt.Sprintf("${%v}${%v%v}", nodeNameKey, nodeAttributePrefix, attrKey), 111 fmt.Sprintf("${%v}${%v%v}", nodeClassKey, nodeMetaPrefix, metaKey), 112 fmt.Sprintf("${%v}${%v}", envTwoKey, nodeClassKey), 113 } 114 exp := []string{ 115 fmt.Sprintf("%v%v", nodeName, attrVal), 116 fmt.Sprintf("%v%v", nodeClass, metaVal), 117 fmt.Sprintf("%v%v", envTwoVal, nodeClass), 118 } 119 env := testTaskEnvironment() 120 act := env.ParseAndReplace(input) 121 122 if !reflect.DeepEqual(act, exp) { 123 t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp) 124 } 125 } 126 127 func TestEnvironment_ReplaceEnv_Mixed(t *testing.T) { 128 input := fmt.Sprintf("${%v}${%v%v}", nodeNameKey, nodeAttributePrefix, attrKey) 129 exp := fmt.Sprintf("%v%v", nodeName, attrVal) 130 env := testTaskEnvironment() 131 act := env.ReplaceEnv(input) 132 133 if act != exp { 134 t.Fatalf("ParseAndReplace(%v) returned %#v; want %#v", input, act, exp) 135 } 136 } 137 138 func TestEnvironment_AsList(t *testing.T) { 139 n := mock.Node() 140 a := mock.Alloc() 141 a.Resources.Networks[0].ReservedPorts = append(a.Resources.Networks[0].ReservedPorts, 142 structs.Port{Label: "ssh", Value: 22}, 143 structs.Port{Label: "other", Value: 1234}, 144 ) 145 a.TaskResources["web"].Networks[0].DynamicPorts[0].Value = 2000 146 a.TaskResources["ssh"] = &structs.Resources{ 147 Networks: []*structs.NetworkResource{ 148 { 149 Device: "eth0", 150 IP: "192.168.0.100", 151 MBits: 50, 152 ReservedPorts: []structs.Port{ 153 {Label: "ssh", Value: 22}, 154 {Label: "other", Value: 1234}, 155 }, 156 }, 157 }, 158 } 159 env := NewTaskEnvironment(n). 160 SetNetworks(networks). 161 SetPortMap(portMap). 162 SetTaskMeta(map[string]string{"foo": "baz"}). 163 SetAlloc(a). 164 SetTaskName("taskA").Build() 165 166 act := env.EnvList() 167 exp := []string{ 168 "NOMAD_ADDR_http=127.0.0.1:80", 169 "NOMAD_PORT_http=80", 170 "NOMAD_IP_http=127.0.0.1", 171 "NOMAD_ADDR_https=127.0.0.1:443", 172 "NOMAD_PORT_https=443", 173 "NOMAD_IP_https=127.0.0.1", 174 "NOMAD_HOST_PORT_http=80", 175 "NOMAD_HOST_PORT_https=8080", 176 "NOMAD_META_FOO=baz", 177 "NOMAD_META_foo=baz", 178 "NOMAD_ADDR_web_main=192.168.0.100:5000", 179 "NOMAD_ADDR_web_http=192.168.0.100:2000", 180 "NOMAD_PORT_web_main=5000", 181 "NOMAD_PORT_web_http=2000", 182 "NOMAD_IP_web_main=192.168.0.100", 183 "NOMAD_IP_web_http=192.168.0.100", 184 "NOMAD_TASK_NAME=taskA", 185 "NOMAD_ADDR_ssh_other=192.168.0.100:1234", 186 "NOMAD_ADDR_ssh_ssh=192.168.0.100:22", 187 "NOMAD_IP_ssh_other=192.168.0.100", 188 "NOMAD_IP_ssh_ssh=192.168.0.100", 189 "NOMAD_PORT_ssh_other=1234", 190 "NOMAD_PORT_ssh_ssh=22", 191 fmt.Sprintf("NOMAD_ALLOC_ID=%s", a.ID), 192 } 193 sort.Strings(act) 194 sort.Strings(exp) 195 if len(act) != len(exp) { 196 t.Fatalf("wat: %d != %d", len(act), len(exp)) 197 } 198 for i := range act { 199 if act[i] != exp[i] { 200 t.Errorf("%d %q != %q", i, act[i], exp[i]) 201 } 202 } 203 } 204 205 func TestEnvironment_VaultToken(t *testing.T) { 206 n := mock.Node() 207 env := NewTaskEnvironment(n).SetVaultToken("123", false).Build() 208 209 act := env.EnvList() 210 if len(act) != 0 { 211 t.Fatalf("Unexpected environment variables: %v", act) 212 } 213 214 env = env.SetVaultToken("123", true).Build() 215 act = env.EnvList() 216 exp := []string{"VAULT_TOKEN=123"} 217 if !reflect.DeepEqual(act, exp) { 218 t.Fatalf("env.List() returned %v; want %v", act, exp) 219 } 220 } 221 222 func TestEnvironment_ClearEnvvars(t *testing.T) { 223 n := mock.Node() 224 env := NewTaskEnvironment(n). 225 SetNetworks(networks). 226 SetPortMap(portMap). 227 SetEnvvars(map[string]string{"foo": "baz", "bar": "bang"}).Build() 228 229 act := env.EnvList() 230 exp := []string{ 231 "NOMAD_ADDR_http=127.0.0.1:80", 232 "NOMAD_PORT_http=80", 233 "NOMAD_IP_http=127.0.0.1", 234 "NOMAD_ADDR_https=127.0.0.1:443", 235 "NOMAD_PORT_https=443", 236 "NOMAD_IP_https=127.0.0.1", 237 "NOMAD_HOST_PORT_http=80", 238 "NOMAD_HOST_PORT_https=8080", 239 "bar=bang", 240 "foo=baz", 241 } 242 sort.Strings(act) 243 sort.Strings(exp) 244 if !reflect.DeepEqual(act, exp) { 245 t.Fatalf("env.List() returned %v; want %v", act, exp) 246 } 247 248 // Clear the environent variables. 249 env.ClearEnvvars().Build() 250 251 act = env.EnvList() 252 exp = []string{ 253 "NOMAD_ADDR_http=127.0.0.1:80", 254 "NOMAD_PORT_http=80", 255 "NOMAD_IP_http=127.0.0.1", 256 "NOMAD_ADDR_https=127.0.0.1:443", 257 "NOMAD_PORT_https=443", 258 "NOMAD_IP_https=127.0.0.1", 259 "NOMAD_HOST_PORT_https=8080", 260 "NOMAD_HOST_PORT_http=80", 261 } 262 sort.Strings(act) 263 sort.Strings(exp) 264 if !reflect.DeepEqual(act, exp) { 265 t.Fatalf("env.List() returned %v; want %v", act, exp) 266 } 267 } 268 269 func TestEnvironment_Interpolate(t *testing.T) { 270 env := testTaskEnvironment(). 271 SetEnvvars(map[string]string{"test": "${node.class}", "test2": "${attr.arch}"}). 272 Build() 273 274 act := env.EnvList() 275 exp := []string{fmt.Sprintf("test=%s", nodeClass), fmt.Sprintf("test2=%s", attrVal)} 276 sort.Strings(act) 277 sort.Strings(exp) 278 if !reflect.DeepEqual(act, exp) { 279 t.Fatalf("env.List() returned %v; want %v", act, exp) 280 } 281 } 282 283 func TestEnvironment_AppendHostEnvvars(t *testing.T) { 284 host := os.Environ() 285 if len(host) < 2 { 286 t.Skip("No host environment variables. Can't test") 287 } 288 skip := strings.Split(host[0], "=")[0] 289 env := testTaskEnvironment(). 290 AppendHostEnvvars([]string{skip}). 291 Build() 292 293 act := env.EnvMap() 294 if len(act) < 1 { 295 t.Fatalf("Host environment variables not properly set") 296 } 297 if _, ok := act[skip]; ok { 298 t.Fatalf("Didn't filter environment variable %q", skip) 299 } 300 } 301 302 // TestEnvironment_DashesInTaskName asserts dashes in port labels are properly 303 // converted to underscores in environment variables. 304 // See: https://github.com/ncodes/nomad/issues/2405 305 func TestEnvironment_DashesInTaskName(t *testing.T) { 306 env := testTaskEnvironment() 307 env.SetNetworks([]*structs.NetworkResource{ 308 { 309 Device: "eth0", 310 DynamicPorts: []structs.Port{ 311 { 312 Label: "just-some-dashes", 313 Value: 9000, 314 }, 315 }, 316 }, 317 }) 318 env.Build() 319 320 if env.TaskEnv["NOMAD_PORT_just_some_dashes"] != "9000" { 321 t.Fatalf("Expected NOMAD_PORT_just_some_dashes=9000 in TaskEnv; found:\n%#v", env.TaskEnv) 322 } 323 }