Merge branch 'main' of github.com:nickorlow/ingress-nginx

This commit is contained in:
Nicholas Orlowsky 2023-07-16 23:53:52 -04:00
commit 3a64d7402c
No known key found for this signature in database
GPG key ID: 58832FD3AC16C706
248 changed files with 5133 additions and 3219 deletions

View file

@ -413,7 +413,7 @@
"secured": false
},
"externalAuth": {
"url": "https://httpbin.org/basic-auth/user/passwd",
"url": "https://httpbun.com/basic-auth/user/passwd",
"method": "",
"sendBody": false
},
@ -59354,7 +59354,7 @@
"secured": false
},
"externalAuth": {
"url": "https://httpbin.org/basic-auth/user/passwd",
"url": "https://httpbun.com/basic-auth/user/passwd",
"method": "",
"sendBody": false
},
@ -60272,4 +60272,4 @@
"failTimeout": 0
}]
}]
}
}

View file

@ -1,9 +1,10 @@
ARG E2E_BASE_IMAGE
FROM ${E2E_BASE_IMAGE} AS BASE
FROM alpine:3.17.2
FROM alpine:3.18.0
RUN apk add -U --no-cache \
RUN apk update \
&& apk upgrade && apk add -U --no-cache \
ca-certificates \
bash \
curl \

View file

@ -1,6 +1,6 @@
DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
E2E_BASE_IMAGE="registry.k8s.io/ingress-nginx/e2e-test-runner:v20230314-helm-chart-4.5.2-32-g520384b11@sha256:754c62f9a5efd1ee515ee908ecc16c0c4d1dda96a8cc8019667182a55f3a9035"
E2E_BASE_IMAGE ?= "registry.k8s.io/ingress-nginx/e2e-test-runner:v20230623-d50c7193b@sha256:e5c68dc56934c273850bfb75c0348a2819756669baf59fcdce9e16771537b247"
image:
echo "..entered Makefile in /test/e2e-image"

1
test/e2e/HTTPBUN_IMAGE Normal file
View file

@ -0,0 +1 @@
registry.k8s.io/ingress-nginx/e2e-test-httpbun:v20230505-v0.0.1

View file

@ -30,6 +30,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/test/e2e/framework"
networking "k8s.io/api/networking/v1"
)
var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller", func() {
@ -161,6 +163,41 @@ var _ = framework.IngressNginxDescribeSerial("[Admission] admission controller",
assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid annotation value should return an error")
})
ginkgo.It("should return an error if there is an invalid path and wrong pathType is set", func() {
host := "path-validation"
var (
exactPathType = networking.PathTypeExact
prefixPathType = networking.PathTypePrefix
implSpecific = networking.PathTypeImplementationSpecific
)
f.UpdateNginxConfigMapData("strict-validate-path-type", "true")
invalidPath := framework.NewSingleIngress("first-ingress", "/foo/bar/[a-z]{3}", host, f.Namespace, framework.EchoService, 80, nil)
invalidPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &exactPathType
_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), invalidPath, metav1.CreateOptions{})
assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid path value should return an error")
invalidPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &prefixPathType
_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), invalidPath, metav1.CreateOptions{})
assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid path value should return an error")
annotations := map[string]string{
"nginx.ingress.kubernetes.io/use-regex": "true",
"nginx.ingress.kubernetes.io/rewrite-target": "/new/backend",
}
pathSpecific := framework.NewSingleIngress("pathspec-ingress", "/foo/bar/[a-z]{3}", host, f.Namespace, framework.EchoService, 80, annotations)
pathSpecific.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &implSpecific
_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), pathSpecific, metav1.CreateOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress with arbitrary path and implSpecific value should not return an error")
validPath := framework.NewSingleIngress("second-ingress", "/bloblo", host, f.Namespace, framework.EchoService, 80, nil)
_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), validPath, metav1.CreateOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress with valid path should not return an error")
})
ginkgo.It("should not return an error if the Ingress V1 definition is valid with Ingress Class", func() {
out, err := createIngress(f.Namespace, validV1Ingress)
assert.Equal(ginkgo.GinkgoT(), "ingress.networking.k8s.io/extensions created\n", out)

View file

@ -125,7 +125,7 @@ var _ = framework.DescribeAnnotation("affinitymode", func() {
framework.Sleep()
// validate, there is no backend to serve the request
response = request.WithCookies(cookies).Expect().Status(http.StatusServiceUnavailable)
request.WithCookies(cookies).Expect().Status(http.StatusServiceUnavailable)
// create brand new backends
replicas = 2

View file

@ -19,12 +19,12 @@ package annotations
import (
"context"
"fmt"
"golang.org/x/crypto/bcrypt"
"net/http"
"net/url"
"regexp"
"strings"
"time"
"golang.org/x/crypto/bcrypt"
"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/assert"
@ -37,7 +37,7 @@ import (
)
var _ = framework.DescribeAnnotation("auth-*", func() {
f := framework.NewDefaultFramework("auth")
f := framework.NewDefaultFramework("auth", framework.WithHTTPBunEnabled())
ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
@ -389,10 +389,10 @@ http {
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets), 1, "expected at least one endpoint")
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets[0].Addresses), 1, "expected at least one address ready in the endpoint")
httpbinIP := e.Subsets[0].Addresses[0].IP
nginxIP := e.Subsets[0].Addresses[0].IP
annotations = map[string]string{
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/cookies/set/alma/armud", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/cookies/set/alma/armud", nginxIP),
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
}
@ -456,21 +456,8 @@ http {
var ing *networking.Ingress
ginkgo.BeforeEach(func() {
f.NewHttpbinDeployment()
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
assert.Nil(ginkgo.GinkgoT(), err)
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err)
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets), 1, "expected at least one endpoint")
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets[0].Addresses), 1, "expected at least one address ready in the endpoint")
httpbinIP := e.Subsets[0].Addresses[0].IP
annotations = map[string]string{
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", f.HTTPBunIP),
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
}
@ -649,20 +636,8 @@ http {
var ing *networking.Ingress
ginkgo.BeforeEach(func() {
f.NewHttpbinDeployment()
var httpbinIP string
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
assert.Nil(ginkgo.GinkgoT(), err)
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err)
httpbinIP = e.Subsets[0].Addresses[0].IP
annotations = map[string]string{
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", f.HTTPBunIP),
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
"nginx.ingress.kubernetes.io/auth-signin-redirect-param": "orig",
}
@ -728,23 +703,8 @@ http {
barPath := "/bar"
ginkgo.BeforeEach(func() {
f.NewHttpbinDeployment()
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
assert.Nil(ginkgo.GinkgoT(), err)
framework.Sleep(1 * time.Second)
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err)
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets), 1, "expected at least one endpoint")
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets[0].Addresses), 1, "expected at least one address ready in the endpoint")
httpbinIP := e.Subsets[0].Addresses[0].IP
annotations := map[string]string{
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", f.HTTPBunIP),
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
"nginx.ingress.kubernetes.io/auth-cache-key": "fixed",
"nginx.ingress.kubernetes.io/auth-cache-duration": "200 201 401 30m",
@ -777,7 +737,7 @@ http {
Expect().
Status(http.StatusOK)
err := f.DeleteDeployment(framework.HTTPBinService)
err := f.DeleteDeployment(framework.HTTPBunService)
assert.Nil(ginkgo.GinkgoT(), err)
framework.Sleep()
@ -797,7 +757,7 @@ http {
Expect().
Status(http.StatusOK)
err := f.DeleteDeployment(framework.HTTPBinService)
err := f.DeleteDeployment(framework.HTTPBunService)
assert.Nil(ginkgo.GinkgoT(), err)
framework.Sleep()
@ -826,7 +786,7 @@ http {
Expect().
Status(http.StatusOK)
err := f.DeleteDeployment(framework.HTTPBinService)
err := f.DeleteDeployment(framework.HTTPBunService)
assert.Nil(ginkgo.GinkgoT(), err)
framework.Sleep()

View file

@ -105,19 +105,4 @@ var _ = framework.DescribeAnnotation("backend-protocol", func() {
return strings.Contains(server, "fastcgi_pass upstream_balancer;")
})
})
ginkgo.It("should set backend protocol to '' and use ajp_pass", func() {
host := "backendprotocol.foo.com"
annotations := map[string]string{
"nginx.ingress.kubernetes.io/backend-protocol": "AJP",
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
func(server string) bool {
return strings.Contains(server, "ajp_pass upstream_balancer;")
})
})
})

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,6 @@ limitations under the License.
package annotations
import (
"fmt"
"net/http"
"strings"
@ -52,6 +51,6 @@ var _ = framework.DescribeAnnotation("connection-proxy-header", func() {
WithHeader("Host", host).
Expect().
Status(http.StatusOK).
Body().Contains(fmt.Sprintf("connection=keep-alive"))
Body().Contains("connection=keep-alive")
})
})

