diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 8177fd7c6..a76573ce6 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -25,8 +25,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Setup go uses: actions/setup-go@v5 @@ -70,13 +68,40 @@ jobs: max_attempts: 3 command: make verify.generators - install-with-kustomize: + samples: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 + + - name: Setup go + uses: actions/setup-go@v5 with: - fetch-depth: 0 + go-version-file: go.mod + + - name: Create k8s KinD Cluster + uses: helm/kind-action@v1.10.0 + + - uses: jdx/mise-action@v2 + with: + install: false + + # We use install.all to install all CRDs and resources also the ones that are not bundled + # in base kustomization (e.g. currently AIGateway) but which have samples defined. + - name: Verify installing CRDs via kustomize works + run: make install.all + + - name: Install and delete each sample one by one + run: make test.samples + + - name: Verify that uninstalling operator CRDs via kustomize works + run: make uninstall.all + + install-with-kustomize: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 - name: Setup go uses: actions/setup-go@v5 @@ -122,8 +147,6 @@ jobs: steps: - name: checkout repository uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: setup golang uses: actions/setup-go@v5 @@ -198,8 +221,6 @@ jobs: steps: - name: checkout repository uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: setup golang uses: actions/setup-go@v5 @@ -251,8 +272,6 @@ jobs: steps: - name: checkout repository uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: setup golang uses: actions/setup-go@v5 @@ -400,8 +419,6 @@ jobs: - name: checkout repository uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: download tests report id: download-coverage @@ -431,6 +448,7 @@ jobs: - install-with-kustomize - build - unit-tests + - samples # - conformance-tests - integration-tests - integration-tests-bluegreen diff --git a/CHANGELOG.md b/CHANGELOG.md index e5ad8367a..894f1c2bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ ## Unreleased +### Added + +- Add `ExternalTrafficPolicy` to `DataPlane`'s `ServiceOptions` + [#241](https://github.com/Kong/gateway-operator/pull/241) + ### Breaking Changes - Changes project layout to match `kubebuilder` `v4`. Some import paths (due to dir renames) have changed diff --git a/Makefile b/Makefile index a649f710b..d34a03fde 100644 --- a/Makefile +++ b/Makefile @@ -372,6 +372,10 @@ test.conformance: KGO_RELEASE=$(TAG) GOTESTFLAGS="$(GOTESTFLAGS)" +.PHONY: test.samples +test.samples: kustomize + find ./config/samples -not -name "kustomization.*" -type f | xargs -I{} bash -c "kubectl apply -f {}; kubectl delete -f {}" + # ------------------------------------------------------------------------------ # Gateway API # ------------------------------------------------------------------------------ @@ -492,12 +496,23 @@ debug.skaffold.continuous: _ensure-kong-system-namespace install: manifests kustomize install-gateway-api-crds $(KUSTOMIZE) build config/crd | kubectl apply --server-side -f - +# Install standard and experimental CRDs into the K8s cluster specified in ~/.kube/config. +.PHONY: install.all +install.all: manifests kustomize install-gateway-api-crds + kubectl apply --server-side -f $(PROJECT_DIR)/config/crd/bases/ + # Uninstall CRDs from the K8s cluster specified in ~/.kube/config. # Call with ignore-not-found=true to ignore resource not found errors during deletion. .PHONY: uninstall uninstall: manifests kustomize uninstall-gateway-api-crds $(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - +# Uninstall standard and experimental CRDs from the K8s cluster specified in ~/.kube/config. +# Call with ignore-not-found=true to ignore resource not found errors during deletion. +.PHONY: uninstall.all +uninstall.all: manifests kustomize uninstall-gateway-api-crds + kubectl delete --ignore-not-found=$(ignore-not-found) -f $(PROJECT_DIR)/config/crd/bases/ + # Deploy controller to the K8s cluster specified in ~/.kube/config. # This will wait for operator's Deployment to get Available. # This uses a temporary directory becuase "kustomize edit set image" would introduce diff --git a/api/v1beta1/dataplane_types.go b/api/v1beta1/dataplane_types.go index 419e51ec6..f0922b6f6 100644 --- a/api/v1beta1/dataplane_types.go +++ b/api/v1beta1/dataplane_types.go @@ -172,6 +172,27 @@ type ServiceOptions struct { // // +optional Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,12,rep,name=annotations"` + + // ExternalTrafficPolicy describes how nodes distribute service traffic they + // receive on one of the Service's "externally-facing" addresses (NodePorts, + // ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure + // the service in a way that assumes that external load balancers will take care + // of balancing the service traffic between nodes, and so each node will deliver + // traffic only to the node-local endpoints of the service, without masquerading + // the client source IP. (Traffic mistakenly sent to a node with no endpoints will + // be dropped.) The default value, "Cluster", uses the standard behavior of + // routing to all endpoints evenly (possibly modified by topology and other + // features). Note that traffic sent to an External IP or LoadBalancer IP from + // within the cluster will always get "Cluster" semantics, but clients sending to + // a NodePort from within the cluster may need to take traffic policy into account + // when picking a node. + // + // More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + // + // +optional + // +kubebuilder:default=Cluster + // +kubebuilder:validation:Enum=Cluster;Local + ExternalTrafficPolicy corev1.ServiceExternalTrafficPolicy `json:"externalTrafficPolicy,omitempty"` } // DataPlaneStatus defines the observed state of DataPlane diff --git a/config/crd/bases/gateway-operator.konghq.com_dataplanes.yaml b/config/crd/bases/gateway-operator.konghq.com_dataplanes.yaml index b04b98798..06379224d 100644 --- a/config/crd/bases/gateway-operator.konghq.com_dataplanes.yaml +++ b/config/crd/bases/gateway-operator.konghq.com_dataplanes.yaml @@ -8397,6 +8397,29 @@ spec: More info: http://kubernetes.io/docs/user-guide/annotations type: object + externalTrafficPolicy: + default: Cluster + description: |- + ExternalTrafficPolicy describes how nodes distribute service traffic they + receive on one of the Service's "externally-facing" addresses (NodePorts, + ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure + the service in a way that assumes that external load balancers will take care + of balancing the service traffic between nodes, and so each node will deliver + traffic only to the node-local endpoints of the service, without masquerading + the client source IP. (Traffic mistakenly sent to a node with no endpoints will + be dropped.) The default value, "Cluster", uses the standard behavior of + routing to all endpoints evenly (possibly modified by topology and other + features). Note that traffic sent to an External IP or LoadBalancer IP from + within the cluster will always get "Cluster" semantics, but clients sending to + a NodePort from within the cluster may need to take traffic policy into account + when picking a node. + + + More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + enum: + - Cluster + - Local + type: string ports: description: |- Ports defines the list of ports that are exposed by the service. diff --git a/config/crd/bases/gateway-operator.konghq.com_gatewayconfigurations.yaml b/config/crd/bases/gateway-operator.konghq.com_gatewayconfigurations.yaml index 5ffbd9e80..a18c2fecd 100644 --- a/config/crd/bases/gateway-operator.konghq.com_gatewayconfigurations.yaml +++ b/config/crd/bases/gateway-operator.konghq.com_gatewayconfigurations.yaml @@ -16254,6 +16254,29 @@ spec: More info: http://kubernetes.io/docs/user-guide/annotations type: object + externalTrafficPolicy: + default: Cluster + description: |- + ExternalTrafficPolicy describes how nodes distribute service traffic they + receive on one of the Service's "externally-facing" addresses (NodePorts, + ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure + the service in a way that assumes that external load balancers will take care + of balancing the service traffic between nodes, and so each node will deliver + traffic only to the node-local endpoints of the service, without masquerading + the client source IP. (Traffic mistakenly sent to a node with no endpoints will + be dropped.) The default value, "Cluster", uses the standard behavior of + routing to all endpoints evenly (possibly modified by topology and other + features). Note that traffic sent to an External IP or LoadBalancer IP from + within the cluster will always get "Cluster" semantics, but clients sending to + a NodePort from within the cluster may need to take traffic policy into account + when picking a node. + + + More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + enum: + - Cluster + - Local + type: string type: default: LoadBalancer description: |- diff --git a/config/crd/dataplane/gateway-operator.konghq.com_dataplanes.yaml b/config/crd/dataplane/gateway-operator.konghq.com_dataplanes.yaml index b04b98798..06379224d 100644 --- a/config/crd/dataplane/gateway-operator.konghq.com_dataplanes.yaml +++ b/config/crd/dataplane/gateway-operator.konghq.com_dataplanes.yaml @@ -8397,6 +8397,29 @@ spec: More info: http://kubernetes.io/docs/user-guide/annotations type: object + externalTrafficPolicy: + default: Cluster + description: |- + ExternalTrafficPolicy describes how nodes distribute service traffic they + receive on one of the Service's "externally-facing" addresses (NodePorts, + ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure + the service in a way that assumes that external load balancers will take care + of balancing the service traffic between nodes, and so each node will deliver + traffic only to the node-local endpoints of the service, without masquerading + the client source IP. (Traffic mistakenly sent to a node with no endpoints will + be dropped.) The default value, "Cluster", uses the standard behavior of + routing to all endpoints evenly (possibly modified by topology and other + features). Note that traffic sent to an External IP or LoadBalancer IP from + within the cluster will always get "Cluster" semantics, but clients sending to + a NodePort from within the cluster may need to take traffic policy into account + when picking a node. + + + More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + enum: + - Cluster + - Local + type: string ports: description: |- Ports defines the list of ports that are exposed by the service. diff --git a/controller/gateway/controller_reconciler_utils.go b/controller/gateway/controller_reconciler_utils.go index 5ae5c5334..31d3a933a 100644 --- a/controller/gateway/controller_reconciler_utils.go +++ b/controller/gateway/controller_reconciler_utils.go @@ -134,8 +134,9 @@ func gatewayConfigDataPlaneOptionsToDataPlaneOptions(opts operatorv1beta1.Gatewa Services: &operatorv1beta1.DataPlaneServices{ Ingress: &operatorv1beta1.DataPlaneServiceOptions{ ServiceOptions: operatorv1beta1.ServiceOptions{ - Type: opts.Network.Services.Ingress.Type, - Annotations: opts.Network.Services.Ingress.Annotations, + Type: opts.Network.Services.Ingress.Type, + Annotations: opts.Network.Services.Ingress.Annotations, + ExternalTrafficPolicy: opts.Network.Services.Ingress.ExternalTrafficPolicy, }, }, }, diff --git a/docs/api-reference.md b/docs/api-reference.md index f5286b41e..de3cc40b5 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -754,6 +754,7 @@ DataPlaneServiceOptions contains Services related DataPlane configuration. | `ports` _[DataPlaneServicePort](#dataplaneserviceport) array_ | Ports defines the list of ports that are exposed by the service. The ports field allows defining the name, port and targetPort of the underlying service ports, while the protocol is defaulted to TCP, as it is the only protocol currently supported. | | `type` _[ServiceType](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#servicetype-v1-core)_ | Type determines how the Service is exposed. Defaults to `LoadBalancer`.

