From 87a53778a8817d471e53be08630e5abd666a4265 Mon Sep 17 00:00:00 2001 From: Karsten Siemer Date: Mon, 4 Dec 2023 15:15:08 +0100 Subject: [PATCH] =?UTF-8?q?fix(istio):=20support=20for=20ExternalIPs=20in?= =?UTF-8?q?=20Istio=20resources=20=E2=9C=A8=20Add=20support=20for=20Extern?= =?UTF-8?q?alIPs=20in=20Istio=20Gateway=20and=20VirtualService=20=E2=84=B9?= =?UTF-8?q?=EF=B8=8F=20This=20commit=20extends=20Istio=20Gateway=20and=20V?= =?UTF-8?q?irtualService=20resources=20to=20support=20ExternalIPs.=20The?= =?UTF-8?q?=20changes=20include:=20-=20Checking=20if=20service=20has=20Ext?= =?UTF-8?q?ernalIPs=20defined=20-=20If=20yes,=20adding=20them=20to=20the?= =?UTF-8?q?=20list=20of=20targets=20-=20If=20not,=20continuing=20with=20th?= =?UTF-8?q?e=20existing=20process?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 👌 Now you can have your Istio resources use `externalIPs` too! 🎉 Not to be `ip`-percritical, but don't we all love an `ip`grade! 🎈 Signed-off-by: Karsten Siemer --- source/istio_gateway.go | 5 + source/istio_gateway_test.go | 66 ++++++++++++-- source/istio_virtualservice.go | 5 + source/istio_virtualservice_test.go | 137 ++++++++++++++++++++++++++-- 4 files changed, 197 insertions(+), 16 deletions(-) diff --git a/source/istio_gateway.go b/source/istio_gateway.go index 1c780c31c..d158b30a7 100644 --- a/source/istio_gateway.go +++ b/source/istio_gateway.go @@ -289,6 +289,11 @@ func (sc *gatewaySource) targetsFromGateway(ctx context.Context, gateway *networ continue } + if len(service.Spec.ExternalIPs) > 0 { + targets = append(targets, service.Spec.ExternalIPs...) + continue + } + for _, lb := range service.Status.LoadBalancer.Ingress { if lb.IP != "" { targets = append(targets, lb.IP) diff --git a/source/istio_gateway_test.go b/source/istio_gateway_test.go index f8450c5e5..9c74d7a7f 100644 --- a/source/istio_gateway_test.go +++ b/source/istio_gateway_test.go @@ -337,8 +337,9 @@ func testEndpointsFromGatewayConfig(t *testing.T) { title: "no rule.host", lbServices: []fakeIngressGatewayService{ { - ips: []string{"8.8.8.8", "127.0.0.1"}, - hostnames: []string{"elb.com", "alb.com"}, + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, }, }, config: fakeGatewayConfig{ @@ -350,8 +351,9 @@ func testEndpointsFromGatewayConfig(t *testing.T) { title: "one empty rule.host", lbServices: []fakeIngressGatewayService{ { - ips: []string{"8.8.8.8", "127.0.0.1"}, - hostnames: []string{"elb.com", "alb.com"}, + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, }, }, config: fakeGatewayConfig{ @@ -447,6 +449,48 @@ func testEndpointsFromGatewayConfig(t *testing.T) { }, }, }, + { + title: "one rule.host one lb.externalIP", + lbServices: []fakeIngressGatewayService{ + { + externalIPs: []string{"8.8.8.8"}, + }, + }, + config: fakeGatewayConfig{ + dnsnames: [][]string{ + {"foo.bar"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + }, + { + title: "one rule.host two lb.IP, two lb.Hostname and two lb.externalIP", + lbServices: []fakeIngressGatewayService{ + { + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, + }, + }, + config: fakeGatewayConfig{ + dnsnames: [][]string{ + {"foo.bar"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.1.1.1", "2.2.2.2"}, + }, + }, + }, } { ti := ti t.Run(ti.title, func(t *testing.T) { @@ -1521,11 +1565,12 @@ func newTestGatewaySource(loadBalancerList []fakeIngressGatewayService, ingressL } type fakeIngressGatewayService struct { - ips []string - hostnames []string - namespace string - name string - selector map[string]string + ips []string + hostnames []string + namespace string + name string + selector map[string]string + externalIPs []string } func (ig fakeIngressGatewayService) Service() *v1.Service { @@ -1540,7 +1585,8 @@ func (ig fakeIngressGatewayService) Service() *v1.Service { }, }, Spec: v1.ServiceSpec{ - Selector: ig.selector, + Selector: ig.selector, + ExternalIPs: ig.externalIPs, }, } diff --git a/source/istio_virtualservice.go b/source/istio_virtualservice.go index 1eed91d1a..992e1ef1d 100644 --- a/source/istio_virtualservice.go +++ b/source/istio_virtualservice.go @@ -470,6 +470,11 @@ func (sc *virtualServiceSource) targetsFromGateway(ctx context.Context, gateway continue } + if len(service.Spec.ExternalIPs) > 0 { + targets = append(targets, service.Spec.ExternalIPs...) + continue + } + for _, lb := range service.Status.LoadBalancer.Ingress { if lb.IP != "" { targets = append(targets, lb.IP) diff --git a/source/istio_virtualservice_test.go b/source/istio_virtualservice_test.go index d907da2eb..b5bfe3c98 100644 --- a/source/istio_virtualservice_test.go +++ b/source/istio_virtualservice_test.go @@ -450,6 +450,29 @@ func testEndpointsFromVirtualServiceConfig(t *testing.T) { }, }, }, + { + title: "one rule.host one lb.externalIPs", + lbServices: []fakeIngressGatewayService{ + { + externalIPs: []string{"8.8.8.8"}, + }, + }, + gwconfig: fakeGatewayConfig{ + name: "mygw", + dnsnames: [][]string{{"*"}}, + }, + vsconfig: fakeVirtualServiceConfig{ + gateways: []string{"mygw"}, + dnsnames: []string{"foo.bar"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + }, { title: "one rule.host two lb.IP and two lb.Hostname", lbServices: []fakeIngressGatewayService{ @@ -479,12 +502,38 @@ func testEndpointsFromVirtualServiceConfig(t *testing.T) { }, }, }, + { + title: "one rule.host two lb.IP and two lb.Hostname and two lb.externalIPs", + lbServices: []fakeIngressGatewayService{ + { + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, + }, + }, + gwconfig: fakeGatewayConfig{ + name: "mygw", + dnsnames: [][]string{{"*"}}, + }, + vsconfig: fakeVirtualServiceConfig{ + gateways: []string{"mygw"}, + dnsnames: []string{"foo.bar"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.1.1.1", "2.2.2.2"}, + }, + }, + }, { title: "no rule.host", lbServices: []fakeIngressGatewayService{ { - ips: []string{"8.8.8.8", "127.0.0.1"}, - hostnames: []string{"elb.com", "alb.com"}, + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, }, }, gwconfig: fakeGatewayConfig{ @@ -501,8 +550,9 @@ func testEndpointsFromVirtualServiceConfig(t *testing.T) { title: "no rule.gateway", lbServices: []fakeIngressGatewayService{ { - ips: []string{"8.8.8.8", "127.0.0.1"}, - hostnames: []string{"elb.com", "alb.com"}, + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, }, }, gwconfig: fakeGatewayConfig{ @@ -519,8 +569,9 @@ func testEndpointsFromVirtualServiceConfig(t *testing.T) { title: "one empty rule.host", lbServices: []fakeIngressGatewayService{ { - ips: []string{"8.8.8.8", "127.0.0.1"}, - hostnames: []string{"elb.com", "alb.com"}, + ips: []string{"8.8.8.8", "127.0.0.1"}, + hostnames: []string{"elb.com", "alb.com"}, + externalIPs: []string{"1.1.1.1", "2.2.2.2"}, }, }, gwconfig: fakeGatewayConfig{ @@ -844,6 +895,42 @@ func testVirtualServiceEndpoints(t *testing.T) { }, }, }, + { + title: "one virtualservice with two gateways, one ingressgateway loadbalancer service with externalIPs", + lbServices: []fakeIngressGatewayService{ + { + namespace: namespace, + externalIPs: []string{"8.8.8.8"}, + }, + }, + gwConfigs: []fakeGatewayConfig{ + { + name: "gw1", + namespace: namespace, + dnsnames: [][]string{{"*"}}, + }, + { + name: "gw2", + namespace: namespace, + dnsnames: [][]string{{"*"}}, + }, + }, + vsConfigs: []fakeVirtualServiceConfig{ + { + name: "vs", + namespace: namespace, + gateways: []string{"gw1", "gw2"}, + dnsnames: []string{"example.org"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "example.org", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + }, { title: "two simple virtualservices on different namespaces with the same target gateway, one ingressgateway loadbalancer service", lbServices: []fakeIngressGatewayService{ @@ -941,6 +1028,44 @@ func testVirtualServiceEndpoints(t *testing.T) { }, }, }, + { + title: "two simple virtualservices with one gateway on different namespaces and a target namespace, one ingressgateway loadbalancer service with externalIPs", + targetNamespace: "testing1", + lbServices: []fakeIngressGatewayService{ + { + externalIPs: []string{"8.8.8.8"}, + namespace: "testing1", + }, + }, + gwConfigs: []fakeGatewayConfig{ + { + name: "fake1", + namespace: "testing1", + dnsnames: [][]string{{"*"}}, + }, + }, + vsConfigs: []fakeVirtualServiceConfig{ + { + name: "vs1", + namespace: "testing1", + gateways: []string{"testing1/fake1"}, + dnsnames: []string{"example.org"}, + }, + { + name: "vs2", + namespace: "testing2", + gateways: []string{"testing1/fake1"}, + dnsnames: []string{"new.org"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "example.org", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + }, { title: "two simple virtualservices with one gateway on different namespaces and a target namespace, one ingress", targetNamespace: "testing1",