github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/agent/consul/connect_test.go (about) 1 package consul 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/hashicorp/consul/api" 8 "github.com/hashicorp/nomad/helper" 9 "github.com/hashicorp/nomad/nomad/structs" 10 "github.com/stretchr/testify/require" 11 ) 12 13 var ( 14 testConnectNetwork = structs.Networks{{ 15 Mode: "bridge", 16 Device: "eth0", 17 IP: "192.168.30.1", 18 DynamicPorts: []structs.Port{ 19 {Label: "healthPort", Value: 23100, To: 23100}, 20 {Label: "metricsPort", Value: 23200, To: 23200}, 21 {Label: "connect-proxy-redis", Value: 3000, To: 3000}, 22 }, 23 }} 24 testConnectPorts = structs.AllocatedPorts{{ 25 Label: "connect-proxy-redis", 26 Value: 3000, 27 To: 3000, 28 HostIP: "192.168.30.1", 29 }} 30 ) 31 32 func TestConnect_newConnect(t *testing.T) { 33 t.Parallel() 34 35 t.Run("nil", func(t *testing.T) { 36 asr, err := newConnect("", "", nil, nil, nil) 37 require.NoError(t, err) 38 require.Nil(t, asr) 39 }) 40 41 t.Run("native", func(t *testing.T) { 42 asr, err := newConnect("", "", &structs.ConsulConnect{ 43 Native: true, 44 }, nil, nil) 45 require.NoError(t, err) 46 require.True(t, asr.Native) 47 require.Nil(t, asr.SidecarService) 48 }) 49 50 t.Run("with sidecar", func(t *testing.T) { 51 asr, err := newConnect("redis-service-id", "redis", &structs.ConsulConnect{ 52 Native: false, 53 SidecarService: &structs.ConsulSidecarService{ 54 Tags: []string{"foo", "bar"}, 55 Port: "connect-proxy-redis", 56 }, 57 }, testConnectNetwork, testConnectPorts) 58 require.NoError(t, err) 59 require.Equal(t, &api.AgentServiceRegistration{ 60 Tags: []string{"foo", "bar"}, 61 Port: 3000, 62 Address: "192.168.30.1", 63 Proxy: &api.AgentServiceConnectProxyConfig{ 64 Config: map[string]interface{}{ 65 "bind_address": "0.0.0.0", 66 "bind_port": 3000, 67 }, 68 }, 69 Checks: api.AgentServiceChecks{ 70 { 71 Name: "Connect Sidecar Listening", 72 TCP: "192.168.30.1:3000", 73 Interval: "10s", 74 }, 75 { 76 Name: "Connect Sidecar Aliasing redis-service-id", 77 AliasService: "redis-service-id", 78 }, 79 }, 80 }, asr.SidecarService) 81 }) 82 } 83 84 func TestConnect_connectSidecarRegistration(t *testing.T) { 85 t.Parallel() 86 87 t.Run("nil", func(t *testing.T) { 88 sidecarReg, err := connectSidecarRegistration("", nil, testConnectNetwork, testConnectPorts) 89 require.NoError(t, err) 90 require.Nil(t, sidecarReg) 91 }) 92 93 t.Run("no service port", func(t *testing.T) { 94 _, err := connectSidecarRegistration("unknown-id", &structs.ConsulSidecarService{ 95 Port: "unknown-label", 96 }, testConnectNetwork, testConnectPorts) 97 require.EqualError(t, err, `No port of label "unknown-label" defined`) 98 }) 99 100 t.Run("bad proxy", func(t *testing.T) { 101 _, err := connectSidecarRegistration("redis-service-id", &structs.ConsulSidecarService{ 102 Port: "connect-proxy-redis", 103 Proxy: &structs.ConsulProxy{ 104 Expose: &structs.ConsulExposeConfig{ 105 Paths: []structs.ConsulExposePath{{ 106 ListenerPort: "badPort", 107 }}, 108 }, 109 }, 110 }, testConnectNetwork, testConnectPorts) 111 require.EqualError(t, err, `No port of label "badPort" defined`) 112 }) 113 114 t.Run("normal", func(t *testing.T) { 115 proxy, err := connectSidecarRegistration("redis-service-id", &structs.ConsulSidecarService{ 116 Tags: []string{"foo", "bar"}, 117 Port: "connect-proxy-redis", 118 }, testConnectNetwork, testConnectPorts) 119 require.NoError(t, err) 120 require.Equal(t, &api.AgentServiceRegistration{ 121 Tags: []string{"foo", "bar"}, 122 Port: 3000, 123 Address: "192.168.30.1", 124 Proxy: &api.AgentServiceConnectProxyConfig{ 125 Config: map[string]interface{}{ 126 "bind_address": "0.0.0.0", 127 "bind_port": 3000, 128 }, 129 }, 130 Checks: api.AgentServiceChecks{ 131 { 132 Name: "Connect Sidecar Listening", 133 TCP: "192.168.30.1:3000", 134 Interval: "10s", 135 }, 136 { 137 Name: "Connect Sidecar Aliasing redis-service-id", 138 AliasService: "redis-service-id", 139 }, 140 }, 141 }, proxy) 142 }) 143 } 144 145 func TestConnect_connectProxy(t *testing.T) { 146 t.Parallel() 147 148 // If the input proxy is nil, we expect the output to be a proxy with its 149 // config set to default values. 150 t.Run("nil proxy", func(t *testing.T) { 151 proxy, err := connectSidecarProxy(nil, 2000, testConnectNetwork) 152 require.NoError(t, err) 153 require.Equal(t, &api.AgentServiceConnectProxyConfig{ 154 LocalServiceAddress: "", 155 LocalServicePort: 0, 156 Upstreams: nil, 157 Expose: api.ExposeConfig{}, 158 Config: map[string]interface{}{ 159 "bind_address": "0.0.0.0", 160 "bind_port": 2000, 161 }, 162 }, proxy) 163 }) 164 165 t.Run("bad proxy", func(t *testing.T) { 166 _, err := connectSidecarProxy(&structs.ConsulProxy{ 167 LocalServiceAddress: "0.0.0.0", 168 LocalServicePort: 2000, 169 Upstreams: nil, 170 Expose: &structs.ConsulExposeConfig{ 171 Paths: []structs.ConsulExposePath{{ 172 ListenerPort: "badPort", 173 }}, 174 }, 175 Config: nil, 176 }, 2000, testConnectNetwork) 177 require.EqualError(t, err, `No port of label "badPort" defined`) 178 }) 179 180 t.Run("normal", func(t *testing.T) { 181 proxy, err := connectSidecarProxy(&structs.ConsulProxy{ 182 LocalServiceAddress: "0.0.0.0", 183 LocalServicePort: 2000, 184 Upstreams: nil, 185 Expose: &structs.ConsulExposeConfig{ 186 Paths: []structs.ConsulExposePath{{ 187 Path: "/health", 188 Protocol: "http", 189 LocalPathPort: 8000, 190 ListenerPort: "healthPort", 191 }}, 192 }, 193 Config: nil, 194 }, 2000, testConnectNetwork) 195 require.NoError(t, err) 196 require.Equal(t, &api.AgentServiceConnectProxyConfig{ 197 LocalServiceAddress: "0.0.0.0", 198 LocalServicePort: 2000, 199 Upstreams: nil, 200 Expose: api.ExposeConfig{ 201 Paths: []api.ExposePath{{ 202 Path: "/health", 203 Protocol: "http", 204 LocalPathPort: 8000, 205 ListenerPort: 23100, 206 }}, 207 }, 208 Config: map[string]interface{}{ 209 "bind_address": "0.0.0.0", 210 "bind_port": 2000, 211 }, 212 }, proxy) 213 }) 214 } 215 216 func TestConnect_connectProxyExpose(t *testing.T) { 217 t.Parallel() 218 219 t.Run("nil", func(t *testing.T) { 220 exposeConfig, err := connectProxyExpose(nil, nil) 221 require.NoError(t, err) 222 require.Equal(t, api.ExposeConfig{}, exposeConfig) 223 }) 224 225 t.Run("bad port", func(t *testing.T) { 226 _, err := connectProxyExpose(&structs.ConsulExposeConfig{ 227 Paths: []structs.ConsulExposePath{{ 228 ListenerPort: "badPort", 229 }}, 230 }, testConnectNetwork) 231 require.EqualError(t, err, `No port of label "badPort" defined`) 232 }) 233 234 t.Run("normal", func(t *testing.T) { 235 expose, err := connectProxyExpose(&structs.ConsulExposeConfig{ 236 Paths: []structs.ConsulExposePath{{ 237 Path: "/health", 238 Protocol: "http", 239 LocalPathPort: 8000, 240 ListenerPort: "healthPort", 241 }}, 242 }, testConnectNetwork) 243 require.NoError(t, err) 244 require.Equal(t, api.ExposeConfig{ 245 Checks: false, 246 Paths: []api.ExposePath{{ 247 Path: "/health", 248 ListenerPort: 23100, 249 LocalPathPort: 8000, 250 Protocol: "http", 251 ParsedFromCheck: false, 252 }}, 253 }, expose) 254 }) 255 } 256 257 func TestConnect_connectProxyExposePaths(t *testing.T) { 258 t.Parallel() 259 260 t.Run("nil", func(t *testing.T) { 261 upstreams, err := connectProxyExposePaths(nil, nil) 262 require.NoError(t, err) 263 require.Empty(t, upstreams) 264 }) 265 266 t.Run("no network", func(t *testing.T) { 267 original := []structs.ConsulExposePath{{Path: "/path"}} 268 _, err := connectProxyExposePaths(original, nil) 269 require.EqualError(t, err, `Connect only supported with exactly 1 network (found 0)`) 270 }) 271 272 t.Run("normal", func(t *testing.T) { 273 original := []structs.ConsulExposePath{{ 274 Path: "/health", 275 Protocol: "http", 276 LocalPathPort: 8000, 277 ListenerPort: "healthPort", 278 }, { 279 Path: "/metrics", 280 Protocol: "grpc", 281 LocalPathPort: 9500, 282 ListenerPort: "metricsPort", 283 }} 284 exposePaths, err := connectProxyExposePaths(original, testConnectNetwork) 285 require.NoError(t, err) 286 require.Equal(t, []api.ExposePath{ 287 { 288 Path: "/health", 289 Protocol: "http", 290 LocalPathPort: 8000, 291 ListenerPort: 23100, 292 ParsedFromCheck: false, 293 }, 294 { 295 Path: "/metrics", 296 Protocol: "grpc", 297 LocalPathPort: 9500, 298 ListenerPort: 23200, 299 ParsedFromCheck: false, 300 }, 301 }, exposePaths) 302 }) 303 } 304 305 func TestConnect_connectUpstreams(t *testing.T) { 306 t.Parallel() 307 308 t.Run("nil", func(t *testing.T) { 309 require.Nil(t, connectUpstreams(nil)) 310 }) 311 312 t.Run("not empty", func(t *testing.T) { 313 require.Equal(t, 314 []api.Upstream{{ 315 DestinationName: "foo", 316 LocalBindPort: 8000, 317 }, { 318 DestinationName: "bar", 319 LocalBindPort: 9000, 320 Datacenter: "dc2", 321 LocalBindAddress: "127.0.0.2", 322 }}, 323 connectUpstreams([]structs.ConsulUpstream{{ 324 DestinationName: "foo", 325 LocalBindPort: 8000, 326 }, { 327 DestinationName: "bar", 328 LocalBindPort: 9000, 329 Datacenter: "dc2", 330 LocalBindAddress: "127.0.0.2", 331 }}), 332 ) 333 }) 334 } 335 336 func TestConnect_connectProxyConfig(t *testing.T) { 337 t.Parallel() 338 339 t.Run("nil map", func(t *testing.T) { 340 require.Equal(t, map[string]interface{}{ 341 "bind_address": "0.0.0.0", 342 "bind_port": 42, 343 }, connectProxyConfig(nil, 42)) 344 }) 345 346 t.Run("pre-existing map", func(t *testing.T) { 347 require.Equal(t, map[string]interface{}{ 348 "bind_address": "0.0.0.0", 349 "bind_port": 42, 350 "foo": "bar", 351 }, connectProxyConfig(map[string]interface{}{ 352 "foo": "bar", 353 }, 42)) 354 }) 355 } 356 357 func TestConnect_getConnectPort(t *testing.T) { 358 t.Parallel() 359 360 networks := structs.Networks{{ 361 IP: "192.168.30.1", 362 DynamicPorts: []structs.Port{{ 363 Label: "connect-proxy-foo", 364 Value: 23456, 365 To: 23456, 366 }}}} 367 368 ports := structs.AllocatedPorts{{ 369 Label: "foo", 370 Value: 23456, 371 To: 23456, 372 HostIP: "192.168.30.1", 373 }} 374 375 t.Run("normal", func(t *testing.T) { 376 nr, err := connectPort("foo", networks, ports) 377 require.NoError(t, err) 378 require.Equal(t, structs.AllocatedPortMapping{ 379 Label: "foo", 380 Value: 23456, 381 To: 23456, 382 HostIP: "192.168.30.1", 383 }, nr) 384 }) 385 386 t.Run("no such service", func(t *testing.T) { 387 _, err := connectPort("other", networks, ports) 388 require.EqualError(t, err, `No port of label "other" defined`) 389 }) 390 391 t.Run("no network", func(t *testing.T) { 392 _, err := connectPort("foo", nil, nil) 393 require.EqualError(t, err, "Connect only supported with exactly 1 network (found 0)") 394 }) 395 396 t.Run("multi network", func(t *testing.T) { 397 _, err := connectPort("foo", append(networks, &structs.NetworkResource{ 398 Device: "eth1", 399 IP: "10.0.10.0", 400 }), nil) 401 require.EqualError(t, err, "Connect only supported with exactly 1 network (found 2)") 402 }) 403 } 404 405 func TestConnect_getExposePathPort(t *testing.T) { 406 t.Parallel() 407 408 networks := structs.Networks{{ 409 Device: "eth0", 410 IP: "192.168.30.1", 411 DynamicPorts: []structs.Port{{ 412 Label: "myPort", 413 Value: 23456, 414 To: 23456, 415 }}}} 416 417 t.Run("normal", func(t *testing.T) { 418 ip, port, err := connectExposePathPort("myPort", networks) 419 require.NoError(t, err) 420 require.Equal(t, ip, "192.168.30.1") 421 require.Equal(t, 23456, port) 422 }) 423 424 t.Run("no such port label", func(t *testing.T) { 425 _, _, err := connectExposePathPort("otherPort", networks) 426 require.EqualError(t, err, `No port of label "otherPort" defined`) 427 }) 428 429 t.Run("no network", func(t *testing.T) { 430 _, _, err := connectExposePathPort("myPort", nil) 431 require.EqualError(t, err, "Connect only supported with exactly 1 network (found 0)") 432 }) 433 434 t.Run("multi network", func(t *testing.T) { 435 _, _, err := connectExposePathPort("myPort", append(networks, &structs.NetworkResource{ 436 Device: "eth1", 437 IP: "10.0.10.0", 438 })) 439 require.EqualError(t, err, "Connect only supported with exactly 1 network (found 2)") 440 }) 441 } 442 443 func TestConnect_newConnectGateway(t *testing.T) { 444 t.Parallel() 445 446 t.Run("not a gateway", func(t *testing.T) { 447 result := newConnectGateway("s1", &structs.ConsulConnect{Native: true}) 448 require.Nil(t, result) 449 }) 450 451 t.Run("canonical empty", func(t *testing.T) { 452 result := newConnectGateway("s1", &structs.ConsulConnect{ 453 Gateway: &structs.ConsulGateway{ 454 Proxy: &structs.ConsulGatewayProxy{ 455 ConnectTimeout: helper.TimeToPtr(1 * time.Second), 456 EnvoyGatewayBindTaggedAddresses: false, 457 EnvoyGatewayBindAddresses: nil, 458 EnvoyGatewayNoDefaultBind: false, 459 Config: nil, 460 }, 461 }, 462 }) 463 require.Equal(t, &api.AgentServiceConnectProxyConfig{ 464 Config: map[string]interface{}{ 465 "connect_timeout_ms": int64(1000), 466 }, 467 }, result) 468 }) 469 470 t.Run("proxy undefined", func(t *testing.T) { 471 result := newConnectGateway("s1", &structs.ConsulConnect{ 472 Gateway: &structs.ConsulGateway{ 473 Proxy: nil, 474 }, 475 }) 476 require.Equal(t, &api.AgentServiceConnectProxyConfig{ 477 Config: nil, 478 }, result) 479 }) 480 481 t.Run("full", func(t *testing.T) { 482 result := newConnectGateway("s1", &structs.ConsulConnect{ 483 Gateway: &structs.ConsulGateway{ 484 Proxy: &structs.ConsulGatewayProxy{ 485 ConnectTimeout: helper.TimeToPtr(1 * time.Second), 486 EnvoyGatewayBindTaggedAddresses: true, 487 EnvoyGatewayBindAddresses: map[string]*structs.ConsulGatewayBindAddress{ 488 "service1": &structs.ConsulGatewayBindAddress{ 489 Address: "10.0.0.1", 490 Port: 2000, 491 }, 492 }, 493 EnvoyGatewayNoDefaultBind: true, 494 EnvoyDNSDiscoveryType: "STRICT_DNS", 495 Config: map[string]interface{}{ 496 "foo": 1, 497 }, 498 }, 499 }, 500 }) 501 require.Equal(t, &api.AgentServiceConnectProxyConfig{ 502 Config: map[string]interface{}{ 503 "connect_timeout_ms": int64(1000), 504 "envoy_gateway_bind_tagged_addresses": true, 505 "envoy_gateway_bind_addresses": map[string]*structs.ConsulGatewayBindAddress{ 506 "service1": &structs.ConsulGatewayBindAddress{ 507 Address: "10.0.0.1", 508 Port: 2000, 509 }, 510 }, 511 "envoy_gateway_no_default_bind": true, 512 "envoy_dns_discovery_type": "STRICT_DNS", 513 "foo": 1, 514 }, 515 }, result) 516 }) 517 }