Valid options are `LoadBalancer` and `ClusterIP`.

`ClusterIP` allocates a cluster-internal IP address for load-balancing to endpoints.

`LoadBalancer` builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP.

More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types | | `annotations` _object (keys:string, values:string)_ | Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.

More info: http://kubernetes.io/docs/user-guide/annotations | +| `externalTrafficPolicy` _[ServiceExternalTrafficPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#serviceexternaltrafficpolicy-v1-core)_ | ExternalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's "externally-facing" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get "Cluster" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node.

More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip | _Appears in:_ @@ -908,6 +909,7 @@ such as the annotations. | --- | --- | | `type` _[ServiceType](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#servicetype-v1-core)_ | Type determines how the Service is exposed. Defaults to `LoadBalancer`.

Valid options are `LoadBalancer` and `ClusterIP`.

`ClusterIP` allocates a cluster-internal IP address for load-balancing to endpoints.

`LoadBalancer` builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP.

More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types | | `annotations` _object (keys:string, values:string)_ | Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.

More info: http://kubernetes.io/docs/user-guide/annotations | +| `externalTrafficPolicy` _[ServiceExternalTrafficPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#serviceexternaltrafficpolicy-v1-core)_ | ExternalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's "externally-facing" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get "Cluster" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node.

More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip | _Appears in:_ @@ -1158,6 +1160,7 @@ such as the annotations. | --- | --- | | `type` _[ServiceType](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#servicetype-v1-core)_ | Type determines how the Service is exposed. Defaults to `LoadBalancer`.

Valid options are `LoadBalancer` and `ClusterIP`.

`ClusterIP` allocates a cluster-internal IP address for load-balancing to endpoints.

`LoadBalancer` builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP.

More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types | | `annotations` _object (keys:string, values:string)_ | Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.

More info: http://kubernetes.io/docs/user-guide/annotations | +| `externalTrafficPolicy` _[ServiceExternalTrafficPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#serviceexternaltrafficpolicy-v1-core)_ | ExternalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's "externally-facing" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to "Local", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, "Cluster", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get "Cluster" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node.

More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip | _Appears in:_ diff --git a/pkg/utils/kubernetes/resources/services.go b/pkg/utils/kubernetes/resources/services.go index b8ffecc38..71064b5fe 100644 --- a/pkg/utils/kubernetes/resources/services.go +++ b/pkg/utils/kubernetes/resources/services.go @@ -57,9 +57,12 @@ func GenerateNewIngressServiceForDataPlane(dataplane *operatorv1beta1.DataPlane, }, }, Spec: corev1.ServiceSpec{ - Type: getDataPlaneIngressServiceType(dataplane), - Selector: map[string]string{"app": dataplane.Name}, - Ports: DefaultDataPlaneIngressServicePorts, + Type: getDataPlaneIngressServiceType(dataplane), + Selector: map[string]string{ + "app": dataplane.Name, + }, + Ports: DefaultDataPlaneIngressServicePorts, + ExternalTrafficPolicy: getDataPlaneIngressServiceExternalTrafficPolicy(dataplane), }, } LabelObjectAsDataPlaneManaged(svc) @@ -109,6 +112,14 @@ func getDataPlaneIngressServiceType(dataplane *operatorv1beta1.DataPlane) corev1 return dataplane.Spec.Network.Services.Ingress.Type } +func getDataPlaneIngressServiceExternalTrafficPolicy(dataplane *operatorv1beta1.DataPlane) corev1.ServiceExternalTrafficPolicy { + if dataplane == nil || dataplane.Spec.Network.Services == nil { + return corev1.ServiceExternalTrafficPolicyCluster + } + + return dataplane.Spec.Network.Services.Ingress.ExternalTrafficPolicy +} + // ServiceOpt is an option function for a Service. type ServiceOpt func(*corev1.Service) diff --git a/pkg/utils/kubernetes/resources/services_test.go b/pkg/utils/kubernetes/resources/services_test.go index 2f7726ce1..7e45312f7 100644 --- a/pkg/utils/kubernetes/resources/services_test.go +++ b/pkg/utils/kubernetes/resources/services_test.go @@ -3,7 +3,14 @@ package resources import ( "testing" + "github.com/samber/lo" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + + operatorv1beta1 "github.com/kong/gateway-operator/api/v1beta1" ) func TestGetSelectorOverrides(t *testing.T) { @@ -69,3 +76,156 @@ func TestGetSelectorOverrides(t *testing.T) { }) } } + +func TestGenerateNewIngressServiceForDataPlane(t *testing.T) { + testCases := []struct { + name string + dataplane *operatorv1beta1.DataPlane + expectedSvc *corev1.Service + expectedErr error + }{ + { + name: "base", + dataplane: &operatorv1beta1.DataPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dp-1", + Namespace: "default", + UID: types.UID("1234"), + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: "gateway.konghq.com/v1beta1", + Kind: "DataPlane", + }, + }, + expectedSvc: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "dataplane-ingress-dp-1-", + Namespace: "default", + Labels: map[string]string{ + "app": "dp-1", + "gateway-operator.konghq.com/dataplane-service-type": "ingress", + "gateway-operator.konghq.com/managed-by": "dataplane", + "konghq.com/gateway-operator": "dataplane", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "gateway.konghq.com/v1beta1", + Kind: "DataPlane", + Name: "dp-1", + UID: "1234", + Controller: lo.ToPtr(true), + }, + }, + Finalizers: []string{ + "gateway-operator.konghq.com/wait-for-owner", + }, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + Ports: []corev1.ServicePort{ + { + Name: "http", + Protocol: corev1.ProtocolTCP, + Port: 80, + TargetPort: intstr.FromInt(8000), + }, + { + Name: "https", + Protocol: corev1.ProtocolTCP, + Port: 443, + TargetPort: intstr.FromInt(8443), + }, + }, + Selector: map[string]string{ + "app": "dp-1", + }, + ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeCluster, + }, + }, + expectedErr: nil, + }, + { + name: "setting ExternalTrafficPolicy to Local", + dataplane: &operatorv1beta1.DataPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dp-1", + Namespace: "default", + UID: types.UID("1234"), + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: "gateway.konghq.com/v1beta1", + Kind: "DataPlane", + }, + Spec: operatorv1beta1.DataPlaneSpec{ + DataPlaneOptions: operatorv1beta1.DataPlaneOptions{ + Network: operatorv1beta1.DataPlaneNetworkOptions{ + Services: &operatorv1beta1.DataPlaneServices{ + Ingress: &operatorv1beta1.DataPlaneServiceOptions{ + ServiceOptions: operatorv1beta1.ServiceOptions{ + ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal, + Type: corev1.ServiceTypeLoadBalancer, + }, + }, + }, + }, + }, + }, + }, + expectedSvc: &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "dataplane-ingress-dp-1-", + Namespace: "default", + Labels: map[string]string{ + "app": "dp-1", + "gateway-operator.konghq.com/dataplane-service-type": "ingress", + "gateway-operator.konghq.com/managed-by": "dataplane", + "konghq.com/gateway-operator": "dataplane", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "gateway.konghq.com/v1beta1", + Kind: "DataPlane", + Name: "dp-1", + UID: "1234", + Controller: lo.ToPtr(true), + }, + }, + Finalizers: []string{ + "gateway-operator.konghq.com/wait-for-owner", + }, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + Ports: []corev1.ServicePort{ + { + Name: "http", + Protocol: corev1.ProtocolTCP, + Port: 80, + TargetPort: intstr.FromInt(8000), + }, + { + Name: "https", + Protocol: corev1.ProtocolTCP, + Port: 443, + TargetPort: intstr.FromInt(8443), + }, + }, + Selector: map[string]string{ + "app": "dp-1", + }, + ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyTypeLocal, + }, + }, + expectedErr: nil, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + svc, err := GenerateNewIngressServiceForDataPlane(tc.dataplane) + require.Equal(t, tc.expectedErr, err) + require.Equal(t, tc.expectedSvc, svc) + }) + } +}