View file

@ -29,7 +29,6 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
core "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
@ -38,7 +37,7 @@ import (
)
var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() {
f := framework.NewDefaultFramework("grpc")
f := framework.NewDefaultFramework("grpc", framework.WithHTTPBunEnabled())
ginkgo.It("should use grpc_pass in the configuration file", func() {
f.NewGRPCFortuneTellerDeployment()
@ -70,7 +69,7 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() {
host := "echo"
svc := &core.Service{
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "grpcbin-test",
Namespace: f.Namespace,
@ -121,15 +120,14 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() {
metadata := res.GetMetadata()
assert.Equal(ginkgo.GinkgoT(), metadata["content-type"].Values[0], "application/grpc")
assert.Equal(ginkgo.GinkgoT(), metadata[":authority"].Values[0], host)
})
ginkgo.It("authorization metadata should be overwritten by external auth response headers", func() {
f.NewGRPCBinDeployment()
f.NewHttpbinDeployment()
host := "echo"
svc := &core.Service{
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "grpcbin-test",
Namespace: f.Namespace,
@ -149,19 +147,8 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() {
}
f.EnsureService(svc)
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
assert.Nil(ginkgo.GinkgoT(), err)
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err)
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets), 1, "expected at least one endpoint")
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets[0].Addresses), 1, "expected at least one address ready in the endpoint")
httpbinIP := e.Subsets[0].Addresses[0].IP
annotations := map[string]string{
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/response-headers?authorization=foo", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/response-headers?authorization=foo", f.HTTPBunIP),
"nginx.ingress.kubernetes.io/auth-response-headers": "Authorization",
"nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
}
@ -201,7 +188,7 @@ var _ = framework.DescribeAnnotation("backend-protocol - GRPC", func() {
host := "echo"
svc := &core.Service{
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "grpcbin-test",
Namespace: f.Namespace,

View file

@ -1,186 +0,0 @@
/*
Copyright 2018 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 annotations
import (
"bytes"
"context"
"fmt"
"net/http"
"os/exec"
"strings"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/ingress-nginx/test/e2e/framework"
)
var _ = framework.DescribeAnnotation("influxdb-*", func() {
f := framework.NewDefaultFramework("influxdb")
ginkgo.BeforeEach(func() {
f.NewInfluxDBDeployment()
f.NewEchoDeployment()
})
ginkgo.Context("when influxdb is enabled", func() {
ginkgo.It("should send the request metric to the influxdb server", func() {
ifs := createInfluxDBService(f)
// Ingress configured with InfluxDB annotations
host := "influxdb.e2e.local"
createInfluxDBIngress(
f,
host,
framework.EchoService,
80,
map[string]string{
"nginx.ingress.kubernetes.io/enable-influxdb": "true",
"nginx.ingress.kubernetes.io/influxdb-host": ifs.Spec.ClusterIP,
"nginx.ingress.kubernetes.io/influxdb-port": "8089",
"nginx.ingress.kubernetes.io/influxdb-measurement": "requests",
"nginx.ingress.kubernetes.io/influxdb-servername": "e2e-nginx-srv",
},
)
// Do a request to the echo server ingress that sends metrics
// to the InfluxDB backend.
f.HTTPTestClient().
GET("/").
WithHeader("Host", host).
Expect().
Status(http.StatusOK)
framework.Sleep(10 * time.Second)
var measurements string
var err error
err = wait.Poll(time.Second, time.Minute, func() (bool, error) {
measurements, err = extractInfluxDBMeasurements(f)
if err != nil {
return false, nil
}
return true, nil
})
assert.Nil(ginkgo.GinkgoT(), err)
var results map[string][]map[string]interface{}
_ = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(measurements), &results)
assert.NotEqual(ginkgo.GinkgoT(), len(measurements), 0)
for _, elem := range results["results"] {
assert.NotEqual(ginkgo.GinkgoT(), len(elem), 0)
}
})
})
})
func createInfluxDBService(f *framework.Framework) *corev1.Service {
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "influxdb",
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{Ports: []corev1.ServicePort{
{
Name: "udp",
Port: 8089,
TargetPort: intstr.FromInt(8089),
Protocol: "UDP",
},
},
Selector: map[string]string{
"app": "influxdb",
},
},
}
return f.EnsureService(service)
}
func createInfluxDBIngress(f *framework.Framework, host, service string, port int, annotations map[string]string) {
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, service, port, annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
func(server string) bool {
return strings.Contains(server, fmt.Sprintf("server_name %v", host))
})
}
func extractInfluxDBMeasurements(f *framework.Framework) (string, error) {
l, err := f.KubeClientSet.CoreV1().Pods(f.Namespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: "app=influxdb",
})
if err != nil {
return "", err
}
if len(l.Items) == 0 {
return "", err
}
cmd := "influx -database 'nginx' -execute 'select * from requests' -format 'json' -pretty"
var pod *corev1.Pod
for _, p := range l.Items {
pod = &p
break
}
if pod == nil {
return "", fmt.Errorf("no influxdb pods found")
}
o, err := execInfluxDBCommand(pod, cmd)
if err != nil {
return "", err
}
return o, nil
}
func execInfluxDBCommand(pod *corev1.Pod, command string) (string, error) {
var (
execOut bytes.Buffer
execErr bytes.Buffer
)
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("%v exec --namespace %s %s -- %s", framework.KubectlPath, pod.Namespace, pod.Name, command))
cmd.Stdout = &execOut
cmd.Stderr = &execErr
err := cmd.Run()
if execErr.Len() > 0 {
return "", fmt.Errorf("stderr: %v", execErr.String())
}
if err != nil {
return "", fmt.Errorf("could not execute '%s %s': %v", cmd.Path, cmd.Args, err)
}
return execOut.String(), nil
}

View file

@ -60,7 +60,7 @@ var _ = framework.DescribeAnnotation("mirror-*", func() {
func(server string) bool {
return strings.Contains(server, fmt.Sprintf("mirror /_mirror-%v;", ing.UID)) &&
strings.Contains(server, "mirror_request_body on;") &&
strings.Contains(server, "proxy_pass https://test.env.com/$request_uri;")
strings.Contains(server, `proxy_pass "https://test.env.com/$request_uri";`)
})
})

View file

@ -17,7 +17,6 @@ limitations under the License.
package annotations
import (
"context"
"fmt"
"net/http"
"net/url"
@ -27,13 +26,12 @@ import (
"github.com/stretchr/testify/assert"
networking "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/test/e2e/framework"
)
var _ = framework.DescribeAnnotation("satisfy", func() {
f := framework.NewDefaultFramework("satisfy")
f := framework.NewDefaultFramework("satisfy", framework.WithHTTPBunEnabled())
ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
@ -84,17 +82,6 @@ var _ = framework.DescribeAnnotation("satisfy", func() {
ginkgo.It("should allow multiple auth with satisfy any", func() {
host := "auth"
// setup external auth
f.NewHttpbinDeployment()
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
assert.Nil(ginkgo.GinkgoT(), err)
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err)
httpbinIP := e.Subsets[0].Addresses[0].IP
// create basic auth secret at ingress
s := f.EnsureSecret(buildSecret("uname", "pwd", "basic-secret", f.Namespace))
@ -105,7 +92,7 @@ var _ = framework.DescribeAnnotation("satisfy", func() {
"nginx.ingress.kubernetes.io/auth-realm": "test basic auth",
// annotations for external auth
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", f.HTTPBunIP),
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
// set satisfy any

View file

@ -26,21 +26,25 @@ import (
)
var _ = framework.DescribeAnnotation("configuration-snippet", func() {
f := framework.NewDefaultFramework("configurationsnippet")
f := framework.NewDefaultFramework(
"configurationsnippet",
framework.WithHTTPBunEnabled(),
)
ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
})
ginkgo.It(`set snippet "more_set_headers "Foo1: Bar1";" in all locations"`, func() {
ginkgo.It("set snippet more_set_headers in all locations", func() {
host := "configurationsnippet.foo.com"
annotations := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": `
more_set_headers "Foo1: Bar1";`,
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`,
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.EnsureIngress(ing)
f.EnsureIngress(framework.NewSingleIngress(
host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
annotations))
f.WaitForNginxServer(host,
func(server string) bool {
@ -51,23 +55,32 @@ var _ = framework.DescribeAnnotation("configuration-snippet", func() {
GET("/").
WithHeader("Host", host).
Expect().
Status(http.StatusOK).Headers().
Status(http.StatusOK).
Headers().
ValueEqual("Foo1", []string{"Bar1"})
})
ginkgo.It(`drops snippet "more_set_headers "Foo1: Bar1";" in all locations if disabled by admin"`, func() {
ginkgo.It("drops snippet more_set_header in all locations if disabled by admin", func() {
host := "noconfigurationsnippet.foo.com"
annotations := map[string]string{
"nginx.ingress.kubernetes.io/configuration-snippet": `
more_set_headers "Foo1: Bar1";`,
"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_headers "Foo1: Bar1";`,
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
ing := framework.NewSingleIngress(
host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
annotations)
f.UpdateNginxConfigMapData("allow-snippet-annotations", "false")
defer func() {
// Return to the original value
f.UpdateNginxConfigMapData("allow-snippet-annotations", "true")
}()
// Sleep a while just to guarantee that the configmap is applied
framework.Sleep()
f.EnsureIngress(ing)
@ -81,7 +94,8 @@ var _ = framework.DescribeAnnotation("configuration-snippet", func() {
GET("/").
WithHeader("Host", host).
Expect().
Status(http.StatusOK).Headers().
Status(http.StatusOK).
Headers().
NotContainsKey("Foo1")
})
})

View file

@ -40,6 +40,7 @@ import (
_ "k8s.io/ingress-nginx/test/e2e/leaks"
_ "k8s.io/ingress-nginx/test/e2e/loadbalance"
_ "k8s.io/ingress-nginx/test/e2e/lua"
_ "k8s.io/ingress-nginx/test/e2e/metrics"
_ "k8s.io/ingress-nginx/test/e2e/nginx"
_ "k8s.io/ingress-nginx/test/e2e/security"
_ "k8s.io/ingress-nginx/test/e2e/servicebackend"

View file

@ -76,7 +76,8 @@ var _ = framework.IngressNginxDescribeSerial("[TopologyHints] topology aware rou
status, err := f.ExecIngressPod(curlCmd)
assert.Nil(ginkgo.GinkgoT(), err)
var backends []map[string]interface{}
json.Unmarshal([]byte(status), &backends)
err = json.Unmarshal([]byte(status), &backends)
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error unmarshalling backends")
gotBackends := 0
for _, bck := range backends {
if strings.Contains(bck["name"].(string), "topology") {

View file

@ -19,6 +19,7 @@ package framework
import (
"context"
"errors"
"fmt"
"os"
"time"
@ -36,12 +37,25 @@ const EchoService = "echo"
// SlowEchoService name of the deployment for the echo app
const SlowEchoService = "slow-echo"
// HTTPBinService name of the deployment for the httpbin app
const HTTPBinService = "httpbin"
// HTTPBunService name of the deployment for the httpbun app
const HTTPBunService = "httpbun"
// NipService name of external service using nip.io
const NIPService = "external-nip"
// HTTPBunImage is the default image that is used to deploy HTTPBun with the framwork
var HTTPBunImage = os.Getenv("HTTPBUN_IMAGE")
// EchoImage is the default image to be used by the echo service
const EchoImage = "registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:4938d1d91a2b7d19454460a8c1b010b89f6ff92d2987fd889ac3e8fc3b70d91a"
// TODO: change all Deployment functions to use these options
// in order to reduce complexity and have a unified API accross the
// framework
type deploymentOptions struct {
namespace string
name string
namespace string
image string
replicas int
svcAnnotations map[string]string
}
@ -82,27 +96,38 @@ func WithName(n string) func(*deploymentOptions) {
}
}
// WithImage allows configuring the image for the deployments
func WithImage(i string) func(*deploymentOptions) {
return func(o *deploymentOptions) {
o.image = i
}
}
// NewEchoDeployment creates a new single replica deployment of the echo server image in a particular namespace
func (f *Framework) NewEchoDeployment(opts ...func(*deploymentOptions)) {
options := &deploymentOptions{
namespace: f.Namespace,
name: EchoService,
replicas: 1,
image: EchoImage,
}
for _, o := range opts {
o(options)
}
deployment := newDeployment(options.name, options.namespace, "registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:4938d1d91a2b7d19454460a8c1b010b89f6ff92d2987fd889ac3e8fc3b70d91a", 80, int32(options.replicas),
f.EnsureDeployment(newDeployment(
options.name,
options.namespace,
options.image,
80,
int32(options.replicas),
nil, nil, nil,
[]corev1.VolumeMount{},
[]corev1.Volume{},
true,
)
))
f.EnsureDeployment(deployment)
service := &corev1.Service{
f.EnsureService(&corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: options.name,
Namespace: options.namespace,
@ -121,12 +146,125 @@ func (f *Framework) NewEchoDeployment(opts ...func(*deploymentOptions)) {
"app": options.name,
},
},
})
err := WaitForEndpoints(
f.KubeClientSet,
DefaultTimeout,
options.name,
options.namespace,
options.replicas,
)
assert.Nil(ginkgo.GinkgoT(), err, "waiting for endpoints to become ready")
}
// BuildNipHost used to generate a nip host for DNS resolving
func BuildNIPHost(ip string) string {
return fmt.Sprintf("%s.nip.io", ip)
}
// GetNipHost used to generate a nip host for external DNS resolving
// for the instance deployed by the framework
func (f *Framework) GetNIPHost() string {
return BuildNIPHost(f.HTTPBunIP)
}
// BuildNIPExternalNameService used to generate a service pointing to nip.io to
// help resolve to an IP address
func BuildNIPExternalNameService(f *Framework, ip, portName string) *corev1.Service {
return &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: NIPService,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: BuildNIPHost(ip),
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Name: portName,
Port: 80,
TargetPort: intstr.FromInt(80),
Protocol: "TCP",
},
},
},
}
}
// NewHttpbunDeployment creates a new single replica deployment of the httpbun
// server image in a particular namespace we return the ip for testing purposes
func (f *Framework) NewHttpbunDeployment(opts ...func(*deploymentOptions)) string {
options := &deploymentOptions{
namespace: f.Namespace,
name: HTTPBunService,
replicas: 1,
image: HTTPBunImage,
}
for _, o := range opts {
o(options)
}
f.EnsureService(service)
// Create the HTTPBun Deployment
f.EnsureDeployment(newDeployment(
options.name,
options.namespace,
options.image,
80,
int32(options.replicas),
nil, nil,
//Required to get hostname information
[]corev1.EnvVar{
{
Name: "HTTPBUN_INFO_ENABLED",
Value: "1",
},
},
[]corev1.VolumeMount{},
[]corev1.Volume{},
true,
))
err := WaitForEndpoints(f.KubeClientSet, DefaultTimeout, options.name, options.namespace, options.replicas)
// Create a service pointing to deployment
f.EnsureService(&corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: options.name,
Namespace: options.namespace,
Annotations: options.svcAnnotations,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "http",
Port: 80,
TargetPort: intstr.FromInt(80),
Protocol: corev1.ProtocolTCP,
},
},
Selector: map[string]string{
"app": options.name,
},
},
})
// Wait for deployment to become available
err := WaitForEndpoints(
f.KubeClientSet,
DefaultTimeout,
options.name,
options.namespace,
options.replicas,
)
assert.Nil(ginkgo.GinkgoT(), err, "waiting for endpoints to become ready")
// Get cluster ip for HTTPBun to be used in tests
e, err := f.KubeClientSet.
CoreV1().
Endpoints(f.Namespace).
Get(context.TODO(), HTTPBunService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "failed to get httpbun endpoint")
return e.Subsets[0].Addresses[0].IP
}
// NewSlowEchoDeployment creates a new deployment of the slow echo server image in a particular namespace.
@ -184,13 +322,16 @@ func (f *Framework) NGINXDeployment(name string, cfg string, waitendpoint bool)
"nginx.conf": cfg,
}
_, err := f.KubeClientSet.CoreV1().ConfigMaps(f.Namespace).Create(context.TODO(), &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: f.Namespace,
},
Data: cfgMap,
}, metav1.CreateOptions{})
_, err := f.KubeClientSet.
CoreV1().
ConfigMaps(f.Namespace).
Create(context.TODO(), &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: f.Namespace,
},
Data: cfgMap,
}, metav1.CreateOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "creating configmap")
deployment := newDeployment(name, f.Namespace, f.GetNginxBaseImage(), 80, 1,
@ -418,11 +559,6 @@ func newDeployment(name, namespace, image string, port int32, replicas int32, co
return d
}
// NewHttpbinDeployment creates a new single replica deployment of the httpbin image in a particular namespace.
func (f *Framework) NewHttpbinDeployment() {
f.NewDeployment(HTTPBinService, "registry.k8s.io/ingress-nginx/e2e-test-httpbin@sha256:c6372ef57a775b95f18e19d4c735a9819f2e7bb4641e5e3f27287d831dfeb7e8", 80, 1)
}
func (f *Framework) NewDeployment(name, image string, port int32, replicas int32) {
f.NewDeploymentWithOpts(name, image, port, replicas, nil, nil, nil, nil, nil, true)
}

View file

@ -27,7 +27,6 @@ import (
"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1"
apiextcs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
@ -38,7 +37,6 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
)
@ -62,23 +60,39 @@ type Framework struct {
// A Kubernetes and Service Catalog client
KubeClientSet kubernetes.Interface
KubeConfig *restclient.Config
KubeConfig *rest.Config
APIExtensionsClientSet apiextcs.Interface
Namespace string
IngressClass string
pod *corev1.Pod
pod *v1.Pod
// We use httpbun as a service that we route to in our tests through
// the ingress controller. We add it as part of the framework as it
// is used extensively
HTTPBunIP string
HTTPBunEnabled bool
}
// WithHTTPBunEnabled deploys an instance of HTTPBun for the specific test
func WithHTTPBunEnabled() func(*Framework) {
return func(f *Framework) {
f.HTTPBunEnabled = true
}
}
// NewDefaultFramework makes a new framework and sets up a BeforeEach/AfterEach for
// you (you can write additional before/after each functions).
func NewDefaultFramework(baseName string) *Framework {
func NewDefaultFramework(baseName string, opts ...func(*Framework)) *Framework {
defer ginkgo.GinkgoRecover()
f := &Framework{
BaseName: baseName,
}
// set framework options
for _, o := range opts {
o(f)
}
ginkgo.BeforeEach(f.BeforeEach)
ginkgo.AfterEach(f.AfterEach)
@ -88,12 +102,16 @@ func NewDefaultFramework(baseName string) *Framework {
// NewSimpleFramework makes a new framework that allows the usage of a namespace
// for arbitraty tests.
func NewSimpleFramework(baseName string) *Framework {
func NewSimpleFramework(baseName string, opts ...func(*Framework)) *Framework {
defer ginkgo.GinkgoRecover()
f := &Framework{
BaseName: baseName,
}
// set framework options
for _, o := range opts {
o(f)
}
ginkgo.BeforeEach(f.CreateEnvironment)
ginkgo.AfterEach(f.DestroyEnvironment)
@ -142,6 +160,11 @@ func (f *Framework) BeforeEach() {
assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller pod information")
f.WaitForNginxListening(80)
// If HTTPBun is enabled deploy an instance to the namespace
if f.HTTPBunEnabled {
f.HTTPBunIP = f.NewHttpbunDeployment()
}
}
// AfterEach deletes the namespace, after reading its events.
@ -162,7 +185,7 @@ func (f *Framework) AfterEach() {
return
}
cmd := fmt.Sprintf("cat /etc/nginx/nginx.conf")
cmd := "cat /etc/nginx/nginx.conf"
o, err := f.ExecCommand(f.pod, cmd)
if err != nil {
Logf("Unexpected error obtaining nginx.conf file: %v", err)
@ -233,7 +256,7 @@ func (f *Framework) GetURL(scheme RequestScheme) string {
}
// GetIngressNGINXPod returns the ingress controller running pod
func (f *Framework) GetIngressNGINXPod() *corev1.Pod {
func (f *Framework) GetIngressNGINXPod() *v1.Pod {
return f.pod
}
@ -279,7 +302,7 @@ func (f *Framework) matchNginxConditions(name string, matcher func(cfg string) b
return func() (bool, error) {
var cmd string
if name == "" {
cmd = fmt.Sprintf("cat /etc/nginx/nginx.conf")
cmd = "cat /etc/nginx/nginx.conf"
} else {
cmd = fmt.Sprintf("cat /etc/nginx/nginx.conf | awk '/## start server %v/,/## end server %v/'", name, name)
}
@ -413,13 +436,13 @@ func (f *Framework) WaitForReload(fn func()) {
assert.Nil(ginkgo.GinkgoT(), err, "while waiting for ingress controller reload")
}
func getReloadCount(pod *corev1.Pod, namespace string, client kubernetes.Interface) int {
func getReloadCount(pod *v1.Pod, namespace string, client kubernetes.Interface) int {
events, err := client.CoreV1().Events(namespace).Search(scheme.Scheme, pod)
assert.Nil(ginkgo.GinkgoT(), err, "obtaining NGINX Pod")
reloadCount := 0
for _, e := range events.Items {
if e.Reason == "RELOAD" && e.Type == corev1.EventTypeNormal {
if e.Reason == "RELOAD" && e.Type == v1.EventTypeNormal {
reloadCount++
}
}
@ -793,7 +816,7 @@ func Sleep(duration ...time.Duration) {
time.Sleep(sleepFor)
}
func loadConfig() (*restclient.Config, error) {
func loadConfig() (*rest.Config, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, err

View file

@ -36,19 +36,3 @@ func (c *chain) fail(message string, args ...interface{}) {
c.failbit = true
c.reporter.Errorf(message, args...)
}
func (c *chain) reset() {
c.failbit = false
}
func (c *chain) assertFailed(r Reporter) {
if !c.failbit {
r.Errorf("expected chain is failed, but it's ok")
}
}
func (c *chain) assertOK(r Reporter) {
if c.failbit {
r.Errorf("expected chain is ok, but it's failed")
}
}

View file

@ -1,141 +0,0 @@
/*
Copyright 2018 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 framework
import (
"github.com/onsi/ginkgo/v2"
"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/apimachinery/pkg/fields"
)
const influxConfig = `
reporting-disabled = true
bind-address = "0.0.0.0:8088"
[meta]
dir = "/var/lib/influxdb/meta"
retention-autocreate = true
logging-enabled = true
[data]
dir = "/var/lib/influxdb/data"
index-version = "inmem"
wal-dir = "/var/lib/influxdb/wal"
wal-fsync-delay = "0s"
query-log-enabled = true
cache-max-memory-size = 1073741824
cache-snapshot-memory-size = 26214400
cache-snapshot-write-cold-duration = "10m0s"
compact-full-write-cold-duration = "4h0m0s"
max-series-per-database = 1000000
max-values-per-tag = 100000
max-concurrent-compactions = 0
trace-logging-enabled = false
[[udp]]
enabled = true
bind-address = ":8089"
database = "nginx"
`
// NewInfluxDBDeployment creates an InfluxDB server configured to reply
// on 8086/tcp and 8089/udp
func (f *Framework) NewInfluxDBDeployment() {
configuration := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "influxdb-config",
Namespace: f.Namespace,
},
Data: map[string]string{
"influxd.conf": influxConfig,
},
}
f.EnsureConfigMap(configuration)
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "influxdb",
Namespace: f.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: NewInt32(1),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "influxdb",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "influxdb",
},
},
Spec: corev1.PodSpec{
TerminationGracePeriodSeconds: NewInt64(0),
Volumes: []corev1.Volume{
{
Name: "influxdb-config",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "influxdb-config",
},
},
},
},
},
Containers: []corev1.Container{
{
Name: "influxdb",
Image: "docker.io/influxdb:1.5",
Env: []corev1.EnvVar{},
Command: []string{"influxd", "-config", "/influxdb-config/influxd.conf"},
VolumeMounts: []corev1.VolumeMount{
{
Name: "influxdb-config",
ReadOnly: true,
MountPath: "/influxdb-config",
},
},
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 8086,
},
{
Name: "udp",
ContainerPort: 8089,
},
},
},
},
},
},
},
}
d := f.EnsureDeployment(deployment)
err := waitForPodsReady(f.KubeClientSet, DefaultTimeout, 1, f.Namespace, metav1.ListOptions{
LabelSelector: fields.SelectorFromSet(fields.Set(d.Spec.Template.ObjectMeta.Labels)).String(),
})
assert.Nil(ginkgo.GinkgoT(), err, "waiting for influxdb pod to become ready")
}

View file

@ -0,0 +1,94 @@
/*
Copyright 2023 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 defaultbackend
import (
"context"
"fmt"
"net/http"
"strings"
"time"
"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/test/e2e/framework"
)
const waitForMetrics = 2 * time.Second
var _ = framework.IngressNginxDescribe("[metrics] exported prometheus metrics", func() {
f := framework.NewDefaultFramework("metrics")
host := "foo.com"
ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil))
f.WaitForNginxServer(host,
func(server string) bool {
return strings.Contains(server, fmt.Sprintf("server_name %s ;", host)) &&
strings.Contains(server, "proxy_pass http://upstream_balancer;")
})
})
ginkgo.It("exclude socket request metrics are absent", func() {
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
args := deployment.Spec.Template.Spec.Containers[0].Args
args = append(args, "--exclude-socket-metrics=nginx_ingress_controller_request_size,nginx_ingress_controller_header_duration_seconds")
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 deployment")
f.HTTPTestClient().
GET("/").
WithHeader("Host", host).
Expect().
Status(http.StatusOK)
time.Sleep(waitForMetrics)
ip := f.GetNginxPodIP()
mf, err := f.GetMetric("nginx_ingress_controller_request_size", ip)
assert.ErrorContains(ginkgo.GinkgoT(), err, "nginx_ingress_controller_request_size")
assert.Nil(ginkgo.GinkgoT(), mf)
})
ginkgo.It("exclude socket request metrics are present", func() {
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
args := deployment.Spec.Template.Spec.Containers[0].Args
args = append(args, "--exclude-socket-metrics=non_existing_metric_does_not_affect_existing_metrics")
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 deployment")
f.HTTPTestClient().
GET("/").
WithHeader("Host", host).
Expect().
Status(http.StatusOK)
time.Sleep(waitForMetrics)
ip := f.GetNginxPodIP()
mf, err := f.GetMetric("nginx_ingress_controller_request_size", ip)
assert.Nil(ginkgo.GinkgoT(), err)
assert.NotNil(ginkgo.GinkgoT(), mf)
})
})

View file

@ -62,7 +62,7 @@ export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}"
if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then
echo "[dev-env] creating Kubernetes cluster with kind"
export K8S_VERSION=${K8S_VERSION:-v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6}
export K8S_VERSION=${K8S_VERSION:-v1.26.3@sha256:61b92f38dff6ccc29969e7aa154d34e38b89443af1a2c14e6cfbd2df6419c66f}
kind create cluster \
--verbosity=${KIND_LOG_LEVEL} \
@ -78,7 +78,7 @@ fi
if [ "${SKIP_IMAGE_CREATION:-false}" = "false" ]; then
if ! command -v ginkgo &> /dev/null; then
go install github.com/onsi/ginkgo/v2/ginkgo@v2.9.0
go install github.com/onsi/ginkgo/v2/ginkgo@v2.9.5
fi
echo "[dev-env] building image"
make -C ${DIR}/../../ clean-image build image
@ -91,9 +91,16 @@ echo "[dev-env] copying docker images to cluster..."
kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes=${KIND_WORKERS} ${REGISTRY}/controller:${TAG}
if [ "${SKIP_CERT_MANAGER_CREATION:-false}" = "false" ]; then
curl -fsSL -o cmctl.tar.gz https://github.com/cert-manager/cert-manager/releases/download/v1.11.1/cmctl-linux-amd64.tar.gz
tar xzf cmctl.tar.gz
chmod +x cmctl
./cmctl help
echo "[dev-env] apply cert-manager ..."
kubectl apply --wait -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml
sleep 10
kubectl apply --wait -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
kubectl wait --timeout=30s --for=condition=available deployment/cert-manager -n cert-manager
kubectl get validatingwebhookconfigurations cert-manager-webhook -ojson | jq '.webhooks[].clientConfig'
kubectl get endpoints -n cert-manager cert-manager-webhook
./cmctl check api --wait=2m
fi
echo "[dev-env] running helm chart e2e tests..."

View file

@ -51,6 +51,7 @@ fi
BASEDIR=$(dirname "$0")
NGINX_BASE_IMAGE=$(cat $BASEDIR/../../NGINX_BASE)
HTTPBUN_IMAGE=$(cat $BASEDIR/HTTPBUN_IMAGE)
echo -e "${BGREEN}Granting permissions to ingress-nginx e2e service account...${NC}"
kubectl create serviceaccount ingress-nginx-e2e || true
@ -79,6 +80,7 @@ kubectl run --rm \
--env="IS_CHROOT=${IS_CHROOT:-false}"\
--env="E2E_CHECK_LEAKS=${E2E_CHECK_LEAKS}" \
--env="NGINX_BASE_IMAGE=${NGINX_BASE_IMAGE}" \
--env="HTTPBUN_IMAGE=${HTTPBUN_IMAGE}" \
--overrides='{ "apiVersion": "v1", "spec":{"serviceAccountName": "ingress-nginx-e2e"}}' \
e2e --image=nginx-ingress-controller:e2e

View file

@ -63,7 +63,7 @@ echo "Running e2e with nginx base image ${NGINX_BASE_IMAGE}"
if [ "${SKIP_CLUSTER_CREATION}" = "false" ]; then
echo "[dev-env] creating Kubernetes cluster with kind"
export K8S_VERSION=${K8S_VERSION:-v1.25.2@sha256:9be91e9e9cdf116809841fc77ebdb8845443c4c72fe5218f3ae9eb57fdb4bace}
export K8S_VERSION=${K8S_VERSION:-v1.26.3@sha256:61b92f38dff6ccc29969e7aa154d34e38b89443af1a2c14e6cfbd2df6419c66f}
# delete the cluster if it exists
if kind get clusters | grep "${KIND_CLUSTER_NAME}"; then
@ -95,7 +95,7 @@ fi
if [ "${SKIP_E2E_IMAGE_CREATION}" = "false" ]; then
if ! command -v ginkgo &> /dev/null; then
go install github.com/onsi/ginkgo/v2/ginkgo@v2.9.0
go install github.com/onsi/ginkgo/v2/ginkgo@v2.9.5
fi
echo "[dev-env] .. done building controller images"

View file

@ -50,9 +50,12 @@ server {
f.UpdateNginxConfigMapData("http-snippet", snippet)
//TODO: currently using a self hosted HTTPBun instance results in a 499, we
//should move away from using httpbun.com once we have the httpbun
//deployment as part of the framework
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, map[string]string{
"nginx.ingress.kubernetes.io/auth-signin": "https://httpbin.org/uuid",
"nginx.ingress.kubernetes.io/auth-url": "https://httpbin.org/basic-auth/user/passwd",
"nginx.ingress.kubernetes.io/auth-signin": "https://httpbun.com/bearer/d4bcba7a-0def-4a31-91a7-47e420adf44b",
"nginx.ingress.kubernetes.io/auth-url": "https://httpbun.com/basic-auth/user/passwd",
})
f.EnsureIngress(ing)
@ -76,7 +79,9 @@ func smugglingRequest(host, addr string, port int) (string, error) {
defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Second * 10))
if err := conn.SetDeadline(time.Now().Add(time.Second * 10)); err != nil {
return "", err
}
_, err = fmt.Fprintf(conn, "GET /echo HTTP/1.1\r\nHost: %v\r\nContent-Length: 56\r\n\r\nGET /_hidden/index.html HTTP/1.1\r\nHost: notlocalhost\r\n\r\n", host)
if err != nil {

View file

@ -29,44 +29,21 @@ import (
corev1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/ingress-nginx/internal/nginx"
"k8s.io/ingress-nginx/test/e2e/framework"
)
func buildHTTPBinExternalNameService(f *framework.Framework, portName string) *corev1.Service {
return &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: framework.HTTPBinService,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: "httpbin.org",
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Name: portName,
Port: 80,
TargetPort: intstr.FromInt(80),
Protocol: "TCP",
},
},
},
}
}
var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
f := framework.NewDefaultFramework("type-externalname")
f := framework.NewDefaultFramework("type-externalname", framework.WithHTTPBunEnabled())
ginkgo.It("works with external name set to incomplete fqdn", func() {
f.NewEchoDeployment()
host := "echo"
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: framework.HTTPBinService,
Name: framework.NIPService,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
@ -74,10 +51,15 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
Type: corev1.ServiceTypeExternalName,
},
}
f.EnsureService(svc)
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.NIPService,
80,
nil)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
@ -97,21 +79,27 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: framework.HTTPBinService,
Name: framework.NIPService,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: "httpbin.org",
ExternalName: f.GetNIPHost(),
Type: corev1.ServiceTypeExternalName,
},
}
f.EnsureService(svc)
annotations := map[string]string{
"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
"nginx.ingress.kubernetes.io/upstream-vhost": f.GetNIPHost(),
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
@ -129,13 +117,19 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
ginkgo.It("should return 200 for service type=ExternalName with a port defined", func() {
host := "echo"
svc := buildHTTPBinExternalNameService(f, host)
svc := framework.BuildNIPExternalNameService(f, f.HTTPBunIP, host)
f.EnsureService(svc)
annotations := map[string]string{
"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
"nginx.ingress.kubernetes.io/upstream-vhost": f.GetNIPHost(),
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
@ -155,7 +149,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: framework.HTTPBinService,
Name: framework.NIPService,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
@ -163,10 +157,15 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
Type: corev1.ServiceTypeExternalName,
},
}
f.EnsureService(svc)
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.NIPService,
80,
nil)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
@ -184,21 +183,29 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
ginkgo.It("should return 200 for service type=ExternalName using a port name", func() {
host := "echo"
svc := buildHTTPBinExternalNameService(f, host)
svc := framework.BuildNIPExternalNameService(f, f.HTTPBunIP, host)
f.EnsureService(svc)
annotations := map[string]string{
"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
"nginx.ingress.kubernetes.io/upstream-vhost": f.GetNIPHost(),
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
annotations)
namedBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: framework.HTTPBinService,
Name: framework.NIPService,
Port: networking.ServiceBackendPort{
Name: host,
},
},
}
ing.Spec.Rules[0].HTTP.Paths[0].Backend = namedBackend
f.EnsureIngress(ing)
@ -219,18 +226,23 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: framework.HTTPBinService,
Name: framework.NIPService,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: "httpbin.org.",
ExternalName: f.GetNIPHost(),
Type: corev1.ServiceTypeExternalName,
},
}
f.EnsureService(svc)
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
nil)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
@ -248,16 +260,24 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
ginkgo.It("should update the external name after a service update", func() {
host := "echo"
svc := buildHTTPBinExternalNameService(f, host)
svc := framework.BuildNIPExternalNameService(f, f.HTTPBunIP, host)
f.EnsureService(svc)
annotations := map[string]string{
"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
"nginx.ingress.kubernetes.io/upstream-vhost": f.GetNIPHost(),
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.HTTPBunService,
80,
annotations)
namedBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: framework.HTTPBinService,
Name: framework.NIPService,
Port: networking.ServiceBackendPort{
Name: host,
},
@ -281,13 +301,21 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
assert.Contains(ginkgo.GinkgoT(), body, `"X-Forwarded-Host": "echo"`)
svc, err := f.KubeClientSet.CoreV1().Services(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error obtaining httpbin service")
svc, err := f.KubeClientSet.
CoreV1().
Services(f.Namespace).
Get(context.TODO(), framework.NIPService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error obtaining external service")
svc.Spec.ExternalName = "eu.httpbin.org"
//Deploy a new instance to switch routing to
ip := f.NewHttpbunDeployment(framework.WithDeploymentName("eu-server"))
svc.Spec.ExternalName = framework.BuildNIPHost(ip)
_, err = f.KubeClientSet.CoreV1().Services(f.Namespace).Update(context.Background(), svc, metav1.UpdateOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error updating httpbin service")
_, err = f.KubeClientSet.
CoreV1().
Services(f.Namespace).
Update(context.Background(), svc, metav1.UpdateOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error updating external service")
framework.Sleep()
@ -301,18 +329,32 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
assert.Contains(ginkgo.GinkgoT(), body, `"X-Forwarded-Host": "echo"`)
ginkgo.By("checking the service is updated to use eu.httpbin.org")
curlCmd := fmt.Sprintf("curl --fail --silent http://localhost:%v/configuration/backends", nginx.StatusPort)
ginkgo.By("checking the service is updated to use new host")
curlCmd := fmt.Sprintf(
"curl --fail --silent http://localhost:%v/configuration/backends",
nginx.StatusPort,
)
output, err := f.ExecIngressPod(curlCmd)
assert.Nil(ginkgo.GinkgoT(), err)
assert.Contains(ginkgo.GinkgoT(), output, `{"address":"eu.httpbin.org"`)
assert.Contains(
ginkgo.GinkgoT(),
output,
fmt.Sprintf("{\"address\":\"%s\"", framework.BuildNIPHost(ip)),
)
})
ginkgo.It("should sync ingress on external name service addition/deletion", func() {
host := "echo"
// Create the Ingress first
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
ing := framework.NewSingleIngress(host,
"/",
host,
f.Namespace,
framework.NIPService,
80,
nil)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,
@ -328,7 +370,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
Status(http.StatusServiceUnavailable)
// Now create the service
svc := buildHTTPBinExternalNameService(f, host)
svc := framework.BuildNIPExternalNameService(f, f.HTTPBunIP, host)
f.EnsureService(svc)
framework.Sleep()
@ -341,9 +383,11 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
Status(http.StatusOK)
// And back to 503 after deleting the service
err := f.KubeClientSet.CoreV1().Services(f.Namespace).Delete(context.TODO(), framework.HTTPBinService, metav1.DeleteOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error deleting httpbin service")
err := f.KubeClientSet.
CoreV1().
Services(f.Namespace).
Delete(context.TODO(), framework.NIPService, metav1.DeleteOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error deleting external service")
framework.Sleep()

View file

@ -28,14 +28,13 @@ import (
)
var _ = framework.IngressNginxDescribe("brotli", func() {
f := framework.NewDefaultFramework("brotli")
f := framework.NewDefaultFramework(
"brotli",
framework.WithHTTPBunEnabled(),
)
host := "brotli"
ginkgo.BeforeEach(func() {
f.NewHttpbinDeployment()
})
ginkgo.It("should only compress responses that meet the `brotli-min-length` condition", func() {
brotliMinLength := 24
contentEncoding := "application/octet-stream"
@ -43,7 +42,7 @@ var _ = framework.IngressNginxDescribe("brotli", func() {
f.UpdateNginxConfigMapData("brotli-types", contentEncoding)
f.UpdateNginxConfigMapData("brotli-min-length", strconv.Itoa(brotliMinLength))
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil))
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBunService, 80, nil))
f.WaitForNginxConfiguration(
func(server string) bool {

View file

@ -33,7 +33,10 @@ import (
)
var _ = framework.IngressNginxDescribe("[Flag] disable-service-external-name", func() {
f := framework.NewDefaultFramework("disabled-service-external-name")
f := framework.NewDefaultFramework(
"disabled-service-external-name",
framework.WithHTTPBunEnabled(),
)
ginkgo.BeforeEach(func() {
f.NewEchoDeployment(framework.WithDeploymentReplicas(2))
@ -50,21 +53,22 @@ var _ = framework.IngressNginxDescribe("[Flag] disable-service-external-name", f
})
ginkgo.It("should ignore services of external-name type", func() {
nonexternalhost := "echo-svc.com"
externalhost := "echo-external-svc.com"
svcexternal := &corev1.Service{
f.EnsureService(framework.BuildNIPExternalNameService(f, f.HTTPBunIP, "echo"))
f.EnsureService(&corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "external",
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: "httpbin.org",
ExternalName: f.GetNIPHost(),
Type: corev1.ServiceTypeExternalName,
},
}
f.EnsureService(svcexternal)
})
ingexternal := framework.NewSingleIngress(externalhost, "/", externalhost, f.Namespace, "external", 80, nil)
f.EnsureIngress(ingexternal)

View file

@ -64,15 +64,15 @@ var _ = framework.DescribeSetting("enable-real-ip", func() {
Body().
Raw()
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=myhost"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-host=myhost"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=myproto"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=1234"))
assert.NotContains(ginkgo.GinkgoT(), body, "host=myhost")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-host=myhost")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-proto=myproto")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-port=1234")
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=%s", host))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-host=%s", host))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=http"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=80"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=1.2.3.4"))
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=http")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=80")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-for=1.2.3.4")
})
ginkgo.It("should not trust X-Forwarded-For header when setting is false", func() {
@ -101,13 +101,13 @@ var _ = framework.DescribeSetting("enable-real-ip", func() {
Raw()
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=%s", host))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=80"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=http"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-original-forwarded-for=1.2.3.4"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=myhost"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-host=myhost"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=myproto"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=1234"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=1.2.3.4"))
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=80")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=http")
assert.Contains(ginkgo.GinkgoT(), body, "x-original-forwarded-for=1.2.3.4")
assert.NotContains(ginkgo.GinkgoT(), body, "host=myhost")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-host=myhost")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-proto=myproto")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-port=1234")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-for=1.2.3.4")
})
})

View file

@ -17,7 +17,6 @@ limitations under the License.
package settings
import (
"fmt"
"net/http"
"strings"
@ -65,12 +64,12 @@ var _ = framework.DescribeSetting("use-forwarded-headers", func() {
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=myhost"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-host=myhost"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=myproto"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-scheme=myproto"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=1234"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=1.2.3.4"))
assert.Contains(ginkgo.GinkgoT(), body, "host=myhost")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-host=myhost")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=myproto")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-scheme=myproto")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=1234")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-for=1.2.3.4")
ginkgo.By("ensuring that first entry in X-Forwarded-Host is used as the best host")
body = f.HTTPTestClient().
@ -85,8 +84,8 @@ var _ = framework.DescribeSetting("use-forwarded-headers", func() {
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=myhost.com"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-host=myhost.com"))
assert.Contains(ginkgo.GinkgoT(), body, "host=myhost.com")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-host=myhost.com")
})
ginkgo.It("should not trust X-Forwarded headers when setting is false", func() {
@ -115,16 +114,16 @@ var _ = framework.DescribeSetting("use-forwarded-headers", func() {
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=forwarded-headers"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=80"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=http"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-scheme=http"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-original-forwarded-for=1.2.3.4"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=myhost"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-host=myhost"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=myproto"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-scheme=myproto"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=1234"))
assert.NotContains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=1.2.3.4"))
assert.Contains(ginkgo.GinkgoT(), body, "host=forwarded-headers")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=80")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=http")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-scheme=http")
assert.Contains(ginkgo.GinkgoT(), body, "x-original-forwarded-for=1.2.3.4")
assert.NotContains(ginkgo.GinkgoT(), body, "host=myhost")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-host=myhost")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-proto=myproto")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-scheme=myproto")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-port=1234")
assert.NotContains(ginkgo.GinkgoT(), body, "x-forwarded-for=1.2.3.4")
})
})

View file

@ -32,7 +32,10 @@ import (
)
var _ = framework.DescribeSetting("[Security] global-auth-url", func() {
f := framework.NewDefaultFramework("global-external-auth")
f := framework.NewDefaultFramework(
"global-external-auth",
framework.WithHTTPBunEnabled(),
)
host := "global-external-auth"
@ -50,13 +53,12 @@ var _ = framework.DescribeSetting("[Security] global-auth-url", func() {
ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
f.NewHttpbinDeployment()
})
ginkgo.Context("when global external authentication is configured", func() {
ginkgo.BeforeEach(func() {
globalExternalAuthURL := fmt.Sprintf("http://%s.%s.svc.cluster.local:80/status/401", framework.HTTPBinService, f.Namespace)
globalExternalAuthURL := fmt.Sprintf("http://%s.%s.svc.cluster.local:80/status/401", framework.HTTPBunService, f.Namespace)
ginkgo.By("Adding an ingress rule for /foo")
fooIng := framework.NewSingleIngress("foo-ingress", fooPath, host, f.Namespace, echoServiceName, 80, nil)
@ -158,7 +160,7 @@ var _ = framework.DescribeSetting("[Security] global-auth-url", func() {
globalExternalAuthCacheKey := "foo"
globalExternalAuthCacheDurationSetting := "global-auth-cache-duration"
globalExternalAuthCacheDuration := "200 201 401 30m"
globalExternalAuthURL := fmt.Sprintf("http://%s.%s.svc.cluster.local:80/status/200", framework.HTTPBinService, f.Namespace)
globalExternalAuthURL := fmt.Sprintf("http://%s.%s.svc.cluster.local:80/status/200", framework.HTTPBunService, f.Namespace)
ginkgo.By("Adding a global-auth-cache-key to configMap")
f.SetNginxConfigMapData(map[string]string{
@ -182,7 +184,7 @@ var _ = framework.DescribeSetting("[Security] global-auth-url", func() {
Expect().
Status(http.StatusOK)
err := f.DeleteDeployment(framework.HTTPBinService)
err := f.DeleteDeployment(framework.HTTPBunService)
assert.Nil(ginkgo.GinkgoT(), err)
framework.Sleep()
@ -307,9 +309,9 @@ http {
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets), 1, "expected at least one endpoint")
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets[0].Addresses), 1, "expected at least one address ready in the endpoint")
httpbinIP := e.Subsets[0].Addresses[0].IP
nginxIP := e.Subsets[0].Addresses[0].IP
f.UpdateNginxConfigMapData(globalExternalAuthURLSetting, fmt.Sprintf("http://%s/cookies/set/alma/armud", httpbinIP))
f.UpdateNginxConfigMapData(globalExternalAuthURLSetting, fmt.Sprintf("http://%s/cookies/set/alma/armud", nginxIP))
ing1 = framework.NewSingleIngress(host, "/", host, f.Namespace, "http-cookie-with-error", 80, nil)
f.EnsureIngress(ing1)

View file

@ -17,7 +17,6 @@ limitations under the License.
package settings
import (
"fmt"
"regexp"
"strings"
@ -41,7 +40,7 @@ var _ = framework.DescribeSetting("keep-alive keep-alive-requests", func() {
f.UpdateNginxConfigMapData("keep-alive", "140")
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, fmt.Sprintf(`keepalive_timeout 140s;`))
return strings.Contains(server, `keepalive_timeout 140s;`)
})
})
@ -49,7 +48,7 @@ var _ = framework.DescribeSetting("keep-alive keep-alive-requests", func() {
f.UpdateNginxConfigMapData("keep-alive-requests", "200")
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, fmt.Sprintf(`keepalive_requests 200;`))
return strings.Contains(server, `keepalive_requests 200;`)
})
})

View file

@ -17,14 +17,12 @@ limitations under the License.
package settings
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/onsi/ginkgo/v2"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/test/e2e/framework"
)
@ -33,7 +31,7 @@ var _ = framework.IngressNginxDescribe("[Flag] custom HTTP and HTTPS ports", fun
host := "forwarded-headers"
f := framework.NewDefaultFramework("forwarded-port-headers")
f := framework.NewDefaultFramework("forwarded-port-headers", framework.WithHTTPBunEnabled())
ginkgo.BeforeEach(func() {
f.NewEchoDeployment()
@ -92,27 +90,14 @@ var _ = framework.IngressNginxDescribe("[Flag] custom HTTP and HTTPS ports", fun
Expect().
Status(http.StatusOK).
Body().
Contains(fmt.Sprintf("x-forwarded-port=443"))
Contains("x-forwarded-port=443")
})
ginkgo.Context("when external authentication is configured", func() {
ginkgo.It("should set the X-Forwarded-Port header to 443", func() {
f.NewHttpbinDeployment()
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
assert.Nil(ginkgo.GinkgoT(), err)
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err)
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets), 1, "expected at least one endpoint")
assert.GreaterOrEqual(ginkgo.GinkgoT(), len(e.Subsets[0].Addresses), 1, "expected at least one address ready in the endpoint")
httpbinIP := e.Subsets[0].Addresses[0].IP
annotations := map[string]string{
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", httpbinIP),
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", f.HTTPBunIP),
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
}
@ -141,7 +126,7 @@ var _ = framework.IngressNginxDescribe("[Flag] custom HTTP and HTTPS ports", fun
Expect().
Status(http.StatusOK).
Body().
Contains(fmt.Sprintf("x-forwarded-port=443"))
Contains("x-forwarded-port=443")
})
})
})

View file

@ -17,7 +17,6 @@ limitations under the License.
package settings
import (
"fmt"
"strings"
"github.com/onsi/ginkgo/v2"
@ -34,7 +33,7 @@ var _ = framework.DescribeSetting("Add no tls redirect locations", func() {
f.EnsureIngress(ing)
f.WaitForNginxConfiguration(func(server string) bool {
return !strings.Contains(server, fmt.Sprintf("force_no_ssl_redirect = true,"))
return !strings.Contains(server, "force_no_ssl_redirect = true,")
})
wlKey := "no-tls-redirect-locations"
@ -43,7 +42,7 @@ var _ = framework.DescribeSetting("Add no tls redirect locations", func() {
f.UpdateNginxConfigMapData(wlKey, wlValue)
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, fmt.Sprintf("force_no_ssl_redirect = true,"))
return strings.Contains(server, "force_no_ssl_redirect = true,")
})
})

View file

@ -68,7 +68,7 @@ var _ = framework.DescribeSetting("OCSP", func() {
var pemCertBuffer bytes.Buffer
pemCertBuffer.Write(leafCert)
pemCertBuffer.Write([]byte("\n"))
pemCertBuffer.WriteString("\n")
pemCertBuffer.Write(intermediateCa)
f.EnsureSecret(&corev1.Secret{
@ -290,7 +290,7 @@ func ocspserveDeployment(namespace string) (*appsv1.Deployment, *corev1.Service)
Containers: []corev1.Container{
{
Name: name,
Image: "registry.k8s.io/ingress-nginx/e2e-test-cfssl@sha256:d02c1e18f573449966999fc850f1fed3d37621bf77797562cbe77ebdb06a66ea",
Image: "registry.k8s.io/ingress-nginx/e2e-test-cfssl@sha256:adaa118c179c41cb33fb567004a1f0c71b8fce6bc13263efa63d42dddd5b4346",
Command: []string{
"/bin/bash",
"-c",

View file

@ -66,7 +66,7 @@ var _ = framework.IngressNginxDescribe("Dynamic $proxy_host", func() {
f.WaitForNginxConfiguration(
func(server string) bool {
return strings.Contains(server, fmt.Sprintf("server_name %v", test)) &&
strings.Contains(server, fmt.Sprintf("set $proxy_host $proxy_upstream_name"))
strings.Contains(server, "set $proxy_host $proxy_upstream_name")
})
f.HTTPTestClient().

View file

@ -63,17 +63,20 @@ var _ = framework.DescribeSetting("use-proxy-protocol", func() {
defer conn.Close()
header := "PROXY TCP4 192.168.0.1 192.168.0.11 56324 1234\r\n"
conn.Write([]byte(header))
conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
_, err = conn.Write([]byte(header))
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error writing header")
_, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error writing request")
data, err := io.ReadAll(conn)
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error reading connection data")
body := string(data)
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=%v", "proxy-protocol"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=1234"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=http"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=192.168.0.1"))
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=1234")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=http")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-for=192.168.0.1")
})
ginkgo.It("should respect proto passed by the PROXY Protocol server port", func() {
@ -96,17 +99,20 @@ var _ = framework.DescribeSetting("use-proxy-protocol", func() {
defer conn.Close()
header := "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n"
conn.Write([]byte(header))
conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
_, err = conn.Write([]byte(header))
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error writing header")
_, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error writing request")
data, err := io.ReadAll(conn)
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error reading connection data")
body := string(data)
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=%v", "proxy-protocol"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=443"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=https"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=192.168.0.1"))
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=443")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=https")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-for=192.168.0.1")
})
ginkgo.It("should enable PROXY Protocol for HTTPS", func() {
@ -146,10 +152,10 @@ var _ = framework.DescribeSetting("use-proxy-protocol", func() {
body := string(data)
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("host=%v", "proxy-protocol"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-port=1234"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-proto=https"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-scheme=https"))
assert.Contains(ginkgo.GinkgoT(), body, fmt.Sprintf("x-forwarded-for=192.168.0.1"))
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-port=1234")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-proto=https")
assert.Contains(ginkgo.GinkgoT(), body, "x-scheme=https")
assert.Contains(ginkgo.GinkgoT(), body, "x-forwarded-for=192.168.0.1")
})
ginkgo.It("should enable PROXY Protocol for TCP", func() {
@ -205,8 +211,11 @@ var _ = framework.DescribeSetting("use-proxy-protocol", func() {
defer conn.Close()
header := "PROXY TCP4 192.168.0.1 192.168.0.11 56324 8080\r\n"
conn.Write([]byte(header))
conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
_, err = conn.Write([]byte(header))
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error writing header")
_, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: proxy-protocol\r\n\r\n"))
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error writing request")
_, err = io.ReadAll(conn)
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error reading connection data")

View file

@ -34,7 +34,7 @@ import (
)
var _ = framework.IngressNginxDescribe("[Flag] enable-ssl-passthrough", func() {
f := framework.NewDefaultFramework("ssl-passthrough")
f := framework.NewDefaultFramework("ssl-passthrough", framework.WithHTTPBunEnabled())
ginkgo.BeforeEach(func() {
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
@ -86,7 +86,14 @@ var _ = framework.IngressNginxDescribe("[Flag] enable-ssl-passthrough", func() {
"nginx.ingress.kubernetes.io/ssl-passthrough": "true",
}
ingressDef := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, echoName, 80, annotations)
ingressDef := framework.NewSingleIngressWithTLS(host,
"/",
host,
[]string{host},
f.Namespace,
echoName,
80,
annotations)
tlsConfig, err := framework.CreateIngressTLSSecret(f.KubeClientSet,
ingressDef.Spec.TLS[0].Hosts,
ingressDef.Spec.TLS[0].SecretName,
@ -119,7 +126,17 @@ var _ = framework.IngressNginxDescribe("[Flag] enable-ssl-passthrough", func() {
Value: "/certs/tls.key",
},
}
f.NewDeploymentWithOpts("echopass", "ghcr.io/sharat87/httpbun:latest", 80, 1, nil, nil, envs, volumeMount, volume, false)
f.NewDeploymentWithOpts("echopass",
framework.HTTPBunImage,
80,
1,
nil,
nil,
envs,
volumeMount,
volume,
false)
f.EnsureIngress(ingressDef)
@ -133,7 +150,14 @@ var _ = framework.IngressNginxDescribe("[Flag] enable-ssl-passthrough", func() {
/* This one should not receive traffic as it does not contain passthrough annotation */
hostBad := "noannotationnopassthrough.com"
ingBad := f.EnsureIngress(framework.NewSingleIngressWithTLS(hostBad, "/", hostBad, []string{hostBad}, f.Namespace, echoName, 80, nil))
ingBad := f.EnsureIngress(framework.NewSingleIngressWithTLS(hostBad,
"/",
hostBad,
[]string{hostBad},
f.Namespace,
echoName,
80,
nil))
tlsConfigBad, err := framework.CreateIngressTLSSecret(f.KubeClientSet,
ingBad.Spec.TLS[0].Hosts,
ingBad.Spec.TLS[0].SecretName,

View file

@ -112,7 +112,7 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", f
f.UpdateNginxConfigMapData(hstsMaxAge, "86400")
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, fmt.Sprintf(`hsts_max_age = 86400,`))
return strings.Contains(server, `hsts_max_age = 86400,`)
})
f.HTTPTestClientWithTLSConfig(tlsConfig).
@ -131,7 +131,7 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", f
})
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, fmt.Sprintf(`hsts_include_subdomains = false,`))
return strings.Contains(server, `hsts_include_subdomains = false,`)
})
f.HTTPTestClientWithTLSConfig(tlsConfig).
@ -151,7 +151,7 @@ var _ = framework.DescribeSetting("[SSL] TLS protocols, ciphers and headers)", f
})
f.WaitForNginxConfiguration(func(server string) bool {
return strings.Contains(server, fmt.Sprintf(`hsts_preload = true,`))
return strings.Contains(server, `hsts_preload = true,`)
})
f.HTTPTestClientWithTLSConfig(tlsConfig).

