Repository: kubernetes/ingress-nginx
Pull request #7311 (2021-07-01 16:05:31)

Handle named (non-numeric) ports correctly
## What this PR does / why we need it:
Handle named (non-numeric) ports correctly

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Which issue/s this PR fixes
Fixes: https://github.com/kubernetes/ingress-nginx/issues/7280

/assign @rikatz 

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] My change requires a change to the documentation.
- [x] I have updated the documentation accordingly.
- [x] I've read the [CONTRIBUTION](https://github.com/kubernetes/ingress-nginx/blob/master/CONTRIBUTING.md) guide
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/ingress-nginx/pull/7311#" title="Author self-approved">cpanato</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **bowei** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @bowei` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fingress-nginx).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/ingress-nginx/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["bowei"]} -->
rikatz: /cc
On my queue :D

Patch:
diff --git a/RELEASE.md b/RELEASE.md
index 69ed20244..c752b2a34 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -74,5 +74,7 @@ The sha is available in output from [cloud build](https://console.cloud.google.c
     * Update the version in [docs/deploy/index.md](docs/deploy/index.md)
     * Update Supported versions in the Support Versions table in the README.md 
     * Merge
+
+* Update the stable.txt file to reflect the release to be created
       
-7. Github release
\ No newline at end of file
+7. Github release
diff --git a/cmd/nginx/flags.go b/cmd/nginx/flags.go
index 5fb63b430..62c4ced23 100644
--- a/cmd/nginx/flags.go
+++ b/cmd/nginx/flags.go
@@ -126,6 +126,9 @@ Requires the update-status parameter.`)
 		enableSSLPassthrough = flags.Bool("enable-ssl-passthrough", false,
 			`Enable SSL Passthrough.`)
 
+		disableServiceExternalName = flags.Bool("disable-svc-external-name", false,
+			`Disable support for Services of type ExternalName`)
+
 		annotationsPrefix = flags.String("annotations-prefix", parser.DefaultAnnotationsPrefix,
 			`Prefix of the Ingress annotations specific to the NGINX controller.`)
 
@@ -264,28 +267,29 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
 	ngx_config.EnableSSLChainCompletion = *enableSSLChainCompletion
 
 	config := &controller.Configuration{
-		APIServerHost:          *apiserverHost,
-		KubeConfigFile:         *kubeConfigFile,
-		UpdateStatus:           *updateStatus,
-		ElectionID:             *electionID,
-		EnableProfiling:        *profiling,
-		EnableMetrics:          *enableMetrics,
-		MetricsPerHost:         *metricsPerHost,
-		MonitorMaxBatchSize:    *monitorMaxBatchSize,
-		EnableSSLPassthrough:   *enableSSLPassthrough,
-		ResyncPeriod:           *resyncPeriod,
-		DefaultService:         *defaultSvc,
-		Namespace:              *watchNamespace,
-		ConfigMapName:          *configMap,
-		TCPConfigMapName:       *tcpConfigMapName,
-		UDPConfigMapName:       *udpConfigMapName,
-		DefaultSSLCertificate:  *defSSLCertificate,
-		PublishService:         *publishSvc,
-		PublishStatusAddress:   *publishStatusAddress,
-		UpdateStatusOnShutdown: *updateStatusOnShutdown,
-		ShutdownGracePeriod:    *shutdownGracePeriod,
-		UseNodeInternalIP:      *useNodeInternalIP,
-		SyncRateLimit:          *syncRateLimit,
+		APIServerHost:              *apiserverHost,
+		KubeConfigFile:             *kubeConfigFile,
+		UpdateStatus:               *updateStatus,
+		ElectionID:                 *electionID,
+		EnableProfiling:            *profiling,
+		EnableMetrics:              *enableMetrics,
+		MetricsPerHost:             *metricsPerHost,
+		MonitorMaxBatchSize:        *monitorMaxBatchSize,
+		DisableServiceExternalName: *disableServiceExternalName,
+		EnableSSLPassthrough:       *enableSSLPassthrough,
+		ResyncPeriod:               *resyncPeriod,
+		DefaultService:             *defaultSvc,
+		Namespace:                  *watchNamespace,
+		ConfigMapName:              *configMap,
+		TCPConfigMapName:           *tcpConfigMapName,
+		UDPConfigMapName:           *udpConfigMapName,
+		DefaultSSLCertificate:      *defSSLCertificate,
+		PublishService:             *publishSvc,
+		PublishStatusAddress:       *publishStatusAddress,
+		UpdateStatusOnShutdown:     *updateStatusOnShutdown,
+		ShutdownGracePeriod:        *shutdownGracePeriod,
+		UseNodeInternalIP:          *useNodeInternalIP,
+		SyncRateLimit:              *syncRateLimit,
 		ListenPorts: &ngx_config.ListenPorts{
 			Default:  *defServerPort,
 			Health:   *healthzPort,
diff --git a/cmd/plugin/commands/ingresses/ingresses.go b/cmd/plugin/commands/ingresses/ingresses.go
index 422705320..dff967103 100644
--- a/cmd/plugin/commands/ingresses/ingresses.go
+++ b/cmd/plugin/commands/ingresses/ingresses.go
@@ -227,7 +227,7 @@ func serviceToNameAndPort(svc *networking.IngressServiceBackend) (string, intstr
 			return svcName, intstr.FromInt(int(svc.Port.Number))
 		}
 		if svc.Port.Name != "" {
-			return svcName, intstr.FromString(svc.Port.String())
+			return svcName, intstr.FromString(svc.Port.Name)
 		}
 	}
 	return "", intstr.IntOrString{}
diff --git a/go.mod b/go.mod
index e76917964..281ef9425 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/mitchellh/mapstructure v1.3.2
 	github.com/moul/pb v0.0.0-20180404114147-54bdd96e6a52
 	github.com/ncabatoff/process-exporter v0.7.2
-	github.com/onsi/ginkgo v1.14.1
+	github.com/onsi/ginkgo v1.16.4
 	github.com/opencontainers/runc v1.0.0-rc92
 	github.com/pkg/errors v0.9.1
 	github.com/pmezard/go-difflib v1.0.0
diff --git a/go.sum b/go.sum
index ea4453c18..4d5011a98 100644
--- a/go.sum
+++ b/go.sum
@@ -240,6 +240,8 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
 github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
 github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -484,6 +486,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@@ -496,6 +500,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
 github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -842,6 +848,7 @@ golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -909,6 +916,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
 golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go
index 1d67713f7..b19973231 100644
--- a/internal/ingress/controller/controller.go
+++ b/internal/ingress/controller/controller.go
@@ -85,6 +85,8 @@ type Configuration struct {
 
 	ListenPorts *ngx_config.ListenPorts
 
+	DisableServiceExternalName bool
+
 	EnableSSLPassthrough bool
 
 	EnableProfiling bool
@@ -968,6 +970,10 @@ func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingres
 
 	// Ingress with an ExternalName Service and no port defined for that Service
 	if svc.Spec.Type == apiv1.ServiceTypeExternalName {
+		if n.cfg.DisableServiceExternalName {
+			klog.Warningf("Service %q of type ExternalName not allowed due to Ingress configuration.", svcKey)
+			return upstreams, nil
+		}
 		servicePort := externalNamePorts(backendPort, svc)
 		endps := getEndpoints(svc, servicePort, apiv1.ProtocolTCP, n.store.GetServiceEndpoints)
 		if len(endps) == 0 {
diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go
index 3d46262b4..5388b6f78 100644
--- a/internal/ingress/controller/template/template.go
+++ b/internal/ingress/controller/template/template.go
@@ -988,6 +988,8 @@ func getIngressInformation(i, h, p interface{}) *ingressInformation {
 		info.Service = ing.Spec.DefaultBackend.Service.Name
 		if ing.Spec.DefaultBackend.Service.Port.Number > 0 {
 			info.ServicePort = strconv.Itoa(int(ing.Spec.DefaultBackend.Service.Port.Number))
+		} else {
+			info.ServicePort = ing.Spec.DefaultBackend.Service.Port.Name
 		}
 	}
 
@@ -1022,6 +1024,8 @@ func getIngressInformation(i, h, p interface{}) *ingressInformation {
 			info.Service = rPath.Backend.Service.Name
 			if rPath.Backend.Service.Port.Number > 0 {
 				info.ServicePort = strconv.Itoa(int(rPath.Backend.Service.Port.Number))
+			} else {
+				info.ServicePort = rPath.Backend.Service.Port.Name
 			}
 
 			return info
diff --git a/stable.txt b/stable.txt
new file mode 100644
index 000000000..9e8783a76
--- /dev/null
+++ b/stable.txt
@@ -0,0 +1,1 @@
+controller-v0.47.0


Test patch:
diff --git a/cmd/plugin/commands/ingresses/ingresses_test.go b/cmd/plugin/commands/ingresses/ingresses_test.go
new file mode 100644
index 000000000..6a8d8837f
--- /dev/null
+++ b/cmd/plugin/commands/ingresses/ingresses_test.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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.
+*/
+
+package ingresses
+
+import (
+	"testing"
+
+	networking "k8s.io/api/networking/v1"
+	"k8s.io/apimachinery/pkg/util/intstr"
+)
+
+func TestGetIngressInformation(t *testing.T) {
+
+	testcases := map[string]struct {
+		ServiceBackend *networking.IngressServiceBackend
+		wantName       string
+		wantPort       intstr.IntOrString
+	}{
+		"empty ingressServiceBackend": {
+			ServiceBackend: &networking.IngressServiceBackend{},
+			wantName:       "",
+			wantPort:       intstr.IntOrString{},
+		},
+		"ingressServiceBackend with port 8080": {
+			ServiceBackend: &networking.IngressServiceBackend{
+				Name: "test",
+				Port: networking.ServiceBackendPort{
+					Number: 8080,
+				},
+			},
+			wantName: "test",
+			wantPort: intstr.IntOrString{
+				Type:   intstr.Int,
+				IntVal: 8080,
+			},
+		},
+		"ingressServiceBackend with port name a-svc": {
+			ServiceBackend: &networking.IngressServiceBackend{
+				Name: "test",
+				Port: networking.ServiceBackendPort{
+					Name: "a-svc",
+				},
+			},
+			wantName: "test",
+			wantPort: intstr.IntOrString{
+				Type:   intstr.String,
+				StrVal: "a-svc",
+			},
+		},
+	}
+
+	for title, testCase := range testcases {
+		gotName, gotPort := serviceToNameAndPort(testCase.ServiceBackend)
+		if gotName != testCase.wantName {
+			t.Fatalf("%s: expected '%v' but returned %v", title, testCase.wantName, gotName)
+		}
+		if gotPort != testCase.wantPort {
+			t.Fatalf("%s: expected '%v' but returned %v", title, testCase.wantPort, gotPort)
+		}
+	}
+}
diff --git a/internal/ingress/controller/template/template_test.go b/internal/ingress/controller/template/template_test.go
index 2c6b62ea4..2d6ef8ae8 100644
--- a/internal/ingress/controller/template/template_test.go
+++ b/internal/ingress/controller/template/template_test.go
@@ -940,6 +940,76 @@ func TestGetIngressInformation(t *testing.T) {
 			10,
 			&ingressInformation{},
 		},
+		"valid ingress definition with name validIng in namespace default  using a service with name a-svc port number 8080": {
+			&ingress.Ingress{
+				Ingress: networking.Ingress{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "validIng",
+						Namespace: apiv1.NamespaceDefault,
+						Annotations: map[string]string{
+							"ingress.annotation": "ok",
+						},
+					},
+					Spec: networking.IngressSpec{
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "a-svc",
+								Port: networking.ServiceBackendPort{
+									Number: 8080,
+								},
+							},
+						},
+					},
+				},
+			},
+			"host1",
+			"",
+			&ingressInformation{
+				Namespace: "default",
+				Rule:      "validIng",
+				Path:      "/",
+				Annotations: map[string]string{
+					"ingress.annotation": "ok",
+				},
+				Service:     "a-svc",
+				ServicePort: "8080",
+			},
+		},
+		"valid ingress definition with name validIng in namespace default  using a service with name a-svc port name b-svc": {
+			&ingress.Ingress{
+				Ingress: networking.Ingress{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "validIng",
+						Namespace: apiv1.NamespaceDefault,
+						Annotations: map[string]string{
+							"ingress.annotation": "ok",
+						},
+					},
+					Spec: networking.IngressSpec{
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "a-svc",
+								Port: networking.ServiceBackendPort{
+									Name: "b-svc",
+								},
+							},
+						},
+					},
+				},
+			},
+			"host1",
+			"",
+			&ingressInformation{
+				Namespace: "default",
+				Rule:      "validIng",
+				Path:      "/",
+				Annotations: map[string]string{
+					"ingress.annotation": "ok",
+				},
+				Service:     "a-svc",
+				ServicePort: "b-svc",
+			},
+		},
 		"valid ingress definition with name validIng in namespace default": {
 			&ingress.Ingress{
 				Ingress: networking.Ingress{
@@ -1021,6 +1091,56 @@ func TestGetIngressInformation(t *testing.T) {
 				ServicePort: "80",
 			},
 		},
+		"valid ingress definition with name demo in namespace something and path /ok using a service with name b-svc port name b-svc-80": {
+			&ingress.Ingress{
+				Ingress: networking.Ingress{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "demo",
+						Namespace: "something",
+						Annotations: map[string]string{
+							"ingress.annotation": "ok",
+						},
+					},
+					Spec: networking.IngressSpec{
+						Rules: []networking.IngressRule{
+							{
+								Host: "foo.bar",
+								IngressRuleValue: networking.IngressRuleValue{
+									HTTP: &networking.HTTPIngressRuleValue{
+										Paths: []networking.HTTPIngressPath{
+											{
+												Path:     "/ok",
+												PathType: &pathPrefix,
+												Backend: networking.IngressBackend{
+													Service: &networking.IngressServiceBackend{
+														Name: "b-svc",
+														Port: networking.ServiceBackendPort{
+															Name: "b-svc-80",
+														},
+													},
+												},
+											},
+										},
+									},
+								},
+							},
+							{},
+						},
+					},
+				},
+			},
+			"foo.bar",
+			"/ok",
+			&ingressInformation{
+				Namespace: "something",
+				Rule:      "demo",
+				Annotations: map[string]string{
+					"ingress.annotation": "ok",
+				},
+				Service:     "b-svc",
+				ServicePort: "b-svc-80",
+			},
+		},
 	}
 
 	for title, testCase := range testcases {
diff --git a/test/e2e/settings/disable_service_external_name.go b/test/e2e/settings/disable_service_external_name.go
new file mode 100644
index 000000000..910a906ca
--- /dev/null
+++ b/test/e2e/settings/disable_service_external_name.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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.
+*/
+
+package settings
+
+import (
+	"context"
+	"net/http"
+	"strings"
+
+	"github.com/gavv/httpexpect/v2"
+	"github.com/onsi/ginkgo"
+	"github.com/stretchr/testify/assert"
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"k8s.io/ingress-nginx/test/e2e/framework"
+)
+
+var _ = framework.IngressNginxDescribe("[Flag] disable-service-external-name", func() {
+	f := framework.NewDefaultFramework("disabled-service-external-name")
+
+	ginkgo.BeforeEach(func() {
+		f.NewEchoDeploymentWithReplicas(2)
+
+		err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
+			args := deployment.Spec.Template.Spec.Containers[0].Args
+			args = append(args, "--disable-svc-external-name=true")
+			deployment.Spec.Template.Spec.Containers[0].Args = args
+			_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
+
+			return err
+		})
+		assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
+	})
+
+	ginkgo.It("should ignore services of external-name type", func() {
+
+		nonexternalhost := "echo-svc.com"
+
+		externalhost := "echo-external-svc.com"
+		svcexternal := &corev1.Service{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "external",
+				Namespace: f.Namespace,
+			},
+			Spec: corev1.ServiceSpec{
+				ExternalName: "httpbin.org",
+				Type:         corev1.ServiceTypeExternalName,
+			},
+		}
+		f.EnsureService(svcexternal)
+
+		ingexternal := framework.NewSingleIngress(externalhost, "/", externalhost, f.Namespace, "external", 80, nil)
+		f.EnsureIngress(ingexternal)
+
+		ing := framework.NewSingleIngress(nonexternalhost, "/", nonexternalhost, f.Namespace, framework.EchoService, 80, nil)
+		f.EnsureIngress(ing)
+
+		f.WaitForNginxServer(nonexternalhost, func(cfg string) bool {
+			return strings.Contains(cfg, "server_name echo-svc.com")
+		})
+
+		f.WaitForNginxServer(externalhost, func(cfg string) bool {
+			return strings.Contains(cfg, "server_name echo-external-svc.com")
+		})
+
+		f.HTTPTestClient().
+			GET("/").
+			WithHeader("Host", nonexternalhost).
+			Expect().
+			Status(http.StatusOK)
+
+		f.HTTPTestClient().
+			GET("/").
+			WithHeader("Host", externalhost).
+			Expect().
+			StatusRange(httpexpect.Status5xx)
+
+	})
+})