From edb8e6fa14ffb54b7ff3f4e3c23b387cc58df9cc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 08:59:16 +0200 Subject: [PATCH] istio integration Signed-off-by: Andre Baptista Aguas --- .github/workflows/terratest-istiov1beta1.yaml | 81 +++++++ .github/workflows/terratest.yaml | 6 +- .golangci.yaml | 23 +- Makefile | 40 +++- README.md | 7 +- api/v1beta1/gslb_types.go | 8 +- api/v1beta1/zz_generated.deepcopy.go | 2 +- chart/k8gb/crd/k8gb.absa.oss_gslbs.yaml | 90 +++---- chart/k8gb/templates/role.yaml | 11 + chart/k8gb/values.schema.json | 90 ++++--- chart/k8gb/values.yaml | 11 +- controllers/gslb_controller_reconciliation.go | 6 +- .../gslb_controller_reconciliation_test.go | 8 +- controllers/mocks/refresolver_mock.go | 9 +- controllers/providers/dns/external_test.go | 2 +- .../refresolver/{ => ingress}/ingress.go | 82 +++---- .../refresolver/ingress/ingress_test.go | 135 +++++++++++ .../testdata/ingress_multiple_ips.yaml | 26 ++ .../testdata/ingress_multiple_servers.yaml | 1 - .../ingress/testdata/ingress_no_ips.yaml | 24 ++ controllers/refresolver/ingress_test.go | 222 ------------------ .../istiovirtualservice.go | 212 +++++++++++++++++ .../istiovirtualservice_test.go | 150 ++++++++++++ .../testdata/istio_service_multiple_ips.yaml | 21 ++ .../testdata/istio_service_no_ips.yaml | 19 ++ .../istio_virtualservice_multiple_hosts.yaml | 19 ++ .../istio_virtualservice_multiple_routes.yaml | 26 ++ controllers/refresolver/refresolver.go | 43 ++-- controllers/refresolver/refresolver_test.go | 105 +++++++++ ...bedded.yaml => gslb_ingress_embedded.yaml} | 6 +- .../testdata/gslb_ingress_referenced.yaml | 15 ++ ...gslb_ingress_referenced_and_embedded.yaml} | 13 +- .../{gslb_referenced.yaml => gslb_istio.yaml} | 9 +- .../testdata/ingress_embedded.yaml | 10 +- .../testdata/ingress_referenced.yaml | 9 +- .../refresolver/testdata/istio_gateway.yaml | 15 ++ .../refresolver/testdata/istio_service.yaml | 20 ++ .../testdata/istio_virtualservice.yaml | 18 ++ controllers/tracing/tracing.go | 4 +- controllers/utils/yaml.go | 123 +++++++++- ...oss_v1beta1_gslb_cr_failover_ingress.yaml} | 2 +- ...sa.oss_v1beta1_gslb_cr_failover_istio.yaml | 50 ++++ ...sa.oss_v1beta1_gslb_cr_notfound_istio.yaml | 51 ++++ ...s_v1beta1_gslb_cr_roundrobin_ingress.yaml} | 2 +- ....oss_v1beta1_gslb_cr_roundrobin_istio.yaml | 51 ++++ ...a.oss_v1beta1_gslb_cr_unhealthy_istio.yaml | 51 ++++ ...space.yaml => test-namespace-ingress.yaml} | 0 deploy/crds/test-namespace-istio.yaml | 6 + deploy/ingress/istio-ingress-values.yaml | 26 ++ deploy/test-apps/unhealthy-app-svc.yaml | 18 ++ deploy/test-apps/unhealthy-app.yaml | 23 ++ docs/deploy_cloudflare.md | 7 +- docs/deploy_infoblox.md | 7 +- .../cloudflare/test-gslb-failover.yaml | 7 +- docs/examples/route53/k8gb/gslb-failover.yaml | 7 +- .../route53/k8gb/gslb-roundrobin.yaml | 7 +- docs/index.md | 7 +- docs/local.md | 4 +- go.mod | 3 +- go.sum | 76 +----- k3d/test-gslb1.yaml | 5 +- k3d/test-gslb2.yaml | 5 +- k3d/test-gslb3.yaml | 5 +- main.go | 3 +- .../examples/failover-istio-gateway.yaml | 15 ++ terratest/examples/failover-istio-gslb.yaml | 14 ++ .../failover-istio-virtualservice.yaml | 17 ++ .../failover-playground-istio-gateway.yaml | 15 ++ .../failover-playground-istio-gslb.yaml | 14 ++ ...lover-playground-istio-virtualservice.yaml | 17 ++ .../failover-playground-ref-gslb.yaml | 9 +- .../failover-playground-ref-ingress.yaml | 4 +- terratest/examples/failover-playground.yaml | 2 +- terratest/examples/failover-ref-gslb.yaml | 7 +- terratest/examples/failover.yaml | 14 +- .../roundrobin-weight1-istio-gateway.yaml | 15 ++ .../roundrobin-weight1-istio-gslb.yaml | 16 ++ ...undrobin-weight1-istio-virtualservice.yaml | 17 ++ .../examples/roundrobin-weight1-ref-gslb.yaml | 7 +- .../examples/roundrobin2-istio-gateway.yaml | 15 ++ .../examples/roundrobin2-istio-gslb.yaml | 13 + .../roundrobin2-istio-virtualservice.yaml | 17 ++ terratest/examples/roundrobin2-ref-gslb.yaml | 7 +- .../k8gb_abstract_full_roundrobin_test.go | 24 +- .../test/k8gb_failover_playground_test.go | 47 +--- terratest/test/k8gb_full_failover_test.go | 47 +--- terratest/test/k8gb_full_roundrobin_test.go | 33 ++- terratest/test/k8gb_weight_test.go | 48 ++-- terratest/utils/extensions.go | 150 ++++++++++-- terratest/utils/utils.go | 4 +- 90 files changed, 2017 insertions(+), 715 deletions(-) create mode 100644 .github/workflows/terratest-istiov1beta1.yaml rename controllers/refresolver/{ => ingress}/ingress.go (67%) create mode 100644 controllers/refresolver/ingress/ingress_test.go create mode 100644 controllers/refresolver/ingress/testdata/ingress_multiple_ips.yaml rename controllers/refresolver/{ => ingress}/testdata/ingress_multiple_servers.yaml (97%) create mode 100644 controllers/refresolver/ingress/testdata/ingress_no_ips.yaml delete mode 100644 controllers/refresolver/ingress_test.go create mode 100644 controllers/refresolver/istiovirtualservice/istiovirtualservice.go create mode 100644 controllers/refresolver/istiovirtualservice/istiovirtualservice_test.go create mode 100644 controllers/refresolver/istiovirtualservice/testdata/istio_service_multiple_ips.yaml create mode 100644 controllers/refresolver/istiovirtualservice/testdata/istio_service_no_ips.yaml create mode 100644 controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_hosts.yaml create mode 100644 controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_routes.yaml create mode 100644 controllers/refresolver/refresolver_test.go rename controllers/refresolver/testdata/{gslb_embedded.yaml => gslb_ingress_embedded.yaml} (78%) create mode 100644 controllers/refresolver/testdata/gslb_ingress_referenced.yaml rename controllers/refresolver/testdata/{gslb_referenced_and_embedded.yaml => gslb_ingress_referenced_and_embedded.yaml} (66%) rename controllers/refresolver/testdata/{gslb_referenced.yaml => gslb_istio.yaml} (62%) create mode 100644 controllers/refresolver/testdata/istio_gateway.yaml create mode 100644 controllers/refresolver/testdata/istio_service.yaml create mode 100644 controllers/refresolver/testdata/istio_virtualservice.yaml rename deploy/crds/{k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml => k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml} (95%) create mode 100644 deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_istio.yaml create mode 100644 deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_notfound_istio.yaml rename deploy/crds/{k8gb.absa.oss_v1beta1_gslb_cr.yaml => k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml} (98%) create mode 100644 deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_istio.yaml create mode 100644 deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_unhealthy_istio.yaml rename deploy/crds/{test-namespace.yaml => test-namespace-ingress.yaml} (100%) create mode 100644 deploy/crds/test-namespace-istio.yaml create mode 100644 deploy/ingress/istio-ingress-values.yaml create mode 100644 terratest/examples/failover-istio-gateway.yaml create mode 100644 terratest/examples/failover-istio-gslb.yaml create mode 100644 terratest/examples/failover-istio-virtualservice.yaml create mode 100644 terratest/examples/failover-playground-istio-gateway.yaml create mode 100644 terratest/examples/failover-playground-istio-gslb.yaml create mode 100644 terratest/examples/failover-playground-istio-virtualservice.yaml create mode 100644 terratest/examples/roundrobin-weight1-istio-gateway.yaml create mode 100644 terratest/examples/roundrobin-weight1-istio-gslb.yaml create mode 100644 terratest/examples/roundrobin-weight1-istio-virtualservice.yaml create mode 100644 terratest/examples/roundrobin2-istio-gateway.yaml create mode 100644 terratest/examples/roundrobin2-istio-gslb.yaml create mode 100644 terratest/examples/roundrobin2-istio-virtualservice.yaml diff --git a/.github/workflows/terratest-istiov1beta1.yaml b/.github/workflows/terratest-istiov1beta1.yaml new file mode 100644 index 0000000000..c6bb38b9b9 --- /dev/null +++ b/.github/workflows/terratest-istiov1beta1.yaml @@ -0,0 +1,81 @@ +name: Terratest for istio's v1beta1 API version + +on: + pull_request: + types: + - labeled + +permissions: + contents: read + +jobs: + terratest-istio: + runs-on: ubuntu-22.04 + if: ${{ github.event.label.name == 'istio' }} + steps: + - name: Checkout + uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 + with: + fetch-depth: 0 + + - name: Set networking.istio.io/v1beta1 API version + run: | + find . -name "*.yaml" -exec sed -i 's/networking\.istio\.io\/v1/networking.istio.io\/v1beta1/g' {} + + cat k8gb/controllers/refresolver/testdata/gslb_istio.yaml + + - name: Setup Golang + uses: actions/setup-go@bfd2fb341f32be7281829126376a12a780ca79fc + with: + go-version: 1.22.3 + + - name: Build artifacts + uses: goreleaser/goreleaser-action@d33b6f6aeabd7fed8bb3fbf32c4d890d29f48545 + with: + version: v1.9.2 + args: release --rm-dist --skip-publish --skip-validate --snapshot --skip-sbom --skip-sign + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create edgeDNS k3s Cluster + uses: AbsaOSS/k3d-action@4e8b3239042be1dc0aed6c5eb80c13b18200fc79 + with: + cluster-name: "edgedns" + args: -c k3d/edge-dns.yaml + + - name: Create 1st k3s Cluster + uses: AbsaOSS/k3d-action@4e8b3239042be1dc0aed6c5eb80c13b18200fc79 + with: + cluster-name: "test-gslb1" + args: -c k3d/test-gslb1.yaml + + - name: Create 2nd k3s Cluster + uses: AbsaOSS/k3d-action@4e8b3239042be1dc0aed6c5eb80c13b18200fc79 + with: + cluster-name: "test-gslb2" + args: -c k3d/test-gslb2.yaml + + - name: K8GB deployment + run: | + make deploy-test-version list-running-pods + echo "Cluster 1 (eu):" + kubectl get no -owide --context=k3d-test-gslb1 + echo "Cluster 2 (us):" + kubectl get no -owide --context=k3d-test-gslb2 + + - name: Run Terratest + run: | + mkdir -p ${{ github.workspace }}/tmp/terratest + set -o pipefail + echo "::group::Terratest logs" + make terratest | tee ${{ github.workspace }}/tmp/terratest/all.log + echo "::endgroup::" + + - name: Print debug info + if: always() + uses: ./.github/actions/print-debug + + - uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 + if: always() + with: + name: terratest-logs + path: ${{ github.workspace }}/tmp/terratest diff --git a/.github/workflows/terratest.yaml b/.github/workflows/terratest.yaml index 59be3c50cf..74b4ed3ab8 100644 --- a/.github/workflows/terratest.yaml +++ b/.github/workflows/terratest.yaml @@ -44,11 +44,13 @@ jobs: needs: skip-check if: ${{ needs.skip-check.outputs.should_skip != 'true' }} && !contains( github.event.pull_request.labels.*.name, 'renovate') steps: - - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 + - name: Checkout + uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 with: fetch-depth: 0 - - uses: actions/setup-go@bfd2fb341f32be7281829126376a12a780ca79fc + - name: Setup golang + uses: actions/setup-go@bfd2fb341f32be7281829126376a12a780ca79fc with: go-version: 1.22.3 diff --git a/.golangci.yaml b/.golangci.yaml index e9df0f870f..4a9f7ef5bf 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -30,17 +30,17 @@ linters: - dupl - gochecknoinits - # don't enable: - # - golint # deprecated - # - whitespace - # - funlen - # - exhaustive - # - gomnd - # - gofmt - # - deadcode # deprecated since v1.49.0 - # - structcheck # deprecated since v1.49.0 - # - varcheck # deprecated since v1.49.0 - # - rowserrcheck # rowserrcheck is disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649 + # don't enable: + # - golint # deprecated + # - whitespace + # - funlen + # - exhaustive + # - gomnd + # - gofmt + # - deadcode # deprecated since v1.49.0 + # - structcheck # deprecated since v1.49.0 + # - varcheck # deprecated since v1.49.0 + # - rowserrcheck # rowserrcheck is disabled because of generics. You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649 run: deadline: 3m @@ -55,6 +55,7 @@ linters-settings: main: allow: - $gostd + - istio.io/client-go - k8s.io/apimachinery - k8s.io/client-go - k8s.io/api diff --git a/Makefile b/Makefile index 227620798b..0dae1e9554 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,7 @@ STABLE_VERSION := "stable" BUNDLE_IMG ?= controller-bundle:$(VERSION) NGINX_INGRESS_VALUES_PATH ?= deploy/ingress/nginx-ingress-values.yaml +ISTIO_INGRESS_VALUES_PATH ?= deploy/ingress/istio-ingress-values.yaml # options for 'bundle-build' ifneq ($(origin CHANNELS), undefined) @@ -188,6 +189,20 @@ deploy-local-cluster: helm -n k8gb upgrade -i nginx-ingress nginx-stable/ingress-nginx \ --version 4.0.15 -f $(NGINX_INGRESS_VALUES_PATH) + @echo -e "\n$(YELLOW)Install Istio CRDs $(NC)" + kubectl create namespace istio-system + helm repo add --force-update istio https://istio-release.storage.googleapis.com/charts + helm repo update + helm upgrade -i istio-base istio/base -n istio-system + + @echo -e "\n$(YELLOW)Install Istiod $(NC)" + helm upgrade -i istiod istio/istiod -n istio-system --wait + + @echo -e "\n$(YELLOW)Install Istio Ingress Gateway $(NC)" + kubectl create namespace istio-ingress + helm upgrade -i istio-ingressgateway istio/gateway -n istio-ingress \ + -f $(ISTIO_INGRESS_VALUES_PATH) + @if [ "$(DEPLOY_APPS)" = true ]; then $(MAKE) deploy-test-apps ; fi @echo -e "\n$(YELLOW)Wait until Ingress controller is ready $(NC)" @@ -198,9 +213,15 @@ deploy-local-cluster: .PHONY: deploy-test-apps deploy-test-apps: ## Deploy Podinfo (example app) and Apply Gslb Custom Resources @echo -e "\n$(YELLOW)Deploy GSLB cr $(NC)" - kubectl apply -f deploy/crds/test-namespace.yaml - $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml) - $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml) + kubectl apply -f deploy/crds/test-namespace-ingress.yaml + $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml) + $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml) + + kubectl apply -f deploy/crds/test-namespace-istio.yaml + $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_istio.yaml) + $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_istio.yaml) + $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_notfound_istio.yaml) + $(call apply-cr,deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_unhealthy_istio.yaml) @echo -e "\n$(YELLOW)Deploy podinfo $(NC)" kubectl apply -f deploy/test-apps @@ -210,6 +231,11 @@ deploy-test-apps: ## Deploy Podinfo (example app) and Apply Gslb Custom Resource --set image.repository="$(PODINFO_IMAGE_REPO)" \ podinfo/podinfo \ --version 5.1.1 + helm upgrade --install frontend --namespace test-gslb-istio -f deploy/test-apps/podinfo/podinfo-values.yaml \ + --set ui.message="`$(call get-cluster-geo-tag)`" \ + --set image.repository="$(PODINFO_IMAGE_REPO)" \ + podinfo/podinfo \ + --version 5.1.1 .PHONY: deploy-kuar-app deploy-kuar-app: @@ -342,11 +368,11 @@ docker-push: test .PHONY: init-failover init-failover: - $(call init-test-strategy, "deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml") + $(call init-test-strategy, "deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml") .PHONY: init-round-robin init-round-robin: - $(call init-test-strategy, "deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml") + $(call init-test-strategy, "deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml") # creates infoblox secret in current cluster .PHONY: infoblox-secret @@ -554,9 +580,9 @@ endef define debug $(call manifest) - kubectl apply -f deploy/crds/test-namespace.yaml + kubectl apply -f deploy/crds/test-namespace-ingress.yaml kubectl apply -f ./chart/k8gb/templates/k8gb.absa.oss_gslbs.yaml - kubectl apply -f ./deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml + kubectl apply -f ./deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml dlv $1 endef diff --git a/README.md b/README.md index a32c064eaf..0e04b70b7b 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,10 @@ metadata: namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: # ingresses.networking.k8s.io resource selector - app: test-gslb-failover + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: # ingresses.networking.k8s.io resource selector + app: test-gslb-failover strategy: type: failover # Global load balancing strategy primaryGeoTag: eu-west-1 # Primary cluster geo tag diff --git a/api/v1beta1/gslb_types.go b/api/v1beta1/gslb_types.go index 2a913fc26b..7d6b7f8d05 100644 --- a/api/v1beta1/gslb_types.go +++ b/api/v1beta1/gslb_types.go @@ -43,8 +43,12 @@ type Strategy struct { // ResourceRef selects a resource defining the GSLB's load balancer and server // +k8s:openapi-gen=true type ResourceRef struct { - // Ingress selects a kubernetes.networking.k8s.io/v1.Ingress resource - Ingress metav1.LabelSelector `json:"ingress,omitempty"` + // APIVersion of the referenced resource + APIVersion string `json:"apiVersion"` + // Kind of the referenced resource + Kind string `json:"kind"` + // LabelSelector of the referenced resource + metav1.LabelSelector `json:",inline"` } // GslbSpec defines the desired state of Gslb diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 2bfaabbcee..cde1d4f087 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -221,7 +221,7 @@ func (in *NamespacedName) DeepCopy() *NamespacedName { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceRef) DeepCopyInto(out *ResourceRef) { *out = *in - in.Ingress.DeepCopyInto(&out.Ingress) + in.LabelSelector.DeepCopyInto(&out.LabelSelector) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRef. diff --git a/chart/k8gb/crd/k8gb.absa.oss_gslbs.yaml b/chart/k8gb/crd/k8gb.absa.oss_gslbs.yaml index 693d89a85a..7684aa0428 100644 --- a/chart/k8gb/crd/k8gb.absa.oss_gslbs.yaml +++ b/chart/k8gb/crd/k8gb.absa.oss_gslbs.yaml @@ -316,52 +316,58 @@ spec: resourceRef: description: ResourceRef spec properties: - ingress: - description: Ingress selects a kubernetes.networking.k8s.io/v1.Ingress - resource - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: + apiVersion: + description: APIVersion of the referenced resource + type: string + kind: + description: Kind of the referenced resource + type: string + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: |- - operator represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists and DoesNotExist. - type: string - values: - description: |- - values is an array of string values. If the operator is In or NotIn, - the values array must be non-empty. If the operator is Exists or DoesNotExist, - the values array must be empty. This array is replaced during a strategic - merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string - description: |- - matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, whose key field is "key", the - operator is "In", and the values array contains only "value". The requirements are ANDed. - type: object + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object - x-kubernetes-map-type: atomic + required: + - apiVersion + - kind type: object + x-kubernetes-map-type: atomic strategy: description: Gslb Strategy spec properties: diff --git a/chart/k8gb/templates/role.yaml b/chart/k8gb/templates/role.yaml index 15502a9013..2455c5b263 100644 --- a/chart/k8gb/templates/role.yaml +++ b/chart/k8gb/templates/role.yaml @@ -56,4 +56,15 @@ rules: verbs: - update {{- end }} +{{- if .Values.istio.enabled }} +- apiGroups: + - networking.istio.io + resources: + - virtualservices + - gateways + verbs: + - 'get' + - 'list' + - 'watch' +{{- end }} {{- end }} diff --git a/chart/k8gb/values.schema.json b/chart/k8gb/values.schema.json index 4cd06cd004..c285ffa141 100644 --- a/chart/k8gb/values.schema.json +++ b/chart/k8gb/values.schema.json @@ -32,7 +32,7 @@ }, "azuredns": { "$ref": "#/definitions/AzureDNS" - }, + }, "cloudflare": { "$ref": "#/definitions/Cloudflare" }, @@ -41,6 +41,9 @@ }, "tracing": { "$ref": "#/definitions/Tracing" + }, + "istio": { + "$ref": "#/definitions/Istio" } } }, @@ -634,42 +637,42 @@ }, "createAuthSecret": { "type": "object", - "additionalProperties": false, - "properties": { - "enabled": { - "type": "boolean" - }, - "tenantId": { - "type": "string", - "minLength": 1 - }, - "subscriptionId": { - "type": "string", - "minLength": 1 - }, - "resourceGroup": { - "type": "string", - "minLength": 1 - }, - "aadClientId": { - "type": "string" - }, - "aadClientSecret": { - "type": "string" - }, - "useManagedIdentityExtension": { - "type": "boolean", - "default": false - }, - "userAssignedIdentityID": { - "type": "string" - }, - "useWorkloadIdentityExtension": { - "type": "boolean", - "default": false - } - } - } + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "tenantId": { + "type": "string", + "minLength": 1 + }, + "subscriptionId": { + "type": "string", + "minLength": 1 + }, + "resourceGroup": { + "type": "string", + "minLength": 1 + }, + "aadClientId": { + "type": "string" + }, + "aadClientSecret": { + "type": "string" + }, + "useManagedIdentityExtension": { + "type": "boolean", + "default": false + }, + "userAssignedIdentityID": { + "type": "string" + }, + "useWorkloadIdentityExtension": { + "type": "boolean", + "default": false + } + } + } }, "required": [ "enabled" @@ -735,6 +738,19 @@ "enabled" ], "title": "Tracing" + }, + "Istio": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "title": "Istio" } } } diff --git a/chart/k8gb/values.yaml b/chart/k8gb/values.yaml index 7a36b8058d..fee941dbac 100644 --- a/chart/k8gb/values.yaml +++ b/chart/k8gb/values.yaml @@ -21,8 +21,8 @@ k8gb: edgeDNSZone: "example.com" # main zone which would contain gslb zone to delegate # -- host/ip[:port] format is supported here where port defaults to 53 edgeDNSServers: - # -- use this DNS server as a main resolver to enable cross k8gb DNS based communication - - "1.1.1.1" + # -- use this DNS server as a main resolver to enable cross k8gb DNS based communication + - "1.1.1.1" # -- used for places where we need to distinguish between different Gslb instances clusterGeoTag: "eu" # -- comma-separated list of external gslb geo tags to pair with @@ -175,13 +175,12 @@ azuredns: # -- Azure client secret that is associated with the Service Principal. aadClientSecret: myAadClientSecret # -- Use either AKS Kubelet Identity or AAD Pod Identities - useManagedIdentityExtension : false + useManagedIdentityExtension: false # -- Client id from the Managed identitty when using the AAD Pod Identities userAssignedIdentityID: myUserAssignedIdentityID # -- Use AKS workload identity extension useWorkloadIdentityExtension: false - cloudflare: # -- Enable Cloudflare provider enabled: false @@ -228,3 +227,7 @@ tracing: repository: jaegertracing/all-in-one tag: 1.60.0 pullPolicy: Always + +istio: + # -- install istio RBAC + enabled: true diff --git a/controllers/gslb_controller_reconciliation.go b/controllers/gslb_controller_reconciliation.go index 45c94f8a68..63434d54a1 100644 --- a/controllers/gslb_controller_reconciliation.go +++ b/controllers/gslb_controller_reconciliation.go @@ -35,7 +35,6 @@ import ( "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -95,6 +94,7 @@ func (r *GslbReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. } log.Debug(). Str("gslb", gslb.Name). + Str("namespace", gslb.Namespace). Interface("strategy", gslb.Spec.Strategy). Msg("Resolved strategy") // == Finalizer business == @@ -143,7 +143,7 @@ func (r *GslbReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. } // == Ingress ========== - if reflect.DeepEqual(gslb.Spec.ResourceRef.Ingress, metav1.LabelSelector{}) { + if reflect.DeepEqual(gslb.Spec.ResourceRef, k8gbv1beta1.ResourceRef{}) { ingress, err := r.gslbIngress(gslb) if err != nil { m.IncrementError(gslb) @@ -170,7 +170,7 @@ func (r *GslbReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. } gslb.Status.Servers = servers - loadBalancerExposedIPs, err := refResolver.GetGslbExposedIPs(r.Client, r.Config.EdgeDNSServers) + loadBalancerExposedIPs, err := refResolver.GetGslbExposedIPs(r.Config.EdgeDNSServers) if err != nil { m.IncrementError(gslb) return result.RequeueError(fmt.Errorf("getting load balancer exposed IPs (%s)", err)) diff --git a/controllers/gslb_controller_reconciliation_test.go b/controllers/gslb_controller_reconciliation_test.go index dec83d9daf..7ba90e4d3c 100644 --- a/controllers/gslb_controller_reconciliation_test.go +++ b/controllers/gslb_controller_reconciliation_test.go @@ -71,7 +71,7 @@ type testSettings struct { assistant assistant.Assistant } -var crSampleYaml = "../deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml" +var crSampleYaml = "../deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml" var predefinedConfig = depresolver.Config{ ReconcileRequeueSeconds: 30, @@ -1188,7 +1188,7 @@ func TestGslbRemoveDefaultFinalizer(t *testing.T) { // assert err = settings.client.Get(context.TODO(), settings.request.NamespacedName, gslb) - require.EqualError(t, err, "gslbs.k8gb.absa.oss \"test-gslb\" not found") + require.EqualError(t, err, "gslbs.k8gb.absa.oss \"roundrobin-ingress\" not found") assert.Len(t, gslb.Finalizers, 0) }) } @@ -1210,7 +1210,7 @@ func TestGslbRemoveWithFinalizer(t *testing.T) { // assert err = settings.client.Get(context.TODO(), settings.request.NamespacedName, gslb) - require.EqualError(t, err, "gslbs.k8gb.absa.oss \"test-gslb\" not found") + require.EqualError(t, err, "gslbs.k8gb.absa.oss \"roundrobin-ingress\" not found") assert.Len(t, gslb.Finalizers, 0) }) } @@ -1232,7 +1232,7 @@ func TestGslbRemoveBothFinalizers(t *testing.T) { // assert err = settings.reconciler.Get(context.TODO(), settings.request.NamespacedName, gslb) - require.EqualError(t, err, "gslbs.k8gb.absa.oss \"test-gslb\" not found") + require.EqualError(t, err, "gslbs.k8gb.absa.oss \"roundrobin-ingress\" not found") assert.Len(t, gslb.Finalizers, 0) }) } diff --git a/controllers/mocks/refresolver_mock.go b/controllers/mocks/refresolver_mock.go index 99a3db8a33..2b5ce011f8 100644 --- a/controllers/mocks/refresolver_mock.go +++ b/controllers/mocks/refresolver_mock.go @@ -33,7 +33,6 @@ import ( v1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" utils "github.com/k8gb-io/k8gb/controllers/utils" gomock "go.uber.org/mock/gomock" - client "sigs.k8s.io/controller-runtime/pkg/client" ) // MockGslbReferenceResolver is a mock of GslbReferenceResolver interface. @@ -60,18 +59,18 @@ func (m *MockGslbReferenceResolver) EXPECT() *MockGslbReferenceResolverMockRecor } // GetGslbExposedIPs mocks base method. -func (m *MockGslbReferenceResolver) GetGslbExposedIPs(arg0 client.Client, arg1 utils.DNSList) ([]string, error) { +func (m *MockGslbReferenceResolver) GetGslbExposedIPs(arg0 utils.DNSList) ([]string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetGslbExposedIPs", arg0, arg1) + ret := m.ctrl.Call(m, "GetGslbExposedIPs", arg0) ret0, _ := ret[0].([]string) ret1, _ := ret[1].(error) return ret0, ret1 } // GetGslbExposedIPs indicates an expected call of GetGslbExposedIPs. -func (mr *MockGslbReferenceResolverMockRecorder) GetGslbExposedIPs(arg0, arg1 any) *gomock.Call { +func (mr *MockGslbReferenceResolverMockRecorder) GetGslbExposedIPs(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGslbExposedIPs", reflect.TypeOf((*MockGslbReferenceResolver)(nil).GetGslbExposedIPs), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGslbExposedIPs", reflect.TypeOf((*MockGslbReferenceResolver)(nil).GetGslbExposedIPs), arg0) } // GetServers mocks base method. diff --git a/controllers/providers/dns/external_test.go b/controllers/providers/dns/external_test.go index 3ca197cdd8..fa4ad3ecba 100644 --- a/controllers/providers/dns/external_test.go +++ b/controllers/providers/dns/external_test.go @@ -72,7 +72,7 @@ var a = struct { K8gbNamespace: "k8gb", }, Gslb: func() *k8gbv1beta1.Gslb { - var crSampleYaml = "../../../deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml" + var crSampleYaml = "../../../deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml" gslbYaml, _ := os.ReadFile(crSampleYaml) gslb, _ := utils2.YamlToGslb(gslbYaml) gslb.Status.LoadBalancer.ExposedIPs = targetIPs diff --git a/controllers/refresolver/ingress.go b/controllers/refresolver/ingress/ingress.go similarity index 67% rename from controllers/refresolver/ingress.go rename to controllers/refresolver/ingress/ingress.go index 1ca30e6977..a6aed4a7ad 100644 --- a/controllers/refresolver/ingress.go +++ b/controllers/refresolver/ingress/ingress.go @@ -1,4 +1,4 @@ -package refresolver +package ingress /* Copyright 2022 The k8gb Contributors. @@ -18,30 +18,13 @@ limitations under the License. Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic */ -/* -Copyright 2024 The k8gb Contributors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic -*/ - import ( "context" "fmt" "reflect" k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" + "github.com/k8gb-io/k8gb/controllers/logging" "github.com/k8gb-io/k8gb/controllers/utils" netv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -50,27 +33,21 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -type IngressReferenceResolver struct { +var log = logging.Logger() + +type ReferenceResolver struct { ingress *netv1.Ingress } -// NewIngressReferenceResolver creates a reference resolver capable of understanding ingresses.networking.k8s.io resources -func NewIngressReferenceResolver(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (*IngressReferenceResolver, error) { +// NewReferenceResolver creates a reference resolver capable of understanding referenced ingresses.networking.k8s.io resources +func NewReferenceResolver(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (*ReferenceResolver, error) { ingressList, err := getGslbIngressRef(gslb, k8sClient) if err != nil { return nil, err } - ingressEmbedded, err := getGslbIngressEmbedded(gslb, k8sClient) - if err != nil { - return nil, err - } - if ingressEmbedded != nil { - ingressList = append(ingressList, *ingressEmbedded) - } - for _, ingress := range ingressList { log.Info(). - Str("IngressName", ingress.Name). + Str("Name", ingress.Name). Msg("Found Ingress") } @@ -78,7 +55,7 @@ func NewIngressReferenceResolver(gslb *k8gbv1beta1.Gslb, k8sClient client.Client return nil, fmt.Errorf("exactly one Ingress resource expected but %d were found", len(ingressList)) } - return &IngressReferenceResolver{ + return &ReferenceResolver{ ingress: &ingressList[0], }, nil } @@ -86,14 +63,8 @@ func NewIngressReferenceResolver(gslb *k8gbv1beta1.Gslb, k8sClient client.Client // getGslbIngressRef resolves a Kubernetes Ingress resource referenced by the Gslb spec func getGslbIngressRef(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) ([]netv1.Ingress, error) { ingressList := &netv1.IngressList{} - if reflect.DeepEqual(gslb.Spec.ResourceRef.Ingress, metav1.LabelSelector{}) { - log.Info(). - Str("gslb", gslb.Name). - Msg("No configuration for referenced Ingress resource") - return ingressList.Items, nil - } - selector, err := metav1.LabelSelectorAsSelector(&gslb.Spec.ResourceRef.Ingress) + selector, err := metav1.LabelSelectorAsSelector(&gslb.Spec.ResourceRef.LabelSelector) if err != nil { return nil, err } @@ -115,6 +86,21 @@ func getGslbIngressRef(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) ([]netv1 return ingressList.Items, err } +// NewEmbeddedResolver creates a reference resolver capable of understanding embedded ingresses.networking.k8s.io resources +func NewEmbeddedResolver(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (*ReferenceResolver, error) { + ingressEmbedded, err := getGslbIngressEmbedded(gslb, k8sClient) + if err != nil { + return nil, err + } + if ingressEmbedded == nil { + return nil, fmt.Errorf("exactly one Ingress resource expected but none was found") + } + + return &ReferenceResolver{ + ingress: ingressEmbedded, + }, nil +} + // getGslbIngressEmbedded resolves a Kubernetes Ingress resource embedded in the Gslb spec func getGslbIngressEmbedded(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (*netv1.Ingress, error) { if reflect.DeepEqual(gslb.Spec.Ingress, k8gbv1beta1.IngressSpec{}) { @@ -142,11 +128,11 @@ func getGslbIngressEmbedded(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (*n return ingress, nil } -// GetServers retrieves the backend servers referenced by the GSLB -func (irr *IngressReferenceResolver) GetServers() ([]*k8gbv1beta1.Server, error) { +// GetServers retrieves the GSLB server configuration from the gateway resource +func (rr *ReferenceResolver) GetServers() ([]*k8gbv1beta1.Server, error) { servers := []*k8gbv1beta1.Server{} - for _, rule := range irr.ingress.Spec.Rules { + for _, rule := range rr.ingress.Spec.Rules { server := &k8gbv1beta1.Server{ Host: rule.Host, Services: []*k8gbv1beta1.NamespacedName{}, @@ -154,7 +140,7 @@ func (irr *IngressReferenceResolver) GetServers() ([]*k8gbv1beta1.Server, error) for _, path := range rule.HTTP.Paths { if path.Backend.Service == nil || path.Backend.Service.Name == "" { log.Warn(). - Str("ingress", irr.ingress.Name). + Str("ingress", rr.ingress.Name). Interface("service", path.Backend.Service). Msg("Malformed service definition") continue @@ -162,7 +148,7 @@ func (irr *IngressReferenceResolver) GetServers() ([]*k8gbv1beta1.Server, error) server.Services = append(server.Services, &k8gbv1beta1.NamespacedName{ Name: path.Backend.Service.Name, - Namespace: irr.ingress.Namespace, + Namespace: rr.ingress.Namespace, }) } servers = append(servers, server) @@ -172,10 +158,10 @@ func (irr *IngressReferenceResolver) GetServers() ([]*k8gbv1beta1.Server, error) } // GetGslbExposedIPs retrieves the load balancer IP address of the GSLB -func (irr *IngressReferenceResolver) GetGslbExposedIPs(_ client.Client, edgeDNSServers utils.DNSList) ([]string, error) { +func (rr *ReferenceResolver) GetGslbExposedIPs(edgeDNSServers utils.DNSList) ([]string, error) { gslbIngressIPs := []string{} - for _, ip := range irr.ingress.Status.LoadBalancer.Ingress { + for _, ip := range rr.ingress.Status.LoadBalancer.Ingress { if len(ip.IP) > 0 { gslbIngressIPs = append(gslbIngressIPs, ip.IP) } @@ -191,7 +177,3 @@ func (irr *IngressReferenceResolver) GetGslbExposedIPs(_ client.Client, edgeDNSS return gslbIngressIPs, nil } - -func (irr *IngressReferenceResolver) getIngress() *netv1.Ingress { - return irr.ingress -} diff --git a/controllers/refresolver/ingress/ingress_test.go b/controllers/refresolver/ingress/ingress_test.go new file mode 100644 index 0000000000..e288101e81 --- /dev/null +++ b/controllers/refresolver/ingress/ingress_test.go @@ -0,0 +1,135 @@ +package ingress + +/* +Copyright 2022 The k8gb Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic +*/ + +import ( + "testing" + + k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" + "github.com/k8gb-io/k8gb/controllers/utils" + "github.com/stretchr/testify/assert" +) + +func TestGetServers(t *testing.T) { + var tests = []struct { + name string + ingressFile string + expectedServers []*k8gbv1beta1.Server + }{ + { + name: "single server", + ingressFile: "../testdata/ingress_referenced.yaml", + expectedServers: []*k8gbv1beta1.Server{ + { + Host: "ingress-referenced.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "ingress-referenced", + Namespace: "test-gslb", + }, + }, + }, + }, + }, + { + name: "multiple servers", + ingressFile: "./testdata/ingress_multiple_servers.yaml", + expectedServers: []*k8gbv1beta1.Server{ + { + Host: "h1.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "s1", + Namespace: "test-gslb", + }, + }, + }, + { + Host: "h2.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "ss1", + Namespace: "test-gslb", + }, + { + Name: "ss2", + Namespace: "test-gslb", + }, + }, + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // arrange + ingress := utils.FileToIngress(test.ingressFile) + resolver := ReferenceResolver{ + ingress: ingress, + } + + // act + servers, err := resolver.GetServers() + assert.NoError(t, err) + + // assert + assert.Equal(t, test.expectedServers, servers) + }) + } +} + +func TestGetGslbExposedIPs(t *testing.T) { + var tests = []struct { + name string + ingressYaml string + expectedIPs []string + }{ + { + name: "no exposed IPs", + ingressYaml: "./testdata/ingress_no_ips.yaml", + expectedIPs: []string{}, + }, + { + name: "single exposed IP", + ingressYaml: "../testdata/ingress_referenced.yaml", + expectedIPs: []string{"10.0.0.1"}, + }, + { + name: "multiple exposed IPs", + ingressYaml: "./testdata/ingress_multiple_ips.yaml", + expectedIPs: []string{"10.0.0.1", "10.0.0.2"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // arrange + ingress := utils.FileToIngress(test.ingressYaml) + resolver := ReferenceResolver{ + ingress: ingress, + } + + // act + IPs, err := resolver.GetGslbExposedIPs([]utils.DNSServer{}) + assert.NoError(t, err) + + // assert + assert.Equal(t, test.expectedIPs, IPs) + }) + } +} diff --git a/controllers/refresolver/ingress/testdata/ingress_multiple_ips.yaml b/controllers/refresolver/ingress/testdata/ingress_multiple_ips.yaml new file mode 100644 index 0000000000..3f3dc98d84 --- /dev/null +++ b/controllers/refresolver/ingress/testdata/ingress_multiple_ips.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + labels: + app: ingress-referenced + name: ingress-referenced + namespace: test-gslb + resourceVersion: "999" +spec: + ingressClassName: nginx + rules: + - host: ingress-referenced.cloud.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: referenced + port: + name: http +status: + loadBalancer: + ingress: + - ip: 10.0.0.1 + - ip: 10.0.0.2 diff --git a/controllers/refresolver/testdata/ingress_multiple_servers.yaml b/controllers/refresolver/ingress/testdata/ingress_multiple_servers.yaml similarity index 97% rename from controllers/refresolver/testdata/ingress_multiple_servers.yaml rename to controllers/refresolver/ingress/testdata/ingress_multiple_servers.yaml index 5066d8e995..49ca038a24 100644 --- a/controllers/refresolver/testdata/ingress_multiple_servers.yaml +++ b/controllers/refresolver/ingress/testdata/ingress_multiple_servers.yaml @@ -43,4 +43,3 @@ status: loadBalancer: ingress: - ip: 10.0.0.1 - - ip: 10.0.0.2 diff --git a/controllers/refresolver/ingress/testdata/ingress_no_ips.yaml b/controllers/refresolver/ingress/testdata/ingress_no_ips.yaml new file mode 100644 index 0000000000..7969b2d7c8 --- /dev/null +++ b/controllers/refresolver/ingress/testdata/ingress_no_ips.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + labels: + app: ingress-referenced + name: ingress-referenced + namespace: test-gslb + resourceVersion: "999" +spec: + ingressClassName: nginx + rules: + - host: ingress-referenced.cloud.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: referenced + port: + name: http +status: + loadBalancer: + ingress: diff --git a/controllers/refresolver/ingress_test.go b/controllers/refresolver/ingress_test.go deleted file mode 100644 index 62a7e94c30..0000000000 --- a/controllers/refresolver/ingress_test.go +++ /dev/null @@ -1,222 +0,0 @@ -package refresolver - -/* -Copyright 2022 The k8gb Contributors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic -*/ - -/* -Copyright 2024 The k8gb Contributors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic -*/ - -import ( - "fmt" - "os" - "testing" - - k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" - "github.com/k8gb-io/k8gb/controllers/utils" - "github.com/stretchr/testify/assert" - netv1 "k8s.io/api/networking/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func TestGetIngress(t *testing.T) { - var tests = []struct { - name string - gslbYaml string - expectedIngressYaml string - expectedError error - }{ - { - name: "embedded ingress", - gslbYaml: "./testdata/gslb_embedded.yaml", - expectedIngressYaml: "./testdata/ingress_embedded.yaml", - expectedError: nil, - }, - { - name: "referenced ingress", - gslbYaml: "./testdata/gslb_referenced.yaml", - expectedIngressYaml: "./testdata/ingress_referenced.yaml", - expectedError: nil, - }, - { - name: "referenced and embedded ingress", - gslbYaml: "./testdata/gslb_referenced_and_embedded.yaml", - expectedIngressYaml: "", - expectedError: fmt.Errorf("exactly one Ingress resource expected but 2 were found"), - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - // arrange - cl, gslb := getTestContext(test.gslbYaml) - - // act - resolver, err := New(gslb, cl) - assert.Equal(t, test.expectedError, err) - - ingressResolver, ok := resolver.(*IngressReferenceResolver) - assert.True(t, ok, "referenced resolver is of type Ingress") - - // assert - if test.expectedIngressYaml != "" { - expectedIngress := fileToIngress(test.expectedIngressYaml) - assert.Equal(t, expectedIngress, ingressResolver.getIngress()) - } - }) - } -} - -func TestGetServers(t *testing.T) { - var tests = []struct { - name string - ingressYaml string - expectedServers []*k8gbv1beta1.Server - }{ - { - name: "multiple servers", - ingressYaml: "./testdata/ingress_multiple_servers.yaml", - expectedServers: []*k8gbv1beta1.Server{ - { - Host: "h1.cloud.example.com", - Services: []*k8gbv1beta1.NamespacedName{ - { - Name: "s1", - Namespace: "test-gslb", - }, - }, - }, - { - Host: "h2.cloud.example.com", - Services: []*k8gbv1beta1.NamespacedName{ - { - Name: "ss1", - Namespace: "test-gslb", - }, - { - Name: "ss2", - Namespace: "test-gslb", - }, - }, - }, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - // arrange - ingress := fileToIngress(test.ingressYaml) - resolver := IngressReferenceResolver{ - ingress: ingress, - } - - // act - servers, err := resolver.GetServers() - assert.NoError(t, err) - - // assert - assert.Equal(t, test.expectedServers, servers) - }) - } -} - -func TestGetGslbExposedIPs(t *testing.T) { - var tests = []struct { - name string - ingressYaml string - expectedIPs []string - }{ - { - name: "multiple exposed IPs", - ingressYaml: "./testdata/ingress_multiple_servers.yaml", - expectedIPs: []string{"10.0.0.1", "10.0.0.2"}, - }, - { - name: "no exposed IPs", - ingressYaml: "./testdata/ingress_referenced.yaml", - expectedIPs: []string{}, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - // arrange - ingress := fileToIngress(test.ingressYaml) - resolver := IngressReferenceResolver{ - ingress: ingress, - } - - // act - IPs, err := resolver.GetGslbExposedIPs(nil, []utils.DNSServer{}) - assert.NoError(t, err) - - // assert - assert.Equal(t, test.expectedIPs, IPs) - }) - } -} - -func getTestContext(gslbData string) (client.Client, *k8gbv1beta1.Gslb) { - gslbYaml, err := os.ReadFile(gslbData) - if err != nil { - panic(fmt.Errorf("can't open example CR file: %s", gslbData)) - } - gslb, err := utils.YamlToGslb(gslbYaml) - if err != nil { - panic(err) - } - - objs := []runtime.Object{ - gslb, - fileToIngress("./testdata/ingress_embedded.yaml"), - fileToIngress("./testdata/ingress_referenced.yaml"), - } - // Register operator types with the runtime scheme. - s := scheme.Scheme - s.AddKnownTypes(k8gbv1beta1.GroupVersion, gslb) - cl := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build() - - return cl, gslb -} - -func fileToIngress(ingressData string) *netv1.Ingress { - ingressYaml, err := os.ReadFile(ingressData) - if err != nil { - panic(fmt.Errorf("can't open example CR file: %s", ingressData)) - } - ingress, err := utils.YamlToIngress(ingressYaml) - if err != nil { - panic(err) - } - return ingress -} diff --git a/controllers/refresolver/istiovirtualservice/istiovirtualservice.go b/controllers/refresolver/istiovirtualservice/istiovirtualservice.go new file mode 100644 index 0000000000..87d824e517 --- /dev/null +++ b/controllers/refresolver/istiovirtualservice/istiovirtualservice.go @@ -0,0 +1,212 @@ +package istiovirtualservice + +/* +Copyright 2022 The k8gb Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic +*/ + +import ( + "context" + "fmt" + "strings" + + k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" + "github.com/k8gb-io/k8gb/controllers/logging" + "github.com/k8gb-io/k8gb/controllers/utils" + istio "istio.io/client-go/pkg/apis/networking/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var log = logging.Logger() + +type ReferenceResolver struct { + virtualService *istio.VirtualService + lbService *corev1.Service +} + +// NewReferenceResolver creates a new reference resolver capable of understanding `networking.istio.io/v1` resources +func NewReferenceResolver(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (*ReferenceResolver, error) { + virtualServiceList, err := getGslbVirtualServiceRef(gslb, k8sClient) + if err != nil { + return nil, err + } + + if len(virtualServiceList) != 1 { + return nil, fmt.Errorf("exactly one VirtualService resource expected but %d were found", len(virtualServiceList)) + } + virtualService := virtualServiceList[0] + + gateway, err := getGateway(virtualService, k8sClient) + if err != nil { + return nil, err + } + + lbService, err := getLbService(gateway, k8sClient) + if err != nil { + return nil, err + } + + return &ReferenceResolver{ + virtualService: virtualService, + lbService: lbService, + }, nil +} + +// getGslbVirtualServiceRef resolves an istio virtual service resource referenced by the Gslb spec +func getGslbVirtualServiceRef(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) ([]*istio.VirtualService, error) { + virtualServiceList := &istio.VirtualServiceList{} + + selector, err := metav1.LabelSelectorAsSelector(&gslb.Spec.ResourceRef.LabelSelector) + if err != nil { + return nil, err + } + opts := &client.ListOptions{ + LabelSelector: selector, + } + + err = k8sClient.List(context.TODO(), virtualServiceList, opts) + if err != nil { + if errors.IsNotFound(err) { + log.Info(). + Str("gslb", gslb.Name). + Msg("Can't find referenced VirtualService resource") + } + return nil, err + } + + return virtualServiceList.Items, err +} + +// getGateway retrieves the istio gateway referenced by the istio virtual service +func getGateway(virtualService *istio.VirtualService, k8sClient client.Client) (*istio.Gateway, error) { + if len(virtualService.Spec.Gateways) != 1 { + return nil, fmt.Errorf("expected exactly one Gateway to be referenced by the VirtualService but %d were found", len(virtualService.Spec.Gateways)) + } + gatewayRef := strings.Split(virtualService.Spec.Gateways[0], "/") + gatewayNamespace := gatewayRef[0] + gatewayName := gatewayRef[1] + + gateway := &istio.Gateway{} + err := k8sClient.Get(context.TODO(), types.NamespacedName{ + Namespace: gatewayNamespace, + Name: gatewayName, + }, gateway) + if err != nil { + if errors.IsNotFound(err) { + log.Info(). + Str("gatewayNamespace", gatewayNamespace). + Str("gatewayName", gatewayName). + Msg("Can't find Gateway resource referenced by VirtualService") + } + return nil, err + } + + return gateway, nil +} + +// getLbService retrieves the kubernetes service referenced by an istio gateway +func getLbService(gateway *istio.Gateway, k8sClient client.Client) (*corev1.Service, error) { + gatewayServiceList := &corev1.ServiceList{} + opts := &client.ListOptions{ + LabelSelector: labels.SelectorFromSet(gateway.Spec.Selector), + } + + err := k8sClient.List(context.TODO(), gatewayServiceList, opts) + if err != nil { + if errors.IsNotFound(err) { + log.Info(). + Str("gateway", gateway.Name). + Msg("Can't find any service with the gateway's selector") + } + return nil, err + } + + if len(gatewayServiceList.Items) != 1 { + return nil, fmt.Errorf("exactly one Service resource expected but %d were found", len(gatewayServiceList.Items)) + } + + gatewayService := &gatewayServiceList.Items[0] + return gatewayService, nil +} + +// GetServers retrieves the GSLB server configuration from the istio virtual service resource +func (rr *ReferenceResolver) GetServers() ([]*k8gbv1beta1.Server, error) { + hosts := rr.virtualService.Spec.Hosts + if len(hosts) < 1 { + return nil, fmt.Errorf("can't find hosts in VirtualService %s", rr.virtualService.Name) + } + + servers := []*k8gbv1beta1.Server{} + for _, host := range hosts { + server := &k8gbv1beta1.Server{ + Host: host, + Services: []*k8gbv1beta1.NamespacedName{}, + } + for _, http := range rr.virtualService.Spec.Http { + for _, route := range http.Route { + server.Services = append(server.Services, &k8gbv1beta1.NamespacedName{ + Name: route.Destination.Host, + Namespace: rr.virtualService.Namespace, + }) + } + } + for _, tls := range rr.virtualService.Spec.Tls { + for _, route := range tls.Route { + server.Services = append(server.Services, &k8gbv1beta1.NamespacedName{ + Name: route.Destination.Host, + Namespace: rr.virtualService.Namespace, + }) + } + } + for _, tcp := range rr.virtualService.Spec.Tcp { + for _, route := range tcp.Route { + server.Services = append(server.Services, &k8gbv1beta1.NamespacedName{ + Name: route.Destination.Host, + Namespace: rr.virtualService.Namespace, + }) + } + } + servers = append(servers, server) + } + + return servers, nil +} + +// GetGslbExposedIPs retrieves the load balancer IP address of the GSLB +func (rr *ReferenceResolver) GetGslbExposedIPs(edgeDNSServers utils.DNSList) ([]string, error) { + gslbIngressIPs := []string{} + + for _, ip := range rr.lbService.Status.LoadBalancer.Ingress { + if len(ip.IP) > 0 { + gslbIngressIPs = append(gslbIngressIPs, ip.IP) + } + if len(ip.Hostname) > 0 { + IPs, err := utils.Dig(ip.Hostname, edgeDNSServers...) + if err != nil { + log.Warn().Err(err).Msg("Dig error") + return nil, err + } + gslbIngressIPs = append(gslbIngressIPs, IPs...) + } + } + + return gslbIngressIPs, nil +} diff --git a/controllers/refresolver/istiovirtualservice/istiovirtualservice_test.go b/controllers/refresolver/istiovirtualservice/istiovirtualservice_test.go new file mode 100644 index 0000000000..8938e6dd10 --- /dev/null +++ b/controllers/refresolver/istiovirtualservice/istiovirtualservice_test.go @@ -0,0 +1,150 @@ +package istiovirtualservice + +/* +Copyright 2022 The k8gb Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic +*/ + +import ( + "testing" + + k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" + "github.com/k8gb-io/k8gb/controllers/utils" + "github.com/stretchr/testify/assert" +) + +func TestGetServers(t *testing.T) { + var tests = []struct { + name string + virtualServiceFile string + expectedServers []*k8gbv1beta1.Server + }{ + { + name: "single host and route", + virtualServiceFile: "../testdata/istio_virtualservice.yaml", + expectedServers: []*k8gbv1beta1.Server{ + { + Host: "istio.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "istio", + Namespace: "test-gslb", + }, + }, + }, + }, + }, + { + name: "multiple hosts", + virtualServiceFile: "./testdata/istio_virtualservice_multiple_hosts.yaml", + expectedServers: []*k8gbv1beta1.Server{ + { + Host: "istio1.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "istio", + Namespace: "test-gslb", + }, + }, + }, + { + Host: "istio2.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "istio", + Namespace: "test-gslb", + }, + }, + }, + }, + }, + { + name: "multiple routes", + virtualServiceFile: "./testdata/istio_virtualservice_multiple_routes.yaml", + expectedServers: []*k8gbv1beta1.Server{ + { + Host: "istio.cloud.example.com", + Services: []*k8gbv1beta1.NamespacedName{ + { + Name: "istio1", + Namespace: "test-gslb", + }, + { + Name: "istio2", + Namespace: "test-gslb", + }, + }, + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // arrange + vs := utils.FileToIstioVirtualService(test.virtualServiceFile) + resolver := ReferenceResolver{ + virtualService: vs, + } + + // act + servers, err := resolver.GetServers() + assert.NoError(t, err) + + // assert + assert.Equal(t, test.expectedServers, servers) + }) + } +} + +func TestGetGslbExposedIPs(t *testing.T) { + var tests = []struct { + name string + serviceYaml string + expectedIPs []string + }{ + { + name: "no exposed IPs", + serviceYaml: "./testdata/istio_service_no_ips.yaml", + expectedIPs: []string{}, + }, + { + name: "single exposed IP", + serviceYaml: "../testdata/istio_service.yaml", + expectedIPs: []string{"10.0.0.1"}, + }, + { + name: "multiple exposed IPs", + serviceYaml: "./testdata/istio_service_multiple_ips.yaml", + expectedIPs: []string{"10.0.0.1", "10.0.0.2"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // arrange + svc := utils.FileToService(test.serviceYaml) + resolver := ReferenceResolver{ + lbService: svc, + } + + // act + IPs, err := resolver.GetGslbExposedIPs([]utils.DNSServer{}) + assert.NoError(t, err) + + // assert + assert.Equal(t, test.expectedIPs, IPs) + }) + } +} diff --git a/controllers/refresolver/istiovirtualservice/testdata/istio_service_multiple_ips.yaml b/controllers/refresolver/istiovirtualservice/testdata/istio_service_multiple_ips.yaml new file mode 100644 index 0000000000..4cd55a08f1 --- /dev/null +++ b/controllers/refresolver/istiovirtualservice/testdata/istio_service_multiple_ips.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-ingress + labels: + app: istio-ingressgateway +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: istio-ingressgateway + type: LoadBalancer +status: + loadBalancer: + ingress: + - ip: 10.0.0.1 + - ip: 10.0.0.2 diff --git a/controllers/refresolver/istiovirtualservice/testdata/istio_service_no_ips.yaml b/controllers/refresolver/istiovirtualservice/testdata/istio_service_no_ips.yaml new file mode 100644 index 0000000000..e7e0782b72 --- /dev/null +++ b/controllers/refresolver/istiovirtualservice/testdata/istio_service_no_ips.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-ingress + labels: + app: istio-ingressgateway +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8443 + selector: + app: istio-ingressgateway + type: LoadBalancer +status: + loadBalancer: + ingress: diff --git a/controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_hosts.yaml b/controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_hosts.yaml new file mode 100644 index 0000000000..df37dabaa1 --- /dev/null +++ b/controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_hosts.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: istio + namespace: test-gslb + labels: + app: istio +spec: + gateways: + - istio-ingress/istio + hosts: + - istio1.cloud.example.com + - istio2.cloud.example.com + http: + - route: + - destination: + host: istio + port: + number: 80 diff --git a/controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_routes.yaml b/controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_routes.yaml new file mode 100644 index 0000000000..f6f797979d --- /dev/null +++ b/controllers/refresolver/istiovirtualservice/testdata/istio_virtualservice_multiple_routes.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: istio + namespace: test-gslb + labels: + app: istio +spec: + gateways: + - istio-ingress/istio + hosts: + - istio.cloud.example.com + http: + - match: + - uri: + prefix: /debug + route: + - destination: + host: istio1 + port: + number: 80 + - route: + - destination: + host: istio2 + port: + number: 80 diff --git a/controllers/refresolver/refresolver.go b/controllers/refresolver/refresolver.go index b63c19c453..501d5bc03e 100644 --- a/controllers/refresolver/refresolver.go +++ b/controllers/refresolver/refresolver.go @@ -18,49 +18,40 @@ limitations under the License. Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic */ -/* -Copyright 2024 The k8gb Contributors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic -*/ - import ( "fmt" "reflect" + "github.com/davecgh/go-spew/spew" k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" - "github.com/k8gb-io/k8gb/controllers/logging" + "github.com/k8gb-io/k8gb/controllers/refresolver/ingress" + "github.com/k8gb-io/k8gb/controllers/refresolver/istiovirtualservice" "github.com/k8gb-io/k8gb/controllers/utils" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) -var log = logging.Logger() - // GslbReferenceResolver resolves references to other kubernetes resources concerning ingress configuration type GslbReferenceResolver interface { - // GetServers retrieves the server configuration of the GSLB object + // GetServers retrieves GSLB the server configuration GetServers() ([]*k8gbv1beta1.Server, error) // GetGslbExposedIPs retrieves the load balancer IP address of the GSLB - GetGslbExposedIPs(client.Client, utils.DNSList) ([]string, error) + GetGslbExposedIPs(utils.DNSList) ([]string, error) } // New creates a new GSLBReferenceResolver func New(gslb *k8gbv1beta1.Gslb, k8sClient client.Client) (GslbReferenceResolver, error) { - if !reflect.DeepEqual(gslb.Spec.Ingress, k8gbv1beta1.IngressSpec{}) || !reflect.DeepEqual(gslb.Spec.ResourceRef.Ingress, metav1.LabelSelector{}) { - return NewIngressReferenceResolver(gslb, k8sClient) + if reflect.DeepEqual(gslb.Spec.ResourceRef, k8gbv1beta1.ResourceRef{}) { + return ingress.NewEmbeddedResolver(gslb, k8sClient) + } + if gslb.Spec.ResourceRef.Kind == "Ingress" && gslb.Spec.ResourceRef.APIVersion == "networking.k8s.io/v1" { + return ingress.NewReferenceResolver(gslb, k8sClient) + } + if gslb.Spec.ResourceRef.Kind == "VirtualService" { + if gslb.Spec.ResourceRef.APIVersion == "networking.istio.io/v1beta1" || + gslb.Spec.ResourceRef.APIVersion == "networking.istio.io/v1" { + spew.Dump(gslb) + return istiovirtualservice.NewReferenceResolver(gslb, k8sClient) + } } return nil, fmt.Errorf("incomplete gslb configuration, no ingress found") } diff --git a/controllers/refresolver/refresolver_test.go b/controllers/refresolver/refresolver_test.go new file mode 100644 index 0000000000..b5b8740835 --- /dev/null +++ b/controllers/refresolver/refresolver_test.go @@ -0,0 +1,105 @@ +package refresolver + +/* +Copyright 2022 The k8gb Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic +*/ + +import ( + "fmt" + "testing" + + k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" + utils "github.com/k8gb-io/k8gb/controllers/utils" + "github.com/stretchr/testify/assert" + istio "istio.io/client-go/pkg/apis/networking/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +// TestNew tests if the RefResolver is instantiated with the correct type +func TestNew(t *testing.T) { + var tests = []struct { + name string + gslbYaml string + expectedReferenceResolverType string + expectedError error + }{ + { + name: "embedded ingress", + gslbYaml: "./testdata/gslb_ingress_embedded.yaml", + expectedReferenceResolverType: "*ingress.ReferenceResolver", + expectedError: nil, + }, + { + name: "referenced ingress", + gslbYaml: "./testdata/gslb_ingress_referenced.yaml", + expectedReferenceResolverType: "*ingress.ReferenceResolver", + expectedError: nil, + }, + { + name: "referenced istio", + gslbYaml: "./testdata/gslb_istio.yaml", + expectedReferenceResolverType: "*istiovirtualservice.ReferenceResolver", + expectedError: nil, + }, + { + // only the embedded resolver will be picked up + name: "referenced and embedded ingress", + gslbYaml: "./testdata/gslb_ingress_referenced_and_embedded.yaml", + expectedReferenceResolverType: "*ingress.ReferenceResolver", + expectedError: nil, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // arrange + cl, gslb := getTestContext(test.gslbYaml) + + // act + resolver, err := New(gslb, cl) + + // assert + assert.Equal(t, test.expectedError, err) + if err == nil { + assert.Equal(t, test.expectedReferenceResolverType, fmt.Sprintf("%T", resolver)) + } + }) + } +} + +// getTextContext creates a kubernetes client with access to all objects that need to be looked up +func getTestContext(gslbFile string) (client.Client, *k8gbv1beta1.Gslb) { + gslb := utils.FileToGSLB(gslbFile) + objs := []runtime.Object{ + gslb, + utils.FileToIngress("./testdata/ingress_referenced.yaml"), + utils.FileToIngress("./testdata/ingress_embedded.yaml"), + utils.FileToIstioVirtualService("./testdata/istio_virtualservice.yaml"), + utils.FileToIstioGateway("./testdata/istio_gateway.yaml"), + utils.FileToService("./testdata/istio_service.yaml"), + } + // Register operator types with the runtime scheme. + s := scheme.Scheme + s.AddKnownTypes(k8gbv1beta1.GroupVersion, &k8gbv1beta1.Gslb{}, &k8gbv1beta1.GslbList{}) + s.AddKnownTypes(istio.SchemeGroupVersion, &istio.VirtualService{}, &istio.VirtualServiceList{}) + s.AddKnownTypes(istio.SchemeGroupVersion, &istio.Gateway{}, &istio.GatewayList{}) + cl := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build() + + return cl, gslb +} diff --git a/controllers/refresolver/testdata/gslb_embedded.yaml b/controllers/refresolver/testdata/gslb_ingress_embedded.yaml similarity index 78% rename from controllers/refresolver/testdata/gslb_embedded.yaml rename to controllers/refresolver/testdata/gslb_ingress_embedded.yaml index b199886d6c..5099a7275f 100644 --- a/controllers/refresolver/testdata/gslb_embedded.yaml +++ b/controllers/refresolver/testdata/gslb_ingress_embedded.yaml @@ -1,20 +1,20 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: embedded + name: ingress-embedded namespace: test-gslb spec: ingress: ingressClassName: nginx rules: - - host: embedded.cloud.example.com + - host: ingress-embedded.cloud.example.com http: paths: - path: / pathType: Prefix backend: service: - name: embedded + name: ingress-embedded port: name: http strategy: diff --git a/controllers/refresolver/testdata/gslb_ingress_referenced.yaml b/controllers/refresolver/testdata/gslb_ingress_referenced.yaml new file mode 100644 index 0000000000..b54336f986 --- /dev/null +++ b/controllers/refresolver/testdata/gslb_ingress_referenced.yaml @@ -0,0 +1,15 @@ +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: ingress-referenced + namespace: test-gslb +spec: + resourceRef: + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: ingress-referenced + strategy: + type: roundRobin + splitBrainThresholdSeconds: 300 + dnsTtlSeconds: 30 diff --git a/controllers/refresolver/testdata/gslb_referenced_and_embedded.yaml b/controllers/refresolver/testdata/gslb_ingress_referenced_and_embedded.yaml similarity index 66% rename from controllers/refresolver/testdata/gslb_referenced_and_embedded.yaml rename to controllers/refresolver/testdata/gslb_ingress_referenced_and_embedded.yaml index 1073d464dd..0455a70bbe 100644 --- a/controllers/refresolver/testdata/gslb_referenced_and_embedded.yaml +++ b/controllers/refresolver/testdata/gslb_ingress_referenced_and_embedded.yaml @@ -1,24 +1,25 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: embedded + name: ingress-embedded namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: referenced + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: ingress-referenced ingress: ingressClassName: nginx rules: - - host: embedded.cloud.example.com + - host: ingress-embedded.cloud.example.com http: paths: - path: / pathType: Prefix backend: service: - name: embedded + name: ingress-embedded port: name: http strategy: diff --git a/controllers/refresolver/testdata/gslb_referenced.yaml b/controllers/refresolver/testdata/gslb_istio.yaml similarity index 62% rename from controllers/refresolver/testdata/gslb_referenced.yaml rename to controllers/refresolver/testdata/gslb_istio.yaml index 271a00ebee..0ca91933d5 100644 --- a/controllers/refresolver/testdata/gslb_referenced.yaml +++ b/controllers/refresolver/testdata/gslb_istio.yaml @@ -1,13 +1,14 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: referenced + name: istio namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: referenced + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: istio strategy: type: roundRobin splitBrainThresholdSeconds: 300 diff --git a/controllers/refresolver/testdata/ingress_embedded.yaml b/controllers/refresolver/testdata/ingress_embedded.yaml index 7b939fe47d..7a495ac30e 100644 --- a/controllers/refresolver/testdata/ingress_embedded.yaml +++ b/controllers/refresolver/testdata/ingress_embedded.yaml @@ -1,19 +1,23 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: embedded + name: ingress-embedded namespace: test-gslb resourceVersion: "999" spec: ingressClassName: nginx rules: - - host: embedded.cloud.example.com + - host: ingress-embedded.cloud.example.com http: paths: - path: / pathType: Prefix backend: service: - name: embedded + name: ingress-embedded port: name: http +status: + loadBalancer: + ingress: + - ip: 10.0.0.1 diff --git a/controllers/refresolver/testdata/ingress_referenced.yaml b/controllers/refresolver/testdata/ingress_referenced.yaml index e4b4e8a61b..fab04fb9f0 100644 --- a/controllers/refresolver/testdata/ingress_referenced.yaml +++ b/controllers/refresolver/testdata/ingress_referenced.yaml @@ -2,23 +2,24 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: labels: - app: referenced - name: referenced + app: ingress-referenced + name: ingress-referenced namespace: test-gslb resourceVersion: "999" spec: ingressClassName: nginx rules: - - host: referenced.cloud.example.com + - host: ingress-referenced.cloud.example.com http: paths: - path: / pathType: Prefix backend: service: - name: referenced + name: ingress-referenced port: name: http status: loadBalancer: ingress: + - ip: 10.0.0.1 diff --git a/controllers/refresolver/testdata/istio_gateway.yaml b/controllers/refresolver/testdata/istio_gateway.yaml new file mode 100644 index 0000000000..9af565aeab --- /dev/null +++ b/controllers/refresolver/testdata/istio_gateway.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: istio + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - istio.cloud.example.com + port: + name: http + number: 8080 + protocol: http diff --git a/controllers/refresolver/testdata/istio_service.yaml b/controllers/refresolver/testdata/istio_service.yaml new file mode 100644 index 0000000000..b87da87c61 --- /dev/null +++ b/controllers/refresolver/testdata/istio_service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-ingress + labels: + app: istio-ingressgateway +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: istio-ingressgateway + type: LoadBalancer +status: + loadBalancer: + ingress: + - ip: 10.0.0.1 diff --git a/controllers/refresolver/testdata/istio_virtualservice.yaml b/controllers/refresolver/testdata/istio_virtualservice.yaml new file mode 100644 index 0000000000..805537535a --- /dev/null +++ b/controllers/refresolver/testdata/istio_virtualservice.yaml @@ -0,0 +1,18 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + labels: + app: istio + name: istio + namespace: test-gslb +spec: + gateways: + - istio-ingress/istio + hosts: + - istio.cloud.example.com + http: + - route: + - destination: + host: istio + port: + number: 80 diff --git a/controllers/tracing/tracing.go b/controllers/tracing/tracing.go index b3121e4679..f50c708eee 100644 --- a/controllers/tracing/tracing.go +++ b/controllers/tracing/tracing.go @@ -31,6 +31,7 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.6.1" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) const ( @@ -48,8 +49,7 @@ type Settings struct { func SetupTracing(ctx context.Context, cfg Settings, log *zerolog.Logger) (func(), trace.Tracer) { if !cfg.Enabled { log.Info().Msg("OTLP tracing is disabled") - //nolint:staticcheck - return func() {}, trace.NewNoopTracerProvider().Tracer(instrumentationName) + return func() {}, noop.NewTracerProvider().Tracer(instrumentationName) } log.Info().Msg("OTLP tracing is ON") client := otlptracehttp.NewClient( diff --git a/controllers/utils/yaml.go b/controllers/utils/yaml.go index 1d91d79096..31fb0f866a 100644 --- a/controllers/utils/yaml.go +++ b/controllers/utils/yaml.go @@ -21,13 +21,85 @@ Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic import ( "encoding/json" + "fmt" + "os" yamlConv "github.com/ghodss/yaml" k8gbv1beta1 "github.com/k8gb-io/k8gb/api/v1beta1" + istio "istio.io/client-go/pkg/apis/networking/v1" + corev1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" + // TODO: does this code run also for v1beta1 CRDs? No it does not + // What if we add those to the schema? Look for "istio.io/client-go/pkg/apis/networking/v1" in the code ) -// YamlToGslb takes yaml and returns Gslb object +// FileToGSLB takes a file and returns a GSLB object +func FileToGSLB(file string) *k8gbv1beta1.Gslb { + yaml, err := os.ReadFile(file) + if err != nil { + panic(fmt.Errorf("can't open example CR file: %s", file)) + } + gslb, err := YamlToGslb(yaml) + if err != nil { + panic(err) + } + return gslb + +} + +// FileToIngress takes a file and returns an Ingress object +func FileToIngress(file string) *netv1.Ingress { + ingressYaml, err := os.ReadFile(file) + if err != nil { + panic(fmt.Errorf("can't open example CR file: %s", file)) + } + ingress, err := YamlToIngress(ingressYaml) + if err != nil { + panic(err) + } + return ingress +} + +// FileToIstioVirtualService takes a file and returns a VirtualService object +func FileToIstioVirtualService(file string) *istio.VirtualService { + yaml, err := os.ReadFile(file) + if err != nil { + panic(fmt.Errorf("can't open example CR file: %s", file)) + } + vs, err := YamlToIstioVirtualService(yaml) + if err != nil { + panic(err) + } + return vs +} + +// FileToIstioGateway takes a file and returns a Gateway object +func FileToIstioGateway(file string) *istio.Gateway { + yaml, err := os.ReadFile(file) + if err != nil { + panic(fmt.Errorf("can't open example CR file: %s", file)) + } + gw, err := YamlToIstioGateway(yaml) + if err != nil { + panic(err) + } + return gw +} + +// FileToService takes a file and returns a Service object +func FileToService(file string) *corev1.Service { + yaml, err := os.ReadFile(file) + if err != nil { + panic(fmt.Errorf("can't open example CR file: %s", file)) + } + svc, err := YamlToService(yaml) + if err != nil { + panic(err) + } + return svc +} + +// YamlToGslb takes yaml and returns a Gslb object func YamlToGslb(yaml []byte) (*k8gbv1beta1.Gslb, error) { // yamlBytes contains a []byte of my yaml job spec // convert the yaml to json @@ -60,3 +132,52 @@ func YamlToIngress(yaml []byte) (*netv1.Ingress, error) { } return ingress, nil } + +// YamlToService takes yaml and returns a Kubernetes Service object +func YamlToService(yaml []byte) (*corev1.Service, error) { + // convert the yaml to json + jsonBytes, err := yamlConv.YAMLToJSON(yaml) + if err != nil { + return &corev1.Service{}, err + } + // unmarshal the json into the kube struct + svc := &corev1.Service{} + err = json.Unmarshal(jsonBytes, &svc) + if err != nil { + return &corev1.Service{}, err + } + return svc, nil +} + +// YamlToIstioVirtualService takes yaml and returns an Istio Virtual Service object +func YamlToIstioVirtualService(yaml []byte) (*istio.VirtualService, error) { + // convert the yaml to json + jsonBytes, err := yamlConv.YAMLToJSON(yaml) + if err != nil { + return &istio.VirtualService{}, err + } + // unmarshal the json into the kube struct + vs := &istio.VirtualService{} + err = json.Unmarshal(jsonBytes, &vs) + if err != nil { + return &istio.VirtualService{}, err + } + return vs, nil +} + +// YamlToIstioGateway takes yaml and returns an Istio Gateway object +func YamlToIstioGateway(yaml []byte) (*istio.Gateway, error) { + // yamlBytes contains a []byte of my yaml job spec + // convert the yaml to json + jsonBytes, err := yamlConv.YAMLToJSON(yaml) + if err != nil { + return &istio.Gateway{}, err + } + // unmarshal the json into the kube struct + gw := &istio.Gateway{} + err = json.Unmarshal(jsonBytes, &gw) + if err != nil { + return &istio.Gateway{}, err + } + return gw, nil +} diff --git a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml similarity index 95% rename from deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml rename to deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml index 43fa6b458a..93309d257c 100644 --- a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml +++ b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml @@ -1,7 +1,7 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: test-gslb-failover + name: failover-ingress namespace: test-gslb spec: ingress: diff --git a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_istio.yaml b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_istio.yaml new file mode 100644 index 0000000000..f0290921da --- /dev/null +++ b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_istio.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: failover-istio + namespace: test-gslb-istio + labels: + app: failover-istio +spec: + gateways: + - istio-ingress/failover-istio + hosts: + - failover-istio.cloud.example.com + http: + - route: + - destination: + host: frontend-podinfo + port: + number: 9898 +--- +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: failover-istio + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - failover-istio.cloud.example.com + port: + number: 8080 + name: http + protocol: http +--- +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: failover-istio + namespace: test-gslb-istio +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: failover-istio + strategy: + type: failover + primaryGeoTag: eu diff --git a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_notfound_istio.yaml b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_notfound_istio.yaml new file mode 100644 index 0000000000..8fe4acc725 --- /dev/null +++ b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_notfound_istio.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: notfound-istio + namespace: test-gslb-istio + labels: + app: notfound-istio +spec: + gateways: + - istio-ingress/notfound-istio + hosts: + - notfound-istio.cloud.example.com + http: + - route: + - destination: + host: non-existing-app + port: + number: 9898 +--- +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: notfound-istio + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - notfound-istio.cloud.example.com + port: + number: 8080 + name: http + protocol: http +--- +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: notfound-istio + namespace: test-gslb-istio +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: notfound-istio + strategy: + type: roundRobin + splitBrainThresholdSeconds: 300 + dnsTtlSeconds: 30 diff --git a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml similarity index 98% rename from deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml rename to deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml index 4731328858..e1f213ffb5 100644 --- a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml +++ b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml @@ -1,7 +1,7 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: test-gslb + name: roundrobin-ingress namespace: test-gslb spec: ingress: diff --git a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_istio.yaml b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_istio.yaml new file mode 100644 index 0000000000..6c54d90dd0 --- /dev/null +++ b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_istio.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: roundrobin-istio + namespace: test-gslb-istio + labels: + app: roundrobin-istio +spec: + gateways: + - istio-ingress/roundrobin-istio + hosts: + - roundrobin-istio.cloud.example.com + http: + - route: + - destination: + host: frontend-podinfo + port: + number: 9898 +--- +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: roundrobin-istio + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - roundrobin-istio.cloud.example.com + port: + number: 8080 + name: http + protocol: http +--- +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: roundrobin-istio + namespace: test-gslb-istio +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: roundrobin-istio + strategy: + type: roundRobin + splitBrainThresholdSeconds: 300 + dnsTtlSeconds: 30 diff --git a/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_unhealthy_istio.yaml b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_unhealthy_istio.yaml new file mode 100644 index 0000000000..1c13a5a7de --- /dev/null +++ b/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_unhealthy_istio.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: unhealthy-istio + namespace: test-gslb-istio + labels: + app: unhealthy-istio +spec: + gateways: + - istio-ingress/unhealthy-istio + hosts: + - unhealthy-istio.cloud.example.com + http: + - route: + - destination: + host: unhealthy-istio-app + port: + number: 80 +--- +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: unhealthy-istio + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - unhealthy-istio.cloud.example.com + port: + number: 8080 + name: http + protocol: http +--- +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: unhealthy-istio + namespace: test-gslb-istio +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: unhealthy-istio + strategy: + type: roundRobin + splitBrainThresholdSeconds: 300 + dnsTtlSeconds: 30 diff --git a/deploy/crds/test-namespace.yaml b/deploy/crds/test-namespace-ingress.yaml similarity index 100% rename from deploy/crds/test-namespace.yaml rename to deploy/crds/test-namespace-ingress.yaml diff --git a/deploy/crds/test-namespace-istio.yaml b/deploy/crds/test-namespace-istio.yaml new file mode 100644 index 0000000000..3d2388736a --- /dev/null +++ b/deploy/crds/test-namespace-istio.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: test-gslb-istio + labels: + istio-injection: enabled diff --git a/deploy/ingress/istio-ingress-values.yaml b/deploy/ingress/istio-ingress-values.yaml new file mode 100644 index 0000000000..15f624fc7c --- /dev/null +++ b/deploy/ingress/istio-ingress-values.yaml @@ -0,0 +1,26 @@ +# the ingress port on k3d is open only on the agent-0 node +# so we need to make sure the ingress controller runs on that node +affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - k3d-test-gslb1-agent-0 + - k3d-test-gslb2-agent-0 + - k3d-test-gslb3-agent-0 + - k3d-test-gslb4-agent-0 + - k3d-test-gslb5-agent-0 + - k3d-test-gslb6-agent-0 + - k3d-test-gslb7-agent-0 + - k3d-test-gslb8-agent-0 +autoscaling: + enabled: false +service: + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: 8080 diff --git a/deploy/test-apps/unhealthy-app-svc.yaml b/deploy/test-apps/unhealthy-app-svc.yaml index 1994ce9780..1fbc1e471c 100644 --- a/deploy/test-apps/unhealthy-app-svc.yaml +++ b/deploy/test-apps/unhealthy-app-svc.yaml @@ -1,3 +1,4 @@ +--- apiVersion: v1 kind: Service metadata: @@ -14,3 +15,20 @@ spec: run: unhealthy-app sessionAffinity: None type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + labels: + run: unhealthy-app + name: unhealthy-app + namespace: test-gslb-istio +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + run: unhealthy-app + sessionAffinity: None + type: ClusterIP diff --git a/deploy/test-apps/unhealthy-app.yaml b/deploy/test-apps/unhealthy-app.yaml index 03dcda7621..5e75f3417a 100644 --- a/deploy/test-apps/unhealthy-app.yaml +++ b/deploy/test-apps/unhealthy-app.yaml @@ -1,3 +1,4 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -19,3 +20,25 @@ spec: - image: nginx imagePullPolicy: Always name: unhealthy-app +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + run: unhealthy-app + name: unhealthy-app + namespace: test-gslb-istio +spec: + replicas: 0 + selector: + matchLabels: + run: unhealthy-app + template: + metadata: + labels: + run: unhealthy-app + spec: + containers: + - image: nginx + imagePullPolicy: Always + name: unhealthy-app diff --git a/docs/deploy_cloudflare.md b/docs/deploy_cloudflare.md index 7f2b577084..ba50f53461 100644 --- a/docs/deploy_cloudflare.md +++ b/docs/deploy_cloudflare.md @@ -86,9 +86,10 @@ metadata: namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: test-gslb-failover + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: test-gslb-failover strategy: dnsTtlSeconds: 60 # Minimum for non-Enterprise Cloudflare https://developers.cloudflare.com/dns/manage-dns-records/reference/ttl/ primaryGeoTag: eu diff --git a/docs/deploy_infoblox.md b/docs/deploy_infoblox.md index cd86536999..a8581cb922 100644 --- a/docs/deploy_infoblox.md +++ b/docs/deploy_infoblox.md @@ -113,9 +113,10 @@ metadata: namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: podinfo + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: podinfo ``` * And apply the resource in the target app namespace diff --git a/docs/examples/cloudflare/test-gslb-failover.yaml b/docs/examples/cloudflare/test-gslb-failover.yaml index cf917850bc..f292d857fb 100644 --- a/docs/examples/cloudflare/test-gslb-failover.yaml +++ b/docs/examples/cloudflare/test-gslb-failover.yaml @@ -27,9 +27,10 @@ metadata: namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: test-gslb-failover + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: test-gslb-failover strategy: dnsTtlSeconds: 60 # Minimum for non-Enterprise Cloudflare https://developers.cloudflare.com/dns/manage-dns-records/reference/ttl/ primaryGeoTag: eu diff --git a/docs/examples/route53/k8gb/gslb-failover.yaml b/docs/examples/route53/k8gb/gslb-failover.yaml index e427ef3b27..b3c131d334 100644 --- a/docs/examples/route53/k8gb/gslb-failover.yaml +++ b/docs/examples/route53/k8gb/gslb-failover.yaml @@ -26,9 +26,10 @@ metadata: namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: failover + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: failover strategy: type: failover # Global load balancing strategy primaryGeoTag: eu-west-1 # Primary cluster geo tag diff --git a/docs/examples/route53/k8gb/gslb-roundrobin.yaml b/docs/examples/route53/k8gb/gslb-roundrobin.yaml index 87b4863442..6eab171515 100644 --- a/docs/examples/route53/k8gb/gslb-roundrobin.yaml +++ b/docs/examples/route53/k8gb/gslb-roundrobin.yaml @@ -44,9 +44,10 @@ metadata: namespace: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: test-gslb + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: test-gslb strategy: type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too splitBrainThresholdSeconds: 300 # Threshold after which external cluster is filtered out from delegated zone when it doesn't look alive diff --git a/docs/index.md b/docs/index.md index 373caeb6b9..3671144162 100644 --- a/docs/index.md +++ b/docs/index.md @@ -55,9 +55,10 @@ metadata: name: app spec: resourceRef: - ingress: - matchLabels: - app: app + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: app strategy: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too ``` diff --git a/docs/local.md b/docs/local.md index eb00b58c14..d51e331fab 100644 --- a/docs/local.md +++ b/docs/local.md @@ -137,7 +137,7 @@ make destroy-full-local-setup Both clusters have [podinfo](https://github.com/stefanprodan/podinfo) installed on the top, where each cluster has been tagged to serve a different region. In this demo we will hit podinfo by `wget -qO - roundrobin.cloud.example.com` and depending on the region, podinfo will return **us** or **eu**. In the current round robin implementation IP addresses are randomly picked. -See [Gslb manifest with round robin strategy](https://github.com/k8gb-io/k8gb/tree/master/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr.yaml) +See [Gslb manifest with round robin strategy](https://github.com/k8gb-io/k8gb/tree/master/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_roundrobin_ingress.yaml) Try to run the following command several times and watch the `message` field. ```sh @@ -167,7 +167,7 @@ As expected result you should see podinfo message changing Both clusters have [podinfo](https://github.com/stefanprodan/podinfo) installed on the top where each cluster has been tagged to serve a different region. In this demo we will hit podinfo by `wget -qO - failover.cloud.example.com` and depending on whether podinfo is running inside the cluster it returns only **eu** or **us**. -See [Gslb manifest with failover strategy](https://github.com/k8gb-io/k8gb/tree/master/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover.yaml) +See [Gslb manifest with failover strategy](https://github.com/k8gb-io/k8gb/tree/master/deploy/crds/k8gb.absa.oss_v1beta1_gslb_cr_failover_ingress.yaml) Switch GLSB to failover mode: ```sh diff --git a/go.mod b/go.mod index 8c7e586753..b293739eae 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 go.opentelemetry.io/otel/trace v1.29.0 go.uber.org/mock v0.4.0 + istio.io/client-go v1.22.4 k8s.io/api v0.31.0 k8s.io/apimachinery v0.31.0 k8s.io/client-go v0.31.0 @@ -31,7 +32,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.0 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect @@ -87,6 +87,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + istio.io/api v1.22.4-0.20240808015337-e0ff1ca45c33 // indirect k8s.io/apiextensions-apiserver v0.31.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 // indirect diff --git a/go.sum b/go.sum index 0e533a5a98..e8a8c5d602 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -67,8 +65,8 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -105,15 +103,13 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -155,8 +151,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/miekg/dns v1.1.0/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= -github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -178,30 +172,24 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= @@ -226,28 +214,16 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= @@ -276,13 +252,9 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -291,8 +263,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -311,14 +281,10 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -327,8 +293,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -357,19 +321,13 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -405,40 +363,30 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +istio.io/api v1.22.4-0.20240808015337-e0ff1ca45c33 h1:/IeYCiL05FL8ZxndwibKznhLsrZRDH0xaHwsk/roU7I= +istio.io/api v1.22.4-0.20240808015337-e0ff1ca45c33/go.mod h1:S3l8LWqNYS9yT+d4bH+jqzH2lMencPkW7SKM1Cu9EyM= +istio.io/client-go v1.22.4 h1:55aKo0iDD/IZmz0HU0f0UjOeTO4bg43DLnfASYD2lq4= +istio.io/client-go v1.22.4/go.mod h1:pCCBfkXZVAxptGlL5gdGIonPxFsNQZ+iBxvYIUF9z7c= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= -k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= -k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= -k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= -k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= -k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 h1:Q8Z7VlGhcJgBHJHYugJ/K/7iB8a2eSxCyxdVjJp+lLY= k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= -k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= -sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/external-dns v0.14.2 h1:j7rYtQqDAxYfN9N1/BZcRdzUBRsnZp4tZcuZ75ekTlc= diff --git a/k3d/test-gslb1.yaml b/k3d/test-gslb1.yaml index 502af8e718..3fc48deccd 100644 --- a/k3d/test-gslb1.yaml +++ b/k3d/test-gslb1.yaml @@ -11,6 +11,9 @@ ports: - port: 80:80 nodeFilters: - agent:0:direct + - port: 8080:8080 + nodeFilters: + - agent:0:direct - port: 443:443 nodeFilters: - agent:0:direct @@ -31,7 +34,7 @@ options: disableLoadbalancer: true k3s: extraArgs: - - arg: --disable=traefik,servicelb,metrics-server,local-storage + - arg: --disable=traefik,metrics-server,local-storage nodeFilters: - server:* registries: diff --git a/k3d/test-gslb2.yaml b/k3d/test-gslb2.yaml index db95b10136..8292a9c4a8 100644 --- a/k3d/test-gslb2.yaml +++ b/k3d/test-gslb2.yaml @@ -11,6 +11,9 @@ ports: - port: 81:80 nodeFilters: - agent:0:direct + - port: 8081:8080 + nodeFilters: + - agent:0:direct - port: 444:443 nodeFilters: - agent:0:direct @@ -28,7 +31,7 @@ options: disableLoadbalancer: true k3s: extraArgs: - - arg: --disable=traefik,servicelb,metrics-server,local-storage + - arg: --disable=traefik,metrics-server,local-storage nodeFilters: - server:* registries: diff --git a/k3d/test-gslb3.yaml b/k3d/test-gslb3.yaml index c19231e5b1..8e0308ab5d 100644 --- a/k3d/test-gslb3.yaml +++ b/k3d/test-gslb3.yaml @@ -11,6 +11,9 @@ ports: - port: 82:80 nodeFilters: - agent:0:direct + - port: 8082:8080 + nodeFilters: + - agent:0:direct - port: 445:443 nodeFilters: - agent:0:direct @@ -28,7 +31,7 @@ options: disableLoadbalancer: true k3s: extraArgs: - - arg: --disable=traefik,servicelb,metrics-server,local-storage + - arg: --disable=traefik,metrics-server,local-storage nodeFilters: - server:* registries: diff --git a/main.go b/main.go index a9657c3af9..e3f3b0674d 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ import ( "github.com/k8gb-io/k8gb/controllers/providers/dns" "github.com/k8gb-io/k8gb/controllers/providers/metrics" "github.com/k8gb-io/k8gb/controllers/tracing" + istio "istio.io/client-go/pkg/apis/networking/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -49,8 +50,8 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(runtimescheme)) - utilruntime.Must(k8gbv1beta1.AddToScheme(runtimescheme)) + utilruntime.Must(istio.AddToScheme(runtimescheme)) // +kubebuilder:scaffold:scheme } diff --git a/terratest/examples/failover-istio-gateway.yaml b/terratest/examples/failover-istio-gateway.yaml new file mode 100644 index 0000000000..dd6c8668af --- /dev/null +++ b/terratest/examples/failover-istio-gateway.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: terratest-failover + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - terratest-failover.cloud.example.com + port: + name: http + number: 8080 + protocol: http diff --git a/terratest/examples/failover-istio-gslb.yaml b/terratest/examples/failover-istio-gslb.yaml new file mode 100644 index 0000000000..f67555cfce --- /dev/null +++ b/terratest/examples/failover-istio-gslb.yaml @@ -0,0 +1,14 @@ +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: terratest-failover +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: terratest-failover + strategy: + type: failover + dnsTtlSeconds: 5 + primaryGeoTag: "eu" diff --git a/terratest/examples/failover-istio-virtualservice.yaml b/terratest/examples/failover-istio-virtualservice.yaml new file mode 100644 index 0000000000..d0ced51247 --- /dev/null +++ b/terratest/examples/failover-istio-virtualservice.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: terratest-failover + labels: + app: terratest-failover +spec: + gateways: + - istio-ingress/terratest-failover + hosts: + - terratest-failover.cloud.example.com + http: + - route: + - destination: + host: frontend-podinfo + port: + number: 9898 diff --git a/terratest/examples/failover-playground-istio-gateway.yaml b/terratest/examples/failover-playground-istio-gateway.yaml new file mode 100644 index 0000000000..5cee97f434 --- /dev/null +++ b/terratest/examples/failover-playground-istio-gateway.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: playground-failover + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - playground-failover.cloud.example.com + port: + name: http + number: 8080 + protocol: http diff --git a/terratest/examples/failover-playground-istio-gslb.yaml b/terratest/examples/failover-playground-istio-gslb.yaml new file mode 100644 index 0000000000..a562dcad8d --- /dev/null +++ b/terratest/examples/failover-playground-istio-gslb.yaml @@ -0,0 +1,14 @@ +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: playground-failover +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: playground-failover + strategy: + type: failover + dnsTtlSeconds: 5 + primaryGeoTag: "eu" diff --git a/terratest/examples/failover-playground-istio-virtualservice.yaml b/terratest/examples/failover-playground-istio-virtualservice.yaml new file mode 100644 index 0000000000..3678ad873b --- /dev/null +++ b/terratest/examples/failover-playground-istio-virtualservice.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: playground-failover + labels: + app: playground-failover +spec: + gateways: + - istio-ingress/playground-failover + hosts: + - playground-failover.cloud.example.com + http: + - route: + - destination: + host: frontend-podinfo + port: + number: 9898 diff --git a/terratest/examples/failover-playground-ref-gslb.yaml b/terratest/examples/failover-playground-ref-gslb.yaml index fa77797c58..6b17823cb9 100644 --- a/terratest/examples/failover-playground-ref-gslb.yaml +++ b/terratest/examples/failover-playground-ref-gslb.yaml @@ -1,12 +1,13 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: test-gslb + name: playground-failover spec: resourceRef: - ingress: - matchLabels: - app: test-gslb + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: playground-failover strategy: type: failover dnsTtlSeconds: 5 diff --git a/terratest/examples/failover-playground-ref-ingress.yaml b/terratest/examples/failover-playground-ref-ingress.yaml index 509542e81e..355c7991c3 100644 --- a/terratest/examples/failover-playground-ref-ingress.yaml +++ b/terratest/examples/failover-playground-ref-ingress.yaml @@ -1,9 +1,9 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: test-gslb + name: playground-failover labels: - app: test-gslb + app: playground-failover spec: ingressClassName: nginx rules: diff --git a/terratest/examples/failover-playground.yaml b/terratest/examples/failover-playground.yaml index 031e77070c..dc3ed0eed5 100644 --- a/terratest/examples/failover-playground.yaml +++ b/terratest/examples/failover-playground.yaml @@ -1,7 +1,7 @@ apiVersion: k8gb.absa.oss/v1beta1 kind: Gslb metadata: - name: test-gslb + name: playground-failover spec: ingress: ingressClassName: nginx diff --git a/terratest/examples/failover-ref-gslb.yaml b/terratest/examples/failover-ref-gslb.yaml index fa77797c58..a83ec0dcfe 100644 --- a/terratest/examples/failover-ref-gslb.yaml +++ b/terratest/examples/failover-ref-gslb.yaml @@ -4,9 +4,10 @@ metadata: name: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: test-gslb + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: test-gslb strategy: type: failover dnsTtlSeconds: 5 diff --git a/terratest/examples/failover.yaml b/terratest/examples/failover.yaml index b6694e9b2e..fba6772cb7 100644 --- a/terratest/examples/failover.yaml +++ b/terratest/examples/failover.yaml @@ -9,13 +9,13 @@ spec: - host: terratest-failover.cloud.example.com http: paths: - - path: / - pathType: Prefix - backend: - service: - name: frontend-podinfo # Gslb should reflect Healthy status and create associated DNS records - port: - name: http + - path: / + pathType: Prefix + backend: + service: + name: frontend-podinfo # Gslb should reflect Healthy status and create associated DNS records + port: + name: http strategy: type: failover dnsTtlSeconds: 5 diff --git a/terratest/examples/roundrobin-weight1-istio-gateway.yaml b/terratest/examples/roundrobin-weight1-istio-gateway.yaml new file mode 100644 index 0000000000..a78f1f48f4 --- /dev/null +++ b/terratest/examples/roundrobin-weight1-istio-gateway.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: test-gslb + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - terratest-roundrobin.cloud.example.com + port: + name: http + number: 8080 + protocol: http diff --git a/terratest/examples/roundrobin-weight1-istio-gslb.yaml b/terratest/examples/roundrobin-weight1-istio-gslb.yaml new file mode 100644 index 0000000000..afb2e4edc6 --- /dev/null +++ b/terratest/examples/roundrobin-weight1-istio-gslb.yaml @@ -0,0 +1,16 @@ +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: test-gslb +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: test-gslb + strategy: + type: roundRobin + dnsTtlSeconds: 5 + weight: + eu: 5 + us: 5 diff --git a/terratest/examples/roundrobin-weight1-istio-virtualservice.yaml b/terratest/examples/roundrobin-weight1-istio-virtualservice.yaml new file mode 100644 index 0000000000..066a75662c --- /dev/null +++ b/terratest/examples/roundrobin-weight1-istio-virtualservice.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: test-gslb + labels: + app: test-gslb +spec: + gateways: + - istio-ingress/test-gslb + hosts: + - terratest-roundrobin.cloud.example.com + http: + - route: + - destination: + host: frontend-podinfo + port: + number: 9898 diff --git a/terratest/examples/roundrobin-weight1-ref-gslb.yaml b/terratest/examples/roundrobin-weight1-ref-gslb.yaml index 0ddb8d10a0..410647951a 100644 --- a/terratest/examples/roundrobin-weight1-ref-gslb.yaml +++ b/terratest/examples/roundrobin-weight1-ref-gslb.yaml @@ -4,9 +4,10 @@ metadata: name: test-gslb spec: resourceRef: - ingress: - matchLabels: - app: test-gslb + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: test-gslb strategy: type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too dnsTtlSeconds: 5 diff --git a/terratest/examples/roundrobin2-istio-gateway.yaml b/terratest/examples/roundrobin2-istio-gateway.yaml new file mode 100644 index 0000000000..3f4fe8f4f9 --- /dev/null +++ b/terratest/examples/roundrobin2-istio-gateway.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.istio.io/v1 +kind: Gateway +metadata: + name: roundrobin-test-gslb + namespace: istio-ingress +spec: + selector: + app: istio-ingressgateway + servers: + - hosts: + - roundrobin-test.cloud.example.com + port: + name: http + number: 8080 + protocol: http diff --git a/terratest/examples/roundrobin2-istio-gslb.yaml b/terratest/examples/roundrobin2-istio-gslb.yaml new file mode 100644 index 0000000000..27af927ebd --- /dev/null +++ b/terratest/examples/roundrobin2-istio-gslb.yaml @@ -0,0 +1,13 @@ +apiVersion: k8gb.absa.oss/v1beta1 +kind: Gslb +metadata: + name: roundrobin-test-gslb +spec: + resourceRef: + apiVersion: networking.istio.io/v1 + kind: VirtualService + matchLabels: + app: roundrobin-test + strategy: + type: roundRobin + dnsTtlSeconds: 5 diff --git a/terratest/examples/roundrobin2-istio-virtualservice.yaml b/terratest/examples/roundrobin2-istio-virtualservice.yaml new file mode 100644 index 0000000000..d005fcd89b --- /dev/null +++ b/terratest/examples/roundrobin2-istio-virtualservice.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1 +kind: VirtualService +metadata: + name: roundrobin-test-gslb + labels: + app: roundrobin-test +spec: + gateways: + - istio-ingress/roundrobin-test-gslb + hosts: + - roundrobin-test.cloud.example.com + http: + - route: + - destination: + host: frontend-podinfo + port: + number: 9898 diff --git a/terratest/examples/roundrobin2-ref-gslb.yaml b/terratest/examples/roundrobin2-ref-gslb.yaml index 84e0794c81..e86bb8aebd 100644 --- a/terratest/examples/roundrobin2-ref-gslb.yaml +++ b/terratest/examples/roundrobin2-ref-gslb.yaml @@ -4,9 +4,10 @@ metadata: name: roundrobin-test-gslb spec: resourceRef: - ingress: - matchLabels: - app: roundrobin-test-gslb + apiVersion: networking.k8s.io/v1 + kind: Ingress + matchLabels: + app: roundrobin-test-gslb strategy: type: roundRobin # Use a round robin load balancing strategy, when deciding which downstream clusters to route clients too dnsTtlSeconds: 5 diff --git a/terratest/test/k8gb_abstract_full_roundrobin_test.go b/terratest/test/k8gb_abstract_full_roundrobin_test.go index 33a12c127f..21bb8b26e9 100644 --- a/terratest/test/k8gb_abstract_full_roundrobin_test.go +++ b/terratest/test/k8gb_abstract_full_roundrobin_test.go @@ -26,33 +26,25 @@ import ( "github.com/stretchr/testify/require" ) -func abstractTestFullRoundRobin(t *testing.T, n int, testPrefix string, gslbPath string, ingressPath string) { - if n < 2 || n > 8 { - t.Logf("Use value of n that represents the number of clusters from interval [2,8]") +func abstractTestFullRoundRobin(t *testing.T, testPrefix string, workflows []*utils.Workflow) { + if len(workflows) < 2 || len(workflows) > 8 { + t.Logf("Number of cluster must be in the interval [2,8]") t.FailNow() } - t.Logf(fmt.Sprintf("Running TestFullRoundRobin for %d clusters", n)) + t.Logf(fmt.Sprintf("Running TestFullRoundRobin for %d clusters", len(workflows))) tags := []string{"eu", "us", "cz", "af", "ru", "ap", "uk", "ca"} var instances []*utils.Instance - const host = "roundrobin-test.cloud.example.com" - // start all the test apps on all the clusters - for i := 0; i < n; i += 1 { - workflow := utils.NewWorkflow(t, fmt.Sprintf("k3d-test-gslb%d", i+1), 5053+i). - WithGslb(gslbPath, host). - WithTestApp(tags[i]) - if ingressPath != "" { - workflow = workflow.WithIngress(ingressPath) - } - + for i, workflow := range workflows { + workflow = workflow.WithTestApp(tags[i]) instance, er := workflow.Start() require.NoError(t, er) instances = append(instances, instance) defer instance.Kill() } var err error - t.Run(fmt.Sprintf("%s round-robin on %d concurrent clusters with podinfo running", testPrefix, n), func(t *testing.T) { + t.Run(fmt.Sprintf("%s round-robin on %d concurrent clusters with podinfo running", testPrefix, len(workflows)), func(t *testing.T) { for _, ins := range instances { err = ins.WaitForAppIsRunning() require.NoError(t, err) @@ -64,7 +56,7 @@ func abstractTestFullRoundRobin(t *testing.T, n int, testPrefix string, gslbPath for _, ins := range instances { workingTargets = append(workingTargets, ins.GetLocalTargets()...) } - t.Run(fmt.Sprintf("%s all %d clusters should be interconnected", testPrefix, n), func(t *testing.T) { + t.Run(fmt.Sprintf("%s all %d clusters should be interconnected", testPrefix, len(workflows)), func(t *testing.T) { allShouldExpectTheseTargets(t, instances, workingTargets) }) diff --git a/terratest/test/k8gb_failover_playground_test.go b/terratest/test/k8gb_failover_playground_test.go index 032a061de1..9694c13a19 100644 --- a/terratest/test/k8gb_failover_playground_test.go +++ b/terratest/test/k8gb_failover_playground_test.go @@ -33,50 +33,29 @@ import ( // TestFailoverPlayground is equal to k8gb failover test running on local playground. // see: https://github.com/k8gb-io/k8gb/blob/master/docs/local.md#failover func TestFailoverPlayground(t *testing.T) { - tests := []struct { - name string - gslbPath string - ingressPath string - }{ - { - name: "embedded ingress", - gslbPath: "../examples/failover-playground.yaml", - ingressPath: "", - }, - { - name: "referenced ingress", - gslbPath: "../examples/failover-playground-ref-gslb.yaml", - ingressPath: "../examples/failover-playground-ref-ingress.yaml", - }, - } - - for _, test := range tests { - abstractTestFailoverPlayground(t, test.name, test.gslbPath, test.ingressPath) + for _, ingressType := range utils.IngressTypes { + const basePath = "../examples/failover-playground" + const host = "playground-failover.cloud.example.com" + + workflowEU := utils.NewWorkflow(t, "k3d-test-gslb1", 5053) + workflowUS := utils.NewWorkflow(t, "k3d-test-gslb2", 5054) + abstractTestFailoverPlayground(t, ingressType.String(), + workflowEU.Enrich(basePath, host, ingressType), + workflowUS.Enrich(basePath, host, ingressType), + ) } } -func abstractTestFailoverPlayground(t *testing.T, testPrefix string, gslbPath string, ingressPath string) { - const host = "playground-failover.cloud.example.com" - +func abstractTestFailoverPlayground(t *testing.T, testPrefix string, workflowEU, workflowUS *utils.Workflow) { const euGeoTag = "eu" const usGeoTag = "us" - workflowEU := utils.NewWorkflow(t, "k3d-test-gslb1", 5053). - WithGslb(gslbPath, host). - WithTestApp(euGeoTag) - if ingressPath != "" { - workflowEU = workflowEU.WithIngress(ingressPath) - } + workflowEU = workflowEU.WithTestApp(euGeoTag) instanceEU, err := workflowEU.Start() require.NoError(t, err) defer instanceEU.Kill() - workflowUS := utils.NewWorkflow(t, "k3d-test-gslb2", 5054). - WithGslb(gslbPath, host). - WithTestApp(usGeoTag) - if ingressPath != "" { - workflowUS = workflowUS.WithIngress(ingressPath) - } + workflowUS = workflowUS.WithTestApp(usGeoTag) instanceUS, err := workflowUS.Start() require.NoError(t, err) defer instanceUS.Kill() diff --git a/terratest/test/k8gb_full_failover_test.go b/terratest/test/k8gb_full_failover_test.go index dd065e4055..2c7837d522 100644 --- a/terratest/test/k8gb_full_failover_test.go +++ b/terratest/test/k8gb_full_failover_test.go @@ -30,47 +30,26 @@ import ( ) func TestFullFailover(t *testing.T) { - tests := []struct { - name string - gslbPath string - ingressPath string - }{ - { - name: "embedded ingress", - gslbPath: "../examples/failover.yaml", - ingressPath: "", - }, - { - name: "referenced ingress", - gslbPath: "../examples/failover-ref-gslb.yaml", - ingressPath: "../examples/failover-ref-ingress.yaml", - }, - } - - for _, test := range tests { - abstractTestFullFailover(t, test.name, test.gslbPath, test.ingressPath) + for _, ingressType := range utils.IngressTypes { + const basePath = "../examples/failover" + const host = "terratest-failover.cloud.example.com" + + workflowEU := utils.NewWorkflow(t, "k3d-test-gslb1", 5053) + workflowUS := utils.NewWorkflow(t, "k3d-test-gslb2", 5054) + abstractTestFullFailover(t, ingressType.String(), + workflowEU.Enrich(basePath, host, ingressType), + workflowUS.Enrich(basePath, host, ingressType), + ) } } -func abstractTestFullFailover(t *testing.T, testPrefix string, gslbPath string, ingressPath string) { - const host = "terratest-failover.cloud.example.com" - - workflowEU := utils.NewWorkflow(t, "k3d-test-gslb1", 5053). - WithGslb(gslbPath, host). - WithTestApp("eu") - if ingressPath != "" { - workflowEU = workflowEU.WithIngress(ingressPath) - } +func abstractTestFullFailover(t *testing.T, testPrefix string, workflowEU, workflowUS *utils.Workflow) { + workflowEU = workflowEU.WithTestApp("eu") instanceEU, err := workflowEU.Start() require.NoError(t, err) defer instanceEU.Kill() - workflowUS := utils.NewWorkflow(t, "k3d-test-gslb2", 5054). - WithGslb(gslbPath, host). - WithTestApp("us") - if ingressPath != "" { - workflowUS = workflowUS.WithIngress(ingressPath) - } + workflowUS = workflowUS.WithTestApp("us") instanceUS, err := workflowUS.Start() require.NoError(t, err) defer instanceUS.Kill() diff --git a/terratest/test/k8gb_full_roundrobin_test.go b/terratest/test/k8gb_full_roundrobin_test.go index bbb5d60f36..78236f68f2 100644 --- a/terratest/test/k8gb_full_roundrobin_test.go +++ b/terratest/test/k8gb_full_roundrobin_test.go @@ -22,28 +22,23 @@ Generated by GoLic, for more details see: https://github.com/AbsaOSS/golic */ import ( + "fmt" + "k8gbterratest/utils" "testing" ) func TestFullRoundRobin(t *testing.T) { - tests := []struct { - name string - gslbPath string - ingressPath string - }{ - { - name: "embedded ingress", - gslbPath: "../examples/roundrobin2.yaml", - ingressPath: "", - }, - { - name: "referenced ingress", - gslbPath: "../examples/roundrobin2-ref-gslb.yaml", - ingressPath: "../examples/roundrobin2-ref-ingress.yaml", - }, - } - - for test := range tests { - abstractTestFullRoundRobin(t, settings.ClusterNumber, test.name, test.gslbPath, test.ingressPath) + for _, ingressType := range utils.IngressTypes { + const basePath = "../examples/roundrobin2" + const host = "roundrobin-test.cloud.example.com" + + workflows := []*utils.Workflow{} + for i := 0; i < settings.ClustersNumber; i += 1 { + workflow := utils.NewWorkflow(t, fmt.Sprintf("k3d-test-gslb%d", i+1), 5053+i) + workflow.Enrich(basePath, host, ingressType) + workflows = append(workflows, workflow) + } + + abstractTestFullRoundRobin(t, ingressType.String(), workflows) } } diff --git a/terratest/test/k8gb_weight_test.go b/terratest/test/k8gb_weight_test.go index 1988114d62..b881c3cc0a 100644 --- a/terratest/test/k8gb_weight_test.go +++ b/terratest/test/k8gb_weight_test.go @@ -27,50 +27,30 @@ import ( ) func TestWeightsExistsInLocalDNSEndpoint(t *testing.T) { - tests := []struct { - gslbPath string - ingressPath string - name string - }{ - { - name: "with gslb only", - gslbPath: "../examples/roundrobin-weight1.yaml", - ingressPath: "", - }, - { - name: "with ref", - gslbPath: "../examples/roundrobin-weight1-ref-gslb.yaml", - ingressPath: "../examples/roundrobin-weight1-ref-ingress.yaml", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - abstractTestWeightsExistsInLocalDNSEndpoint(t, test.gslbPath, test.ingressPath) + for _, ingressType := range utils.IngressTypes { + const basePath = "../examples/roundrobin-weight1" + const host = "terratest-roundrobin.cloud.example.com" + + workflowEU := utils.NewWorkflow(t, "k3d-test-gslb1", 5053) + workflowUS := utils.NewWorkflow(t, "k3d-test-gslb2", 5054) + t.Run(ingressType.String(), func(t *testing.T) { + abstractTestWeightsExistsInLocalDNSEndpoint(t, host, + workflowEU.Enrich(basePath, host, ingressType), + workflowUS.Enrich(basePath, host, ingressType), + ) }) } } -func abstractTestWeightsExistsInLocalDNSEndpoint(t *testing.T, gslbPath string, ingressPath string) { - const host = "terratest-roundrobin.cloud.example.com" +func abstractTestWeightsExistsInLocalDNSEndpoint(t *testing.T, host string, workflowEU, workflowUS *utils.Workflow) { const endpointDNSNameEU = "gslb-ns-eu-cloud.example.com" const endpointDNSNameUS = "gslb-ns-us-cloud.example.com" - workflowEU := utils.NewWorkflow(t, "k3d-test-gslb1", 5053). - WithGslb(gslbPath, host). - WithTestApp("eu") - if ingressPath != "" { - workflowEU.WithIngress(ingressPath) - } + workflowEU = workflowEU.WithTestApp("eu") instanceEU, err := workflowEU.Start() require.NoError(t, err) defer instanceEU.Kill() - workflowUS := utils.NewWorkflow(t, "k3d-test-gslb2", 5054). - WithGslb(gslbPath, host). - WithTestApp("us") - if ingressPath != "" { - workflowUS.WithIngress(ingressPath) - } + workflowUS = workflowUS.WithTestApp("us") instanceUS, err := workflowUS.Start() require.NoError(t, err) defer instanceUS.Kill() diff --git a/terratest/utils/extensions.go b/terratest/utils/extensions.go index b3f7d25dbb..7510963b52 100644 --- a/terratest/utils/extensions.go +++ b/terratest/utils/extensions.go @@ -44,16 +44,21 @@ import ( ) type Workflow struct { - error error - namespace string - cluster string - k8sOptions *k8s.KubectlOptions - t *testing.T - settings struct { - ingressResourcePath string - gslbResourcePath string - ingressName string - digUsingUDP bool + error error + namespace string + cluster string + k8sOptions *k8s.KubectlOptions + k8sOptionsIstioIngress *k8s.KubectlOptions + t *testing.T + settings struct { + ingressType IngressType + istioVirtualServiceResourcePath string + istioGatewayResourcePath string + ingressResourcePath string + gslbResourcePath string + ingressName string + ingressPort int + digUsingUDP bool } state struct { namespaceCreated bool @@ -104,6 +109,40 @@ type InstanceStatus struct { EndpointGlobalTargets string `json:"ep1-dns-targets"` } +type IngressType int + +const ( + IngressEmbedded IngressType = iota + IngressReferenced + IngressIstio +) + +const ( + istioIngressNamespace = "istio-ingress" + istioIngressLoadBalancerService = "istio-ingressgateway" + kubernetesIngressPort = 80 + istioIngressPort = 8080 +) + +var IngressTypes = []IngressType{ + IngressEmbedded, + IngressReferenced, + IngressIstio, +} + +func (it IngressType) String() string { + switch it { + case IngressEmbedded: + return "ingress embedded" + case IngressReferenced: + return "ingress referenced" + case IngressIstio: + return "ingress istio" + default: + return "ingress unknown" + } +} + func NewWorkflow(t *testing.T, cluster string, port int) *Workflow { var err error if cluster == "" { @@ -116,12 +155,40 @@ func NewWorkflow(t *testing.T, cluster string, port int) *Workflow { w.cluster = cluster w.namespace = fmt.Sprintf("k8gb-test-%s", strings.ToLower(random.UniqueId())) w.k8sOptions = k8s.NewKubectlOptions(cluster, "", w.namespace) + w.k8sOptionsIstioIngress = k8s.NewKubectlOptions(cluster, "", istioIngressNamespace) w.t = t w.state.gslb.port = port w.error = err return w } +// Enrich enriches the workflow with the relevant resources depending on the ingressType +func (w *Workflow) Enrich(basePath string, host string, ingressType IngressType) *Workflow { + gslbPath := "" + ingressPort := kubernetesIngressPort + + switch ingressType { + case IngressEmbedded: + gslbPath = basePath + ".yaml" + case IngressReferenced: + gslbPath = basePath + "-ref-gslb.yaml" + ingressPath := basePath + "-ref-ingress.yaml" + w = w.WithIngress(ingressPath) + case IngressIstio: + gslbPath = basePath + "-istio-gslb.yaml" + virtualServicePath := basePath + "-istio-virtualservice.yaml" + gatewayPath := basePath + "-istio-gateway.yaml" + w = w.WithIstio(virtualServicePath, gatewayPath) + ingressPort = istioIngressPort + } + + w = w.WithGslb(gslbPath, host) + w.settings.ingressType = ingressType + w.settings.ingressPort = ingressPort + + return w +} + func (w *Workflow) WithIngress(path string) *Workflow { if path == "" { w.error = fmt.Errorf("empty ingress resource path") @@ -138,6 +205,27 @@ func (w *Workflow) WithIngress(path string) *Workflow { return w } +func (w *Workflow) WithIstio(virtualServicePath, gatewayPath string) *Workflow { + if virtualServicePath == "" { + w.error = fmt.Errorf("empty istio virtual service resource path") + } + if gatewayPath == "" { + w.error = fmt.Errorf("empty istio gateway resource path") + } + + var err error + w.settings.istioVirtualServiceResourcePath, err = filepath.Abs(virtualServicePath) + if err != nil { + w.error = fmt.Errorf("reading %s; %s", virtualServicePath, err) + } + w.settings.istioGatewayResourcePath, err = filepath.Abs(gatewayPath) + if err != nil { + w.error = fmt.Errorf("reading %s; %s", gatewayPath, err) + } + + return w +} + // WithGslb // TODO: consider taking host dynamically func (w *Workflow) WithGslb(path, host string) *Workflow { @@ -179,7 +267,14 @@ func (w *Workflow) Start() (*Instance, error) { // namespace w.t.Logf("Create namespace %s", w.namespace) - k8s.CreateNamespace(w.t, w.k8sOptions, w.namespace) + istioInjection := "disabled" + if w.settings.ingressType == IngressIstio { + istioInjection = "enabled" + } + k8s.CreateNamespaceWithMetadata(w.t, w.k8sOptions, metav1.ObjectMeta{ + Name: w.namespace, + Labels: map[string]string{"istio-injection": istioInjection}, + }) w.state.namespaceCreated = true // app @@ -217,19 +312,27 @@ func (w *Workflow) Start() (*Instance, error) { // gslb if w.settings.gslbResourcePath != "" { - if w.settings.ingressResourcePath == "" { + switch w.settings.ingressType { + case IngressEmbedded: w.t.Logf("Create ingress %s from %s", w.state.gslb.name, w.settings.gslbResourcePath) k8s.KubectlApply(w.t, w.k8sOptions, w.settings.gslbResourcePath) k8s.WaitUntilIngressAvailable(w.t, w.k8sOptions, w.state.gslb.name, 100, 5*time.Second) ingress := k8s.GetIngress(w.t, w.k8sOptions, w.state.gslb.name) require.Equal(w.t, ingress.Name, w.state.gslb.name) w.settings.ingressName = w.state.gslb.name - } else { + case IngressReferenced: w.t.Logf("Create ingress %s from %s", w.settings.ingressName, w.settings.ingressResourcePath) k8s.KubectlApply(w.t, w.k8sOptions, w.settings.ingressResourcePath) k8s.WaitUntilIngressAvailable(w.t, w.k8sOptions, w.settings.ingressName, 100, 5*time.Second) w.t.Logf("Create gslb %s from %s", w.state.gslb.name, w.settings.gslbResourcePath) k8s.KubectlApply(w.t, w.k8sOptions, w.settings.gslbResourcePath) + case IngressIstio: + w.t.Logf("Create istio virtual service from %s", w.settings.istioVirtualServiceResourcePath) + k8s.KubectlApply(w.t, w.k8sOptions, w.settings.istioVirtualServiceResourcePath) + w.t.Logf("Create istio gateway from %s", w.settings.istioGatewayResourcePath) + k8s.KubectlApply(w.t, w.k8sOptionsIstioIngress, w.settings.istioGatewayResourcePath) + w.t.Logf("Create gslb %s from %s", w.state.gslb.name, w.settings.gslbResourcePath) + k8s.KubectlApply(w.t, w.k8sOptions, w.settings.gslbResourcePath) } } @@ -261,6 +364,9 @@ func (i *Instance) Kill() { if i.w.state.namespaceCreated { k8s.DeleteNamespace(i.w.t, i.w.k8sOptions, i.w.namespace) } + if i.w.settings.istioGatewayResourcePath != "" { + k8s.KubectlDelete(i.w.t, i.w.k8sOptionsIstioIngress, i.w.settings.istioGatewayResourcePath) + } } func (i *Instance) ReapplyIngress(path string) { @@ -293,9 +399,17 @@ func (i *Instance) GetCoreDNSIP() string { func (i *Instance) GetIngressIPs() []string { var ingressIPs []string - ingress := k8s.GetIngress(i.w.t, i.w.k8sOptions, i.w.settings.ingressName) - for _, ip := range ingress.Status.LoadBalancer.Ingress { - ingressIPs = append(ingressIPs, ip.IP) + switch i.w.settings.ingressType { + case IngressIstio: + lbService := k8s.GetService(i.w.t, i.w.k8sOptionsIstioIngress, istioIngressLoadBalancerService) + for _, ip := range lbService.Status.LoadBalancer.Ingress { + ingressIPs = append(ingressIPs, ip.IP) + } + default: + ingress := k8s.GetIngress(i.w.t, i.w.k8sOptions, i.w.settings.ingressName) + for _, ip := range ingress.Status.LoadBalancer.Ingress { + ingressIPs = append(ingressIPs, ip.IP) + } } return ingressIPs } @@ -487,7 +601,7 @@ func (i *Instance) HitTestApp() (result *TestAppResult) { var err error result = new(TestAppResult) coreDNSIP := i.GetCoreDNSIP() - command := []string{"sh", "-c", fmt.Sprintf("wget -qO - %s", i.w.state.gslb.host)} + command := []string{"sh", "-c", fmt.Sprintf("wget -qO - %s:%d", i.w.state.gslb.host, i.w.settings.ingressPort)} for t := 0; t < 60; t++ { result.Body, err = RunBusyBoxCommand(i.w.t, i.w.k8sOptions, coreDNSIP, command) if strings.Contains(result.Body, "503") { @@ -570,7 +684,7 @@ func waitForLocalGSLBNew(t *testing.T, host string, port int, expectedResult []s t, "Wait for failover to happen and coredns to pickup new values...", DefaultRetries, - time.Second*1, + time.Second*3, func() ([]string, error) { return dns.Dig("localhost:"+strconv.Itoa(port), host, isUdp) }, expectedResult) } diff --git a/terratest/utils/utils.go b/terratest/utils/utils.go index d5d739c277..6d072775c7 100644 --- a/terratest/utils/utils.go +++ b/terratest/utils/utils.go @@ -231,7 +231,7 @@ func WaitForLocalGSLB(t *testing.T, dnsServer string, dnsPort int, settings Test t, "Wait for failover to happen and coredns to pickup new values...", 300, - time.Second*1, + time.Second*3, func() ([]string, error) { return Dig(t, dnsServer, dnsPort, host+settings.DNSZone, additionalArgs...) }, expectedResult) } @@ -261,7 +261,7 @@ func RunBusyBoxCommand(t *testing.T, options *k8s.KubectlOptions, dns string, co dnsOverride := fmt.Sprintf("{\"spec\":{\"dnsConfig\":{\"nameservers\":[\"%s\"]},\"dnsPolicy\": \"None\"}}", dns) args := []string{} kubectlCtx := []string{"--context", options.ContextName, "-n", options.Namespace} - containerArgs := []string{"run", "-i", "--rm", "busybox", "--restart", "Never", "--image", "busybox"} + containerArgs := []string{"run", "-i", "--rm", "busybox", "--restart", "Never", "--image", "busybox", "--labels", "sidecar.istio.io/inject=false"} containerDNS := []string{"--overrides", dnsOverride} appArgs := append([]string{"--"}, command...) args = append(kubectlCtx, containerArgs...)