View file

@ -73,7 +73,8 @@ var _ = framework.IngressNginxDescribe("[SSL] secret update", func() {
dummySecret.Data["some-key"] = []byte("some value")
f.KubeClientSet.CoreV1().Secrets(f.Namespace).Update(context.TODO(), dummySecret, metav1.UpdateOptions{})
_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace).Update(context.TODO(), dummySecret, metav1.UpdateOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "updating secret")
assert.NotContains(ginkgo.GinkgoT(), log, fmt.Sprintf("starting syncing of secret %v/dummy", f.Namespace))
assert.NotContains(ginkgo.GinkgoT(), log, fmt.Sprintf("error obtaining PEM from secret %v/dummy", f.Namespace))

View file

@ -71,7 +71,7 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() {
f.NewEchoDeployment()
ing := f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil))
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil))
f.WaitForNginxConfiguration(
func(cfg string) bool {
@ -84,7 +84,7 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() {
err = cmd.Process.Kill()
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error terminating kubectl proxy")
ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error getting %s/%v Ingress", f.Namespace, host)
ing.Status.LoadBalancer.Ingress = []v1.IngressLoadBalancerIngress{}

View file

@ -27,7 +27,7 @@ export default function () {
const params = {
headers: {'host': 'test.ingress-nginx-controller.ga'},
};
// httpbin.org documents these requests
// httpbun.com documents these requests
const req1 = {
method: 'GET',
url: 'http://test.ingress-nginx-controller.ga/ip',

View file

@ -41,7 +41,7 @@ SHDICT_ARGS=(
)
if [ $# -eq 0 ]; then
resty "${SHDICT_ARGS[@]}" ./rootfs/etc/nginx/lua/test/ ./rootfs/etc/nginx/lua/plugins/**/test
resty "${SHDICT_ARGS[@]}" ./rootfs/etc/nginx/lua/test/ ./rootfs/etc/nginx/lua/plugins/**/test ${BUSTED_ARGS}
else
resty "${SHDICT_ARGS[@]}" $@
resty "${SHDICT_ARGS[@]}" $@ ${BUSTED_ARGS}
fi