istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/serviceregistry/serviceentry/conversion_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package serviceentry 16 17 import ( 18 "encoding/json" 19 "strings" 20 "testing" 21 "time" 22 23 "istio.io/api/label" 24 networking "istio.io/api/networking/v1alpha3" 25 "istio.io/istio/pilot/pkg/features" 26 "istio.io/istio/pilot/pkg/model" 27 "istio.io/istio/pilot/pkg/serviceregistry/provider" 28 labelutil "istio.io/istio/pilot/pkg/serviceregistry/util/label" 29 "istio.io/istio/pilot/test/util" 30 "istio.io/istio/pkg/cluster" 31 "istio.io/istio/pkg/config" 32 "istio.io/istio/pkg/config/constants" 33 "istio.io/istio/pkg/config/host" 34 "istio.io/istio/pkg/config/labels" 35 "istio.io/istio/pkg/config/protocol" 36 "istio.io/istio/pkg/config/schema/gvk" 37 "istio.io/istio/pkg/network" 38 "istio.io/istio/pkg/spiffe" 39 "istio.io/istio/pkg/test" 40 ) 41 42 var ( 43 GlobalTime = time.Now() 44 httpNone = &config.Config{ 45 Meta: config.Meta{ 46 GroupVersionKind: gvk.ServiceEntry, 47 Name: "httpNone", 48 Namespace: "httpNone", 49 Domain: "svc.cluster.local", 50 CreationTimestamp: GlobalTime, 51 }, 52 Spec: &networking.ServiceEntry{ 53 Hosts: []string{"*.google.com"}, 54 Ports: []*networking.ServicePort{ 55 {Number: 80, Name: "http-number", Protocol: "http"}, 56 {Number: 8080, Name: "http2-number", Protocol: "http2"}, 57 }, 58 Location: networking.ServiceEntry_MESH_EXTERNAL, 59 Resolution: networking.ServiceEntry_NONE, 60 }, 61 } 62 ) 63 64 var tcpNone = &config.Config{ 65 Meta: config.Meta{ 66 GroupVersionKind: gvk.ServiceEntry, 67 Name: "tcpNone", 68 Namespace: "tcpNone", 69 CreationTimestamp: GlobalTime, 70 }, 71 Spec: &networking.ServiceEntry{ 72 Hosts: []string{"tcpnone.com"}, 73 Addresses: []string{"172.217.0.0/16"}, 74 Ports: []*networking.ServicePort{ 75 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 76 }, 77 Location: networking.ServiceEntry_MESH_EXTERNAL, 78 Resolution: networking.ServiceEntry_NONE, 79 }, 80 } 81 82 var httpStatic = &config.Config{ 83 Meta: config.Meta{ 84 GroupVersionKind: gvk.ServiceEntry, 85 Name: "httpStatic", 86 Namespace: "httpStatic", 87 CreationTimestamp: GlobalTime, 88 }, 89 Spec: &networking.ServiceEntry{ 90 Hosts: []string{"*.google.com"}, 91 Ports: []*networking.ServicePort{ 92 {Number: 80, Name: "http-port", Protocol: "http"}, 93 {Number: 8080, Name: "http-alt-port", Protocol: "http"}, 94 }, 95 Endpoints: []*networking.WorkloadEntry{ 96 { 97 Address: "2.2.2.2", 98 Ports: map[string]uint32{"http-port": 7080, "http-alt-port": 18080}, 99 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 100 }, 101 { 102 Address: "3.3.3.3", 103 Ports: map[string]uint32{"http-port": 1080}, 104 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 105 }, 106 { 107 Address: "4.4.4.4", 108 Ports: map[string]uint32{"http-port": 1080}, 109 Labels: map[string]string{"foo": "bar"}, 110 }, 111 }, 112 Location: networking.ServiceEntry_MESH_EXTERNAL, 113 Resolution: networking.ServiceEntry_STATIC, 114 }, 115 } 116 117 // Shares the same host as httpStatic, but adds some endpoints. We expect these to be merge 118 var httpStaticOverlay = &config.Config{ 119 Meta: config.Meta{ 120 GroupVersionKind: gvk.ServiceEntry, 121 Name: "httpStaticOverlay", 122 Namespace: "httpStatic", 123 CreationTimestamp: GlobalTime, 124 }, 125 Spec: &networking.ServiceEntry{ 126 Hosts: []string{"*.google.com"}, 127 Ports: []*networking.ServicePort{ 128 {Number: 4567, Name: "http-port", Protocol: "http"}, 129 }, 130 Endpoints: []*networking.WorkloadEntry{ 131 { 132 Address: "5.5.5.5", 133 Labels: map[string]string{"overlay": "bar"}, 134 }, 135 }, 136 Location: networking.ServiceEntry_MESH_EXTERNAL, 137 Resolution: networking.ServiceEntry_STATIC, 138 }, 139 } 140 141 var httpDNSnoEndpoints = &config.Config{ 142 Meta: config.Meta{ 143 GroupVersionKind: gvk.ServiceEntry, 144 Name: "httpDNSnoEndpoints", 145 Namespace: "httpDNSnoEndpoints", 146 CreationTimestamp: GlobalTime, 147 }, 148 Spec: &networking.ServiceEntry{ 149 Hosts: []string{"google.com", "www.wikipedia.org"}, 150 Ports: []*networking.ServicePort{ 151 {Number: 80, Name: "http-port", Protocol: "http"}, 152 {Number: 8080, Name: "http-alt-port", Protocol: "http"}, 153 }, 154 Location: networking.ServiceEntry_MESH_EXTERNAL, 155 Resolution: networking.ServiceEntry_DNS, 156 SubjectAltNames: []string{"google.com"}, 157 }, 158 } 159 160 var httpDNSRRnoEndpoints = &config.Config{ 161 Meta: config.Meta{ 162 GroupVersionKind: gvk.ServiceEntry, 163 Name: "httpDNSRRnoEndpoints", 164 Namespace: "httpDNSRRnoEndpoints", 165 CreationTimestamp: GlobalTime, 166 }, 167 Spec: &networking.ServiceEntry{ 168 Hosts: []string{"api.istio.io"}, 169 Ports: []*networking.ServicePort{ 170 {Number: 80, Name: "http-port", Protocol: "http"}, 171 {Number: 8080, Name: "http-alt-port", Protocol: "http"}, 172 }, 173 Location: networking.ServiceEntry_MESH_EXTERNAL, 174 Resolution: networking.ServiceEntry_DNS_ROUND_ROBIN, 175 SubjectAltNames: []string{"api.istio.io"}, 176 }, 177 } 178 179 var dnsTargetPort = &config.Config{ 180 Meta: config.Meta{ 181 GroupVersionKind: gvk.ServiceEntry, 182 Name: "dnsTargetPort", 183 Namespace: "dnsTargetPort", 184 CreationTimestamp: GlobalTime, 185 }, 186 Spec: &networking.ServiceEntry{ 187 Hosts: []string{"google.com"}, 188 Ports: []*networking.ServicePort{ 189 {Number: 80, Name: "http-port", Protocol: "http", TargetPort: 8080}, 190 }, 191 Location: networking.ServiceEntry_MESH_EXTERNAL, 192 Resolution: networking.ServiceEntry_DNS, 193 }, 194 } 195 196 var httpDNS = &config.Config{ 197 Meta: config.Meta{ 198 GroupVersionKind: gvk.ServiceEntry, 199 Name: "httpDNS", 200 Namespace: "httpDNS", 201 CreationTimestamp: GlobalTime, 202 }, 203 Spec: &networking.ServiceEntry{ 204 Hosts: []string{"*.google.com"}, 205 Ports: []*networking.ServicePort{ 206 {Number: 80, Name: "http-port", Protocol: "http"}, 207 {Number: 8080, Name: "http-alt-port", Protocol: "http"}, 208 }, 209 Endpoints: []*networking.WorkloadEntry{ 210 { 211 Address: "us.google.com", 212 Ports: map[string]uint32{"http-port": 7080, "http-alt-port": 18080}, 213 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 214 }, 215 { 216 Address: "uk.google.com", 217 Ports: map[string]uint32{"http-port": 1080}, 218 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 219 }, 220 { 221 Address: "de.google.com", 222 Labels: map[string]string{"foo": "bar", label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 223 }, 224 }, 225 Location: networking.ServiceEntry_MESH_EXTERNAL, 226 Resolution: networking.ServiceEntry_DNS, 227 }, 228 } 229 230 var httpDNSRR = &config.Config{ 231 Meta: config.Meta{ 232 GroupVersionKind: gvk.ServiceEntry, 233 Name: "httpDNSRR", 234 Namespace: "httpDNSRR", 235 CreationTimestamp: GlobalTime, 236 }, 237 Spec: &networking.ServiceEntry{ 238 Hosts: []string{"*.istio.io"}, 239 Ports: []*networking.ServicePort{ 240 {Number: 80, Name: "http-port", Protocol: "http"}, 241 {Number: 8080, Name: "http-alt-port", Protocol: "http"}, 242 }, 243 Endpoints: []*networking.WorkloadEntry{ 244 { 245 Address: "api-v1.istio.io", 246 Ports: map[string]uint32{"http-port": 7080, "http-alt-port": 18080}, 247 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 248 }, 249 }, 250 Location: networking.ServiceEntry_MESH_EXTERNAL, 251 Resolution: networking.ServiceEntry_DNS_ROUND_ROBIN, 252 }, 253 } 254 255 var tcpDNS = &config.Config{ 256 Meta: config.Meta{ 257 GroupVersionKind: gvk.ServiceEntry, 258 Name: "tcpDNS", 259 Namespace: "tcpDNS", 260 CreationTimestamp: GlobalTime, 261 }, 262 Spec: &networking.ServiceEntry{ 263 Hosts: []string{"tcpdns.com"}, 264 Ports: []*networking.ServicePort{ 265 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 266 }, 267 Endpoints: []*networking.WorkloadEntry{ 268 { 269 Address: "lon.google.com", 270 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 271 }, 272 { 273 Address: "in.google.com", 274 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 275 }, 276 }, 277 Location: networking.ServiceEntry_MESH_EXTERNAL, 278 Resolution: networking.ServiceEntry_DNS, 279 }, 280 } 281 282 var tcpStatic = &config.Config{ 283 Meta: config.Meta{ 284 GroupVersionKind: gvk.ServiceEntry, 285 Name: "tcpStatic", 286 Namespace: "tcpStatic", 287 CreationTimestamp: GlobalTime, 288 }, 289 Spec: &networking.ServiceEntry{ 290 Hosts: []string{"tcpstatic.com"}, 291 Addresses: []string{"172.217.0.1"}, 292 Ports: []*networking.ServicePort{ 293 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 294 }, 295 Endpoints: []*networking.WorkloadEntry{ 296 { 297 Address: "1.1.1.1", 298 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 299 }, 300 { 301 Address: "2.2.2.2", 302 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 303 }, 304 }, 305 Location: networking.ServiceEntry_MESH_EXTERNAL, 306 Resolution: networking.ServiceEntry_STATIC, 307 }, 308 } 309 310 var httpNoneInternal = &config.Config{ 311 Meta: config.Meta{ 312 GroupVersionKind: gvk.ServiceEntry, 313 Name: "httpNoneInternal", 314 Namespace: "httpNoneInternal", 315 CreationTimestamp: GlobalTime, 316 }, 317 Spec: &networking.ServiceEntry{ 318 Hosts: []string{"*.google.com"}, 319 Ports: []*networking.ServicePort{ 320 {Number: 80, Name: "http-number", Protocol: "http"}, 321 {Number: 8080, Name: "http2-number", Protocol: "http2"}, 322 }, 323 Location: networking.ServiceEntry_MESH_INTERNAL, 324 Resolution: networking.ServiceEntry_NONE, 325 }, 326 } 327 328 var tcpNoneInternal = &config.Config{ 329 Meta: config.Meta{ 330 GroupVersionKind: gvk.ServiceEntry, 331 Name: "tcpNoneInternal", 332 Namespace: "tcpNoneInternal", 333 CreationTimestamp: GlobalTime, 334 }, 335 Spec: &networking.ServiceEntry{ 336 Hosts: []string{"tcpinternal.com"}, 337 Addresses: []string{"172.217.0.0/16"}, 338 Ports: []*networking.ServicePort{ 339 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 340 }, 341 Location: networking.ServiceEntry_MESH_INTERNAL, 342 Resolution: networking.ServiceEntry_NONE, 343 }, 344 } 345 346 var multiAddrInternal = &config.Config{ 347 Meta: config.Meta{ 348 GroupVersionKind: gvk.ServiceEntry, 349 Name: "multiAddrInternal", 350 Namespace: "multiAddrInternal", 351 CreationTimestamp: GlobalTime, 352 }, 353 Spec: &networking.ServiceEntry{ 354 Hosts: []string{"tcp1.com", "tcp2.com"}, 355 Addresses: []string{"1.1.1.0/16", "2.2.2.0/16"}, 356 Ports: []*networking.ServicePort{ 357 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 358 }, 359 Location: networking.ServiceEntry_MESH_INTERNAL, 360 Resolution: networking.ServiceEntry_NONE, 361 }, 362 } 363 364 var udsLocal = &config.Config{ 365 Meta: config.Meta{ 366 GroupVersionKind: gvk.ServiceEntry, 367 Name: "udsLocal", 368 Namespace: "udsLocal", 369 CreationTimestamp: GlobalTime, 370 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 371 }, 372 Spec: &networking.ServiceEntry{ 373 Hosts: []string{"uds.cluster.local"}, 374 Ports: []*networking.ServicePort{ 375 {Number: 6553, Name: "grpc-1", Protocol: "grpc"}, 376 }, 377 Endpoints: []*networking.WorkloadEntry{ 378 {Address: "unix:///test/sock", Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}}, 379 }, 380 Resolution: networking.ServiceEntry_STATIC, 381 }, 382 } 383 384 // ServiceEntry DNS with a selector 385 var selectorDNS = &config.Config{ 386 Meta: config.Meta{ 387 GroupVersionKind: gvk.ServiceEntry, 388 Name: "selector", 389 Namespace: "selector", 390 CreationTimestamp: GlobalTime, 391 }, 392 Spec: &networking.ServiceEntry{ 393 Hosts: []string{"selector.com"}, 394 Ports: []*networking.ServicePort{ 395 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 396 {Number: 445, Name: "http-445", Protocol: "http"}, 397 }, 398 WorkloadSelector: &networking.WorkloadSelector{ 399 Labels: map[string]string{"app": "wle"}, 400 }, 401 Resolution: networking.ServiceEntry_DNS, 402 }, 403 } 404 405 // ServiceEntry with a selector 406 var selector = &config.Config{ 407 Meta: config.Meta{ 408 GroupVersionKind: gvk.ServiceEntry, 409 Name: "selector", 410 Namespace: "selector", 411 CreationTimestamp: GlobalTime, 412 }, 413 Spec: &networking.ServiceEntry{ 414 Hosts: []string{"selector.com"}, 415 Ports: []*networking.ServicePort{ 416 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 417 {Number: 445, Name: "http-445", Protocol: "http"}, 418 }, 419 WorkloadSelector: &networking.WorkloadSelector{ 420 Labels: map[string]string{"app": "wle"}, 421 }, 422 Resolution: networking.ServiceEntry_STATIC, 423 }, 424 } 425 426 // DNS ServiceEntry with a selector 427 var dnsSelector = &config.Config{ 428 Meta: config.Meta{ 429 GroupVersionKind: gvk.ServiceEntry, 430 Name: "dns-selector", 431 Namespace: "dns-selector", 432 CreationTimestamp: GlobalTime, 433 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 434 }, 435 Spec: &networking.ServiceEntry{ 436 Hosts: []string{"dns.selector.com"}, 437 Ports: []*networking.ServicePort{ 438 {Number: 444, Name: "tcp-444", Protocol: "tcp"}, 439 {Number: 445, Name: "http-445", Protocol: "http"}, 440 }, 441 WorkloadSelector: &networking.WorkloadSelector{ 442 Labels: map[string]string{"app": "dns-wle"}, 443 }, 444 Resolution: networking.ServiceEntry_DNS, 445 }, 446 } 447 448 // Service Entry with DNSRoundRobinLB 449 var dnsRoundRobinLBSE1 = &config.Config{ 450 Meta: config.Meta{ 451 GroupVersionKind: gvk.ServiceEntry, 452 Name: "dns-round-robin-1", 453 Namespace: "dns", 454 CreationTimestamp: GlobalTime, 455 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 456 }, 457 Spec: &networking.ServiceEntry{ 458 Hosts: []string{"example.com"}, 459 Ports: []*networking.ServicePort{ 460 {Number: 445, Name: "http-445", Protocol: "http"}, 461 {Number: 446, Name: "http-446", Protocol: "http"}, 462 }, 463 Resolution: networking.ServiceEntry_DNS_ROUND_ROBIN, 464 }, 465 } 466 467 var dnsRoundRobinLBSE2 = &config.Config{ 468 Meta: config.Meta{ 469 GroupVersionKind: gvk.ServiceEntry, 470 Name: "dns-round-robin-2", 471 Namespace: "dns", 472 CreationTimestamp: GlobalTime, 473 Labels: map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel}, 474 }, 475 Spec: &networking.ServiceEntry{ 476 Hosts: []string{"example.com"}, 477 Ports: []*networking.ServicePort{ 478 {Number: 445, Name: "http-445", Protocol: "http"}, 479 }, 480 Resolution: networking.ServiceEntry_DNS_ROUND_ROBIN, 481 }, 482 } 483 484 func createWorkloadEntry(name, namespace string, spec *networking.WorkloadEntry) *config.Config { 485 return &config.Config{ 486 Meta: config.Meta{ 487 GroupVersionKind: gvk.WorkloadEntry, 488 Name: name, 489 Namespace: namespace, 490 CreationTimestamp: GlobalTime, 491 }, 492 Spec: spec, 493 } 494 } 495 496 func convertPortNameToProtocol(name string) protocol.Instance { 497 prefix := name 498 i := strings.Index(name, "-") 499 if i >= 0 { 500 prefix = name[:i] 501 } 502 return protocol.Parse(prefix) 503 } 504 505 func makeService(hostname host.Name, configNamespace, address string, ports map[string]int, 506 external bool, resolution model.Resolution, serviceAccounts ...string, 507 ) *model.Service { 508 svc := &model.Service{ 509 CreationTime: GlobalTime, 510 Hostname: hostname, 511 DefaultAddress: address, 512 MeshExternal: external, 513 Resolution: resolution, 514 ServiceAccounts: serviceAccounts, 515 Attributes: model.ServiceAttributes{ 516 ServiceRegistry: provider.External, 517 Name: string(hostname), 518 Namespace: configNamespace, 519 }, 520 } 521 522 if external && features.CanonicalServiceForMeshExternalServiceEntry { 523 if svc.Attributes.Labels == nil { 524 svc.Attributes.Labels = make(map[string]string) 525 } 526 svc.Attributes.Labels["service.istio.io/canonical-name"] = configNamespace 527 svc.Attributes.Labels["service.istio.io/canonical-revision"] = "latest" 528 } 529 530 svcPorts := make(model.PortList, 0, len(ports)) 531 for name, port := range ports { 532 svcPort := &model.Port{ 533 Name: name, 534 Port: port, 535 Protocol: convertPortNameToProtocol(name), 536 } 537 svcPorts = append(svcPorts, svcPort) 538 } 539 540 sortPorts(svcPorts) 541 svc.Ports = svcPorts 542 return svc 543 } 544 545 // MTLSMode is the expected instance mtls settings. This is for test setup only 546 type MTLSMode int 547 548 const ( 549 MTLS = iota 550 // Like mTLS, but no label is defined on the endpoint 551 MTLSUnlabelled 552 PlainText 553 ) 554 555 // nolint: unparam 556 func makeInstanceWithServiceAccount(cfg *config.Config, address string, port int, 557 svcPort *networking.ServicePort, svcLabels map[string]string, serviceAccount string, 558 ) *model.ServiceInstance { 559 i := makeInstance(cfg, address, port, svcPort, svcLabels, MTLSUnlabelled) 560 i.Endpoint.ServiceAccount = spiffe.MustGenSpiffeURI(i.Service.Attributes.Namespace, serviceAccount) 561 return i 562 } 563 564 // nolint: unparam 565 func makeTarget(cfg *config.Config, address string, port int, 566 svcPort *networking.ServicePort, svcLabels map[string]string, mtlsMode MTLSMode, 567 ) model.ServiceTarget { 568 services := convertServices(*cfg) 569 svc := services[0] // default 570 for _, s := range services { 571 if string(s.Hostname) == address { 572 svc = s 573 break 574 } 575 } 576 if mtlsMode == MTLS { 577 if svcLabels == nil { 578 svcLabels = map[string]string{} 579 } 580 svcLabels[label.SecurityTlsMode.Name] = model.IstioMutualTLSModeLabel 581 } 582 return model.ServiceTarget{ 583 Service: svc, 584 Port: model.ServiceInstancePort{ 585 ServicePort: &model.Port{ 586 Name: svcPort.Name, 587 Port: int(svcPort.Number), 588 Protocol: protocol.Parse(svcPort.Protocol), 589 }, 590 TargetPort: uint32(port), 591 }, 592 } 593 } 594 595 // nolint: unparam 596 func makeInstance(cfg *config.Config, address string, port int, 597 svcPort *networking.ServicePort, svcLabels map[string]string, mtlsMode MTLSMode, 598 ) *model.ServiceInstance { 599 services := convertServices(*cfg) 600 svc := services[0] // default 601 for _, s := range services { 602 if string(s.Hostname) == address { 603 svc = s 604 break 605 } 606 } 607 tlsMode := model.DisabledTLSModeLabel 608 if mtlsMode == MTLS || mtlsMode == MTLSUnlabelled { 609 tlsMode = model.IstioMutualTLSModeLabel 610 } 611 if mtlsMode == MTLS { 612 if svcLabels == nil { 613 svcLabels = map[string]string{} 614 } 615 svcLabels[label.SecurityTlsMode.Name] = model.IstioMutualTLSModeLabel 616 } 617 return &model.ServiceInstance{ 618 Service: svc, 619 Endpoint: &model.IstioEndpoint{ 620 Address: address, 621 EndpointPort: uint32(port), 622 ServicePortName: svcPort.Name, 623 LegacyClusterPortKey: int(svcPort.Number), 624 Labels: svcLabels, 625 TLSMode: tlsMode, 626 }, 627 ServicePort: &model.Port{ 628 Name: svcPort.Name, 629 Port: int(svcPort.Number), 630 Protocol: protocol.Parse(svcPort.Protocol), 631 }, 632 } 633 } 634 635 func TestConvertService(t *testing.T) { 636 testConvertServiceBody(t) 637 test.SetForTest(t, &features.CanonicalServiceForMeshExternalServiceEntry, true) 638 testConvertServiceBody(t) 639 } 640 641 func testConvertServiceBody(t *testing.T) { 642 t.Helper() 643 644 serviceTests := []struct { 645 externalSvc *config.Config 646 services []*model.Service 647 }{ 648 { 649 // service entry http 650 externalSvc: httpNone, 651 services: []*model.Service{ 652 makeService("*.google.com", "httpNone", constants.UnspecifiedIP, 653 map[string]int{"http-number": 80, "http2-number": 8080}, true, model.Passthrough), 654 }, 655 }, 656 { 657 // service entry tcp 658 externalSvc: tcpNone, 659 services: []*model.Service{ 660 makeService("tcpnone.com", "tcpNone", "172.217.0.0/16", 661 map[string]int{"tcp-444": 444}, true, model.Passthrough), 662 }, 663 }, 664 { 665 // service entry http static 666 externalSvc: httpStatic, 667 services: []*model.Service{ 668 makeService("*.google.com", "httpStatic", constants.UnspecifiedIP, 669 map[string]int{"http-port": 80, "http-alt-port": 8080}, true, model.ClientSideLB), 670 }, 671 }, 672 { 673 // service entry DNS with no endpoints 674 externalSvc: httpDNSnoEndpoints, 675 services: []*model.Service{ 676 makeService("google.com", "httpDNSnoEndpoints", constants.UnspecifiedIP, 677 map[string]int{"http-port": 80, "http-alt-port": 8080}, true, model.DNSLB, "google.com"), 678 makeService("www.wikipedia.org", "httpDNSnoEndpoints", constants.UnspecifiedIP, 679 map[string]int{"http-port": 80, "http-alt-port": 8080}, true, model.DNSLB, "google.com"), 680 }, 681 }, 682 { 683 // service entry dns 684 externalSvc: httpDNS, 685 services: []*model.Service{ 686 makeService("*.google.com", "httpDNS", constants.UnspecifiedIP, 687 map[string]int{"http-port": 80, "http-alt-port": 8080}, true, model.DNSLB), 688 }, 689 }, 690 { 691 // service entry dns with target port 692 externalSvc: dnsTargetPort, 693 services: []*model.Service{ 694 makeService("google.com", "dnsTargetPort", constants.UnspecifiedIP, 695 map[string]int{"http-port": 80}, true, model.DNSLB), 696 }, 697 }, 698 { 699 // service entry tcp DNS 700 externalSvc: tcpDNS, 701 services: []*model.Service{ 702 makeService("tcpdns.com", "tcpDNS", constants.UnspecifiedIP, 703 map[string]int{"tcp-444": 444}, true, model.DNSLB), 704 }, 705 }, 706 { 707 // service entry tcp static 708 externalSvc: tcpStatic, 709 services: []*model.Service{ 710 makeService("tcpstatic.com", "tcpStatic", "172.217.0.1", 711 map[string]int{"tcp-444": 444}, true, model.ClientSideLB), 712 }, 713 }, 714 { 715 // service entry http internal 716 externalSvc: httpNoneInternal, 717 services: []*model.Service{ 718 makeService("*.google.com", "httpNoneInternal", constants.UnspecifiedIP, 719 map[string]int{"http-number": 80, "http2-number": 8080}, false, model.Passthrough), 720 }, 721 }, 722 { 723 // service entry tcp internal 724 externalSvc: tcpNoneInternal, 725 services: []*model.Service{ 726 makeService("tcpinternal.com", "tcpNoneInternal", "172.217.0.0/16", 727 map[string]int{"tcp-444": 444}, false, model.Passthrough), 728 }, 729 }, 730 { 731 // service entry multiAddrInternal 732 externalSvc: multiAddrInternal, 733 services: []*model.Service{ 734 makeService("tcp1.com", "multiAddrInternal", "1.1.1.0/16", 735 map[string]int{"tcp-444": 444}, false, model.Passthrough), 736 makeService("tcp1.com", "multiAddrInternal", "2.2.2.0/16", 737 map[string]int{"tcp-444": 444}, false, model.Passthrough), 738 makeService("tcp2.com", "multiAddrInternal", "1.1.1.0/16", 739 map[string]int{"tcp-444": 444}, false, model.Passthrough), 740 makeService("tcp2.com", "multiAddrInternal", "2.2.2.0/16", 741 map[string]int{"tcp-444": 444}, false, model.Passthrough), 742 }, 743 }, 744 } 745 746 selectorSvc := makeService("selector.com", "selector", "0.0.0.0", 747 map[string]int{"tcp-444": 444, "http-445": 445}, true, model.ClientSideLB) 748 selectorSvc.Attributes.LabelSelectors = map[string]string{"app": "wle"} 749 750 serviceTests = append(serviceTests, struct { 751 externalSvc *config.Config 752 services []*model.Service 753 }{ 754 externalSvc: selector, 755 services: []*model.Service{selectorSvc}, 756 }) 757 758 for _, tt := range serviceTests { 759 services := convertServices(*tt.externalSvc) 760 if err := compare(t, services, tt.services); err != nil { 761 t.Errorf("testcase: %v\n%v ", tt.externalSvc.Name, err) 762 } 763 } 764 } 765 766 func TestConvertInstances(t *testing.T) { 767 serviceInstanceTests := []struct { 768 externalSvc *config.Config 769 out []*model.ServiceInstance 770 }{ 771 { 772 // single instance with multiple ports 773 externalSvc: httpNone, 774 // DNS type none means service should not have a registered instance 775 out: []*model.ServiceInstance{}, 776 }, 777 { 778 // service entry tcp 779 externalSvc: tcpNone, 780 // DNS type none means service should not have a registered instance 781 out: []*model.ServiceInstance{}, 782 }, 783 { 784 // service entry static 785 externalSvc: httpStatic, 786 out: []*model.ServiceInstance{ 787 makeInstance(httpStatic, "2.2.2.2", 7080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 788 makeInstance(httpStatic, "2.2.2.2", 18080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS), 789 makeInstance(httpStatic, "3.3.3.3", 1080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 790 makeInstance(httpStatic, "3.3.3.3", 8080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS), 791 makeInstance(httpStatic, "4.4.4.4", 1080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"foo": "bar"}, PlainText), 792 makeInstance(httpStatic, "4.4.4.4", 8080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"foo": "bar"}, PlainText), 793 }, 794 }, 795 { 796 // service entry DNS with no endpoints 797 externalSvc: httpDNSnoEndpoints, 798 out: []*model.ServiceInstance{ 799 makeInstance(httpDNSnoEndpoints, "google.com", 80, httpDNSnoEndpoints.Spec.(*networking.ServiceEntry).Ports[0], nil, PlainText), 800 makeInstance(httpDNSnoEndpoints, "google.com", 8080, httpDNSnoEndpoints.Spec.(*networking.ServiceEntry).Ports[1], nil, PlainText), 801 makeInstance(httpDNSnoEndpoints, "www.wikipedia.org", 80, httpDNSnoEndpoints.Spec.(*networking.ServiceEntry).Ports[0], nil, PlainText), 802 makeInstance(httpDNSnoEndpoints, "www.wikipedia.org", 8080, httpDNSnoEndpoints.Spec.(*networking.ServiceEntry).Ports[1], nil, PlainText), 803 }, 804 }, 805 { 806 // service entry DNS with no endpoints using round robin 807 externalSvc: httpDNSRRnoEndpoints, 808 out: []*model.ServiceInstance{ 809 makeInstance(httpDNSRRnoEndpoints, "api.istio.io", 80, httpDNSnoEndpoints.Spec.(*networking.ServiceEntry).Ports[0], nil, PlainText), 810 makeInstance(httpDNSRRnoEndpoints, "api.istio.io", 8080, httpDNSnoEndpoints.Spec.(*networking.ServiceEntry).Ports[1], nil, PlainText), 811 }, 812 }, 813 { 814 // service entry DNS with workload selector and no endpoints 815 externalSvc: selectorDNS, 816 out: []*model.ServiceInstance{}, 817 }, 818 { 819 // service entry dns 820 externalSvc: httpDNS, 821 out: []*model.ServiceInstance{ 822 makeInstance(httpDNS, "us.google.com", 7080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 823 makeInstance(httpDNS, "us.google.com", 18080, httpDNS.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS), 824 makeInstance(httpDNS, "uk.google.com", 1080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 825 makeInstance(httpDNS, "uk.google.com", 8080, httpDNS.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS), 826 makeInstance(httpDNS, "de.google.com", 80, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"foo": "bar"}, MTLS), 827 makeInstance(httpDNS, "de.google.com", 8080, httpDNS.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"foo": "bar"}, MTLS), 828 }, 829 }, 830 { 831 // service entry dns with target port 832 externalSvc: dnsTargetPort, 833 out: []*model.ServiceInstance{ 834 makeInstance(dnsTargetPort, "google.com", 8080, dnsTargetPort.Spec.(*networking.ServiceEntry).Ports[0], nil, PlainText), 835 }, 836 }, 837 { 838 // service entry tcp DNS 839 externalSvc: tcpDNS, 840 out: []*model.ServiceInstance{ 841 makeInstance(tcpDNS, "lon.google.com", 444, tcpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 842 makeInstance(tcpDNS, "in.google.com", 444, tcpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 843 }, 844 }, 845 { 846 // service entry tcp static 847 externalSvc: tcpStatic, 848 out: []*model.ServiceInstance{ 849 makeInstance(tcpStatic, "1.1.1.1", 444, tcpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 850 makeInstance(tcpStatic, "2.2.2.2", 444, tcpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 851 }, 852 }, 853 { 854 // service entry unix domain socket static 855 externalSvc: udsLocal, 856 out: []*model.ServiceInstance{ 857 makeInstance(udsLocal, "/test/sock", 0, udsLocal.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS), 858 }, 859 }, 860 } 861 862 for _, tt := range serviceInstanceTests { 863 t.Run(strings.Join(tt.externalSvc.Spec.(*networking.ServiceEntry).Hosts, "_"), func(t *testing.T) { 864 s := &Controller{} 865 instances := s.convertServiceEntryToInstances(*tt.externalSvc, nil) 866 sortServiceInstances(instances) 867 sortServiceInstances(tt.out) 868 if err := compare(t, instances, tt.out); err != nil { 869 t.Fatalf("testcase: %v\n%v", tt.externalSvc.Name, err) 870 } 871 }) 872 } 873 } 874 875 func TestConvertWorkloadEntryToServiceInstances(t *testing.T) { 876 labels := map[string]string{ 877 "app": "wle", 878 } 879 serviceInstanceTests := []struct { 880 name string 881 wle *networking.WorkloadEntry 882 se *config.Config 883 clusterID cluster.ID 884 out []*model.ServiceInstance 885 }{ 886 { 887 name: "simple", 888 wle: &networking.WorkloadEntry{ 889 Address: "1.1.1.1", 890 Labels: labels, 891 }, 892 se: selector, 893 out: []*model.ServiceInstance{ 894 makeInstance(selector, "1.1.1.1", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], labels, PlainText), 895 makeInstance(selector, "1.1.1.1", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], labels, PlainText), 896 }, 897 }, 898 { 899 name: "mtls", 900 wle: &networking.WorkloadEntry{ 901 Address: "1.1.1.1", 902 Labels: labels, 903 ServiceAccount: "default", 904 }, 905 se: selector, 906 out: []*model.ServiceInstance{ 907 makeInstanceWithServiceAccount(selector, "1.1.1.1", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], labels, "default"), 908 makeInstanceWithServiceAccount(selector, "1.1.1.1", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], labels, "default"), 909 }, 910 }, 911 { 912 name: "replace-port", 913 wle: &networking.WorkloadEntry{ 914 Address: "1.1.1.1", 915 Labels: labels, 916 Ports: map[string]uint32{ 917 "http-445": 8080, 918 }, 919 }, 920 se: selector, 921 out: []*model.ServiceInstance{ 922 makeInstance(selector, "1.1.1.1", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], labels, PlainText), 923 makeInstance(selector, "1.1.1.1", 8080, selector.Spec.(*networking.ServiceEntry).Ports[1], labels, PlainText), 924 }, 925 }, 926 { 927 name: "augment label", 928 wle: &networking.WorkloadEntry{ 929 Address: "1.1.1.1", 930 Labels: labels, 931 Locality: "region1/zone1/sunzone1", 932 Network: "network1", 933 ServiceAccount: "default", 934 }, 935 se: selector, 936 clusterID: "fakeCluster", 937 out: []*model.ServiceInstance{ 938 makeInstanceWithServiceAccount(selector, "1.1.1.1", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], labels, "default"), 939 makeInstanceWithServiceAccount(selector, "1.1.1.1", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], labels, "default"), 940 }, 941 }, 942 } 943 944 for _, tt := range serviceInstanceTests { 945 t.Run(tt.name, func(t *testing.T) { 946 services := convertServices(*tt.se) 947 s := &Controller{} 948 instances := s.convertWorkloadEntryToServiceInstances(tt.wle, services, tt.se.Spec.(*networking.ServiceEntry), &configKey{}, tt.clusterID) 949 sortServiceInstances(instances) 950 sortServiceInstances(tt.out) 951 952 if tt.wle.Locality != "" || tt.clusterID != "" || tt.wle.Network != "" { 953 for _, serviceInstance := range tt.out { 954 serviceInstance.Endpoint.Locality = model.Locality{ 955 Label: tt.wle.Locality, 956 ClusterID: tt.clusterID, 957 } 958 serviceInstance.Endpoint.Network = network.ID(tt.wle.Network) 959 serviceInstance.Endpoint.Labels = labelutil.AugmentLabels(serviceInstance.Endpoint.Labels, tt.clusterID, tt.wle.Locality, "", network.ID(tt.wle.Network)) 960 } 961 } 962 963 if err := compare(t, instances, tt.out); err != nil { 964 t.Fatal(err) 965 } 966 }) 967 } 968 } 969 970 func TestConvertWorkloadEntryToWorkloadInstance(t *testing.T) { 971 workloadLabel := map[string]string{ 972 "app": "wle", 973 } 974 975 clusterID := "fakeCluster" 976 expectedLabel := map[string]string{ 977 "app": "wle", 978 "topology.istio.io/cluster": clusterID, 979 } 980 981 workloadInstanceTests := []struct { 982 name string 983 getNetworkIDCb func(IP string, labels labels.Instance) network.ID 984 wle config.Config 985 out *model.WorkloadInstance 986 }{ 987 { 988 name: "simple", 989 wle: config.Config{ 990 Meta: config.Meta{ 991 Namespace: "ns1", 992 }, 993 Spec: &networking.WorkloadEntry{ 994 Address: "1.1.1.1", 995 Labels: workloadLabel, 996 Ports: map[string]uint32{ 997 "http": 80, 998 }, 999 ServiceAccount: "scooby", 1000 }, 1001 }, 1002 out: &model.WorkloadInstance{ 1003 Namespace: "ns1", 1004 Kind: model.WorkloadEntryKind, 1005 Endpoint: &model.IstioEndpoint{ 1006 Labels: expectedLabel, 1007 Address: "1.1.1.1", 1008 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1009 TLSMode: "istio", 1010 Namespace: "ns1", 1011 Locality: model.Locality{ 1012 ClusterID: cluster.ID(clusterID), 1013 }, 1014 }, 1015 PortMap: map[string]uint32{ 1016 "http": 80, 1017 }, 1018 }, 1019 }, 1020 { 1021 name: "simple - tls mode disabled", 1022 wle: config.Config{ 1023 Meta: config.Meta{ 1024 Namespace: "ns1", 1025 }, 1026 Spec: &networking.WorkloadEntry{ 1027 Address: "1.1.1.1", 1028 Labels: map[string]string{ 1029 "security.istio.io/tlsMode": "disabled", 1030 }, 1031 Ports: map[string]uint32{ 1032 "http": 80, 1033 }, 1034 ServiceAccount: "scooby", 1035 }, 1036 }, 1037 out: &model.WorkloadInstance{ 1038 Namespace: "ns1", 1039 Kind: model.WorkloadEntryKind, 1040 Endpoint: &model.IstioEndpoint{ 1041 Labels: map[string]string{ 1042 "security.istio.io/tlsMode": "disabled", 1043 "topology.istio.io/cluster": clusterID, 1044 }, 1045 Address: "1.1.1.1", 1046 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1047 TLSMode: "disabled", 1048 Namespace: "ns1", 1049 Locality: model.Locality{ 1050 ClusterID: cluster.ID(clusterID), 1051 }, 1052 }, 1053 PortMap: map[string]uint32{ 1054 "http": 80, 1055 }, 1056 }, 1057 }, 1058 { 1059 name: "unix domain socket", 1060 wle: config.Config{ 1061 Meta: config.Meta{ 1062 Namespace: "ns1", 1063 }, 1064 Spec: &networking.WorkloadEntry{ 1065 Address: "unix://foo/bar", 1066 ServiceAccount: "scooby", 1067 }, 1068 }, 1069 out: &model.WorkloadInstance{ 1070 Namespace: "ns1", 1071 Kind: model.WorkloadEntryKind, 1072 Endpoint: &model.IstioEndpoint{ 1073 Labels: map[string]string{ 1074 "topology.istio.io/cluster": clusterID, 1075 }, 1076 Address: "unix://foo/bar", 1077 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1078 TLSMode: "istio", 1079 Namespace: "ns1", 1080 Locality: model.Locality{ 1081 ClusterID: cluster.ID(clusterID), 1082 }, 1083 }, 1084 DNSServiceEntryOnly: true, 1085 }, 1086 }, 1087 { 1088 name: "DNS address", 1089 wle: config.Config{ 1090 Meta: config.Meta{ 1091 Namespace: "ns1", 1092 }, 1093 Spec: &networking.WorkloadEntry{ 1094 Address: "scooby.com", 1095 ServiceAccount: "scooby", 1096 }, 1097 }, 1098 out: &model.WorkloadInstance{ 1099 Namespace: "ns1", 1100 Kind: model.WorkloadEntryKind, 1101 Endpoint: &model.IstioEndpoint{ 1102 Labels: map[string]string{ 1103 "topology.istio.io/cluster": clusterID, 1104 }, 1105 Address: "scooby.com", 1106 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1107 TLSMode: "istio", 1108 Namespace: "ns1", 1109 Locality: model.Locality{ 1110 ClusterID: cluster.ID(clusterID), 1111 }, 1112 }, 1113 DNSServiceEntryOnly: true, 1114 }, 1115 }, 1116 { 1117 name: "metadata labels only", 1118 wle: config.Config{ 1119 Meta: config.Meta{ 1120 Labels: workloadLabel, 1121 Namespace: "ns1", 1122 }, 1123 Spec: &networking.WorkloadEntry{ 1124 Address: "1.1.1.1", 1125 Ports: map[string]uint32{ 1126 "http": 80, 1127 }, 1128 ServiceAccount: "scooby", 1129 }, 1130 }, 1131 out: &model.WorkloadInstance{ 1132 Namespace: "ns1", 1133 Kind: model.WorkloadEntryKind, 1134 Endpoint: &model.IstioEndpoint{ 1135 Labels: expectedLabel, 1136 Address: "1.1.1.1", 1137 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1138 TLSMode: "istio", 1139 Namespace: "ns1", 1140 Locality: model.Locality{ 1141 ClusterID: cluster.ID(clusterID), 1142 }, 1143 }, 1144 PortMap: map[string]uint32{ 1145 "http": 80, 1146 }, 1147 }, 1148 }, 1149 { 1150 name: "labels merge", 1151 wle: config.Config{ 1152 Meta: config.Meta{ 1153 Namespace: "ns1", 1154 Labels: map[string]string{ 1155 "my-label": "bar", 1156 }, 1157 }, 1158 Spec: &networking.WorkloadEntry{ 1159 Address: "1.1.1.1", 1160 Labels: workloadLabel, 1161 Ports: map[string]uint32{ 1162 "http": 80, 1163 }, 1164 ServiceAccount: "scooby", 1165 }, 1166 }, 1167 out: &model.WorkloadInstance{ 1168 Namespace: "ns1", 1169 Kind: model.WorkloadEntryKind, 1170 Endpoint: &model.IstioEndpoint{ 1171 Labels: map[string]string{ 1172 "my-label": "bar", 1173 "app": "wle", 1174 "topology.istio.io/cluster": clusterID, 1175 }, 1176 Address: "1.1.1.1", 1177 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1178 TLSMode: "istio", 1179 Namespace: "ns1", 1180 Locality: model.Locality{ 1181 ClusterID: cluster.ID(clusterID), 1182 }, 1183 }, 1184 PortMap: map[string]uint32{ 1185 "http": 80, 1186 }, 1187 }, 1188 }, 1189 { 1190 name: "augment labels", 1191 wle: config.Config{ 1192 Meta: config.Meta{ 1193 Namespace: "ns1", 1194 }, 1195 Spec: &networking.WorkloadEntry{ 1196 Address: "1.1.1.1", 1197 Labels: workloadLabel, 1198 Ports: map[string]uint32{ 1199 "http": 80, 1200 }, 1201 Locality: "region1/zone1/subzone1", 1202 Network: "network1", 1203 ServiceAccount: "scooby", 1204 }, 1205 }, 1206 out: &model.WorkloadInstance{ 1207 Namespace: "ns1", 1208 Kind: model.WorkloadEntryKind, 1209 Endpoint: &model.IstioEndpoint{ 1210 Labels: map[string]string{ 1211 "app": "wle", 1212 "topology.kubernetes.io/region": "region1", 1213 "topology.kubernetes.io/zone": "zone1", 1214 "topology.istio.io/subzone": "subzone1", 1215 "topology.istio.io/network": "network1", 1216 "topology.istio.io/cluster": clusterID, 1217 }, 1218 Address: "1.1.1.1", 1219 Network: "network1", 1220 Locality: model.Locality{ 1221 Label: "region1/zone1/subzone1", 1222 ClusterID: cluster.ID(clusterID), 1223 }, 1224 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1225 TLSMode: "istio", 1226 Namespace: "ns1", 1227 }, 1228 PortMap: map[string]uint32{ 1229 "http": 80, 1230 }, 1231 }, 1232 }, 1233 { 1234 name: "augment labels: networkID get from cb", 1235 wle: config.Config{ 1236 Meta: config.Meta{ 1237 Namespace: "ns1", 1238 }, 1239 Spec: &networking.WorkloadEntry{ 1240 Address: "1.1.1.1", 1241 Labels: workloadLabel, 1242 Ports: map[string]uint32{ 1243 "http": 80, 1244 }, 1245 Locality: "region1/zone1/subzone1", 1246 ServiceAccount: "scooby", 1247 }, 1248 }, 1249 getNetworkIDCb: func(IP string, labels labels.Instance) network.ID { 1250 return "cb-network1" 1251 }, 1252 out: &model.WorkloadInstance{ 1253 Namespace: "ns1", 1254 Kind: model.WorkloadEntryKind, 1255 Endpoint: &model.IstioEndpoint{ 1256 Labels: map[string]string{ 1257 "app": "wle", 1258 "topology.kubernetes.io/region": "region1", 1259 "topology.kubernetes.io/zone": "zone1", 1260 "topology.istio.io/subzone": "subzone1", 1261 "topology.istio.io/network": "cb-network1", 1262 "topology.istio.io/cluster": clusterID, 1263 }, 1264 Address: "1.1.1.1", 1265 Locality: model.Locality{ 1266 Label: "region1/zone1/subzone1", 1267 ClusterID: cluster.ID(clusterID), 1268 }, 1269 ServiceAccount: "spiffe://cluster.local/ns/ns1/sa/scooby", 1270 TLSMode: "istio", 1271 Namespace: "ns1", 1272 }, 1273 PortMap: map[string]uint32{ 1274 "http": 80, 1275 }, 1276 }, 1277 }, 1278 } 1279 1280 for _, tt := range workloadInstanceTests { 1281 t.Run(tt.name, func(t *testing.T) { 1282 s := &Controller{networkIDCallback: tt.getNetworkIDCb} 1283 instance := s.convertWorkloadEntryToWorkloadInstance(tt.wle, cluster.ID(clusterID)) 1284 if err := compare(t, instance, tt.out); err != nil { 1285 t.Fatal(err) 1286 } 1287 }) 1288 } 1289 } 1290 1291 func compare[T any](t testing.TB, actual, expected T) error { 1292 return util.Compare(jsonBytes(t, actual), jsonBytes(t, expected)) 1293 } 1294 1295 func jsonBytes(t testing.TB, v any) []byte { 1296 data, err := json.MarshalIndent(v, "", " ") 1297 if err != nil { 1298 t.Fatal(t) 1299 } 1300 return data 1301 }