Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Sandor Szombat 2020-02-14 07:27:56 +01:00
commit 137156ca8b
79 changed files with 412 additions and 392 deletions

2
.gitignore vendored
View file

@ -51,3 +51,5 @@ cover.out
# secret terraform variables
build/images/nginx/aws.tfvars
build/images/nginx/env.tfvars
images/fastcgi-helloserver/rootfs/fastcgi-helloserver

View file

@ -42,7 +42,7 @@ endif
# Allow limiting the scope of the e2e tests. By default run everything
FOCUS ?= .*
# number of parallel test
E2E_NODES ?= 12
E2E_NODES ?= 15
# slow test only if takes > 50s
SLOW_E2E_THRESHOLD ?= 50
# run e2e test suite with tests that check for memory leaks? (default is false)
@ -258,7 +258,7 @@ misspell: check-go-version ## Check for spelling errors.
.PHONY: kind-e2e-test
kind-e2e-test: check-go-version ## Run e2e tests using kind.
@DIND_TASKS=0 test/e2e/run.sh
@test/e2e/run.sh
.PHONY: run-ingress-controller
run-ingress-controller: ## Run the ingress controller locally using a kubectl proxy connection.
@ -272,7 +272,7 @@ check-go-version:
init-docker-buildx:
ifeq ($(DIND_TASKS),)
ifneq ($(shell docker buildx 2>&1 >/dev/null; echo $?),)
$(error "buildx not vailable. Docker 19.03 or higher is required")
$(error "buildx not available. Docker 19.03 or higher is required with experimental features enabled")
endif
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
docker buildx create --name ingress-nginx --use || true

View file

@ -67,7 +67,7 @@ echo ${docker_password} | docker login -u ${docker_username} --password-stdin qu
curl -sL -o /usr/local/bin/gimme https://raw.githubusercontent.com/travis-ci/gimme/master/gimme
chmod +x /usr/local/bin/gimme
eval "$(gimme 1.13.7)"
eval "$(gimme 1.13.8)"
export GOPATH="/tmp/go"

View file

@ -70,7 +70,7 @@ echo ${docker_password} | docker login -u ${docker_username} --password-stdin qu
curl -sL -o /usr/local/bin/gimme https://raw.githubusercontent.com/travis-ci/gimme/master/gimme
chmod +x /usr/local/bin/gimme
eval "$(gimme 1.13.7)"
eval "$(gimme 1.13.8)"
git clone https://github.com/kubernetes/ingress-nginx

View file

@ -34,7 +34,7 @@ function cleanup {
}
trap cleanup EXIT
E2E_IMAGE=quay.io/kubernetes-ingress-controller/e2e:v02042020-08e19a278
E2E_IMAGE=quay.io/kubernetes-ingress-controller/e2e:v02132020-0e2ca1cc0
DOCKER_OPTS=${DOCKER_OPTS:-}

View file

@ -0,0 +1,28 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
spec:
template:
spec:
containers:
- name: nginx-ingress-controller
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 5

View file

@ -9,3 +9,4 @@ images:
newTag: dev
patchesStrategicMerge:
- service-hostport.yaml
- deployment.yaml

View file

@ -19,6 +19,8 @@ cd ingress-nginx
### Initial developer environment build
Ensure docker experimental features option is enabled for [buildx](https://docs.docker.com/buildx/working-with-buildx/)
```
$ make dev-env
```

View file

@ -26,8 +26,8 @@ docker-build:
--progress plain \
--build-arg K8S_RELEASE=v1.15.7 \
--build-arg ETCD_VERSION=v3.3.18 \
--build-arg GOLANG_VERSION=1.13.7 \
--build-arg GOLANG_SHA=e4ad42cc5f5c19521fbbbde3680995f2546110b5c6aa2b48c3754ff7af9b41f4 \
--build-arg GOLANG_VERSION=1.13.8 \
--build-arg GOLANG_SHA=b13bf04633d4d8cf53226ebeaace8d4d2fd07ae6fa676d0844a688339debec34 \
--build-arg RESTY_CLI_VERSION=0.25rc2 \
--build-arg RESTY_CLI_SHA=a38d850441384fa037a5922ca012dcce8708d0e4abe34ad2fe4164a01b28bdfb \
-t $(IMAGE):$(TAG) .

View file

@ -952,6 +952,8 @@ stream {
location {{ buildAuthSignURLLocation $location.Path $externalAuth.SigninURL }} {
internal;
add_header Set-Cookie $auth_cookie;
return 302 {{ buildAuthSignURL $externalAuth.SigninURL }};
}
{{ end }}

View file

@ -1,4 +1,4 @@
FROM quay.io/kubernetes-ingress-controller/e2e:v02042020-08e19a278 AS BASE
FROM quay.io/kubernetes-ingress-controller/e2e:v02132020-0e2ca1cc0 AS BASE
FROM alpine:3.11

View file

@ -39,6 +39,7 @@ ginkgo_args=(
"-trace"
"-slowSpecThreshold=${SLOW_E2E_THRESHOLD}"
"-r"
"-timeout=45m" # Suite timeout should be lower than Prow job timeout to avoid abrupt termination
)
echo -e "${BGREEN}Running e2e test suite (FOCUS=${FOCUS})...${NC}"

View file

@ -40,9 +40,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Affinity/Sticky Sessions",
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set sticky cookie SERVERID", func() {
host := "sticky.foo.com"
annotations := map[string]string{

View file

@ -34,9 +34,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Alias", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should return status code 200 for host 'foo' and 404 for 'bar'", func() {
host := "foo"
annotations := map[string]string{}

View file

@ -33,9 +33,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Approot", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should redirect to /foo", func() {
host := "approot.bar.com"

View file

@ -332,6 +332,52 @@ var _ = framework.IngressNginxDescribe("Annotations - Auth", func() {
})
})
It("retains cookie set by external authentication server", func() {
Skip("Skipping test until refactoring")
// TODO: this test should look like https://gist.github.com/aledbf/250645d76c080677c695929273f8fd22
host := "auth"
f.NewHttpbinDeployment()
var httpbinIP string
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
Expect(err).NotTo(HaveOccurred())
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(framework.HTTPBinService, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
httpbinIP = 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-signin": "http://$host/auth/start",
}
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host, func(server string) bool {
return Expect(server).Should(ContainSubstring("server_name auth"))
})
resp, _, errs := gorequest.New().
Get(f.GetURL(framework.HTTP)).
Retry(10, 1*time.Second, http.StatusNotFound).
Set("Host", host).
Param("a", "b").
Param("c", "d").
End()
for _, err := range errs {
Expect(err).NotTo(HaveOccurred())
}
framework.Logf("Cookie: %v", resp.Header)
Expect(resp.Header.Get("Set-Cookie")).Should(ContainSubstring("alma=armud"))
})
Context("when external authentication is configured", func() {
host := "auth"

View file

@ -35,9 +35,6 @@ var _ = framework.IngressNginxDescribe("Annotations - AuthTLS", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set valid auth-tls-secret", func() {
host := "authtls.foo.com"
nameSpace := f.Namespace

View file

@ -29,9 +29,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Backendprotocol", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set backend protocol to https:// and use proxy_pass", func() {
host := "backendprotocol.foo.com"
annotations := map[string]string{

View file

@ -29,9 +29,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Client-Body-Buffer-Size",
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set client_body_buffer_size to 1000", func() {
host := "proxy.foo.com"
annotations := map[string]string{

View file

@ -34,9 +34,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Connection", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("set connection header to keep-alive", func() {
host := "connection.foo.com"
annotations := map[string]string{

View file

@ -33,9 +33,6 @@ var _ = framework.IngressNginxDescribe("Annotations - CORS", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should enable cors", func() {
host := "cors.foo.com"
annotations := map[string]string{

View file

@ -38,9 +38,6 @@ var _ = framework.IngressNginxDescribe("Annotations - custom-http-errors", func(
f.NewEchoDeploymentWithReplicas(1)
})
AfterEach(func() {
})
It("configures Nginx correctly", func() {
host := "customerrors.foo.com"

View file

@ -33,9 +33,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Forcesslredirect", func()
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should redirect to https", func() {
host := "forcesslredirect.bar.com"

View file

@ -36,9 +36,6 @@ var _ = framework.IngressNginxDescribe("Annotations - from-to-www-redirect", fun
f.NewEchoDeploymentWithReplicas(1)
})
AfterEach(func() {
})
It("should redirect from www HTTP to HTTP", func() {
By("setting up server for redirect from www")
host := "fromtowwwredirect.bar.com"

View file

@ -65,15 +65,17 @@ var _ = framework.IngressNginxDescribe("Annotations - GRPC", func() {
})
It("should return OK for service with backend protocol GRPC", func() {
f.NewGRPCBinDeployment()
host := "echo"
svc := &core.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "grpcbin",
Name: "grpcbin-test",
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: "grpcb.in",
ExternalName: fmt.Sprintf("grpcbin.%v.svc.cluster.local", f.Namespace),
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
@ -91,7 +93,7 @@ var _ = framework.IngressNginxDescribe("Annotations - GRPC", func() {
"nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
}
ing := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, "grpcbin", 9000, annotations)
ing := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, "grpcbin-test", 9000, annotations)
f.EnsureIngress(ing)
@ -121,15 +123,19 @@ var _ = framework.IngressNginxDescribe("Annotations - GRPC", func() {
})
It("should return OK for service with backend protocol GRPCS", func() {
Skip("GRPCS test temporarily disabled")
f.NewGRPCBinDeployment()
host := "echo"
svc := &core.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "grpcbin",
Name: "grpcbin-test",
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
ExternalName: "grpcb.in",
ExternalName: fmt.Sprintf("grpcbin.%v.svc.cluster.local", f.Namespace),
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
@ -145,15 +151,15 @@ var _ = framework.IngressNginxDescribe("Annotations - GRPC", func() {
annotations := map[string]string{
"nginx.ingress.kubernetes.io/backend-protocol": "GRPCS",
"nginx.ingress.kubernetes.io/configuration-snippet": `
"nginx.ingress.kubernetes.io/configuration-snippet": fmt.Sprintf(`
# without this setting NGINX sends echo instead
grpc_ssl_name grpcb.in;
grpc_ssl_name grpcbin.%v.svc.cluster.local;
grpc_ssl_server_name on;
grpc_ssl_ciphers HIGH:!aNULL:!MD5;
`,
`, f.Namespace),
}
ing := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, "grpcbin", 9001, annotations)
ing := framework.NewSingleIngressWithTLS(host, "/", host, []string{host}, f.Namespace, "grpcbin-test", 9001, annotations)
f.EnsureIngress(ing)
f.WaitForNginxServer(host,

View file

@ -29,9 +29,6 @@ var _ = framework.IngressNginxDescribe("Annotations - HTTP2 Push Preload", func(
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("enable the http2-push-preload directive", func() {
host := "http2pp.foo.com"
annotations := map[string]string{

View file

@ -74,7 +74,7 @@ var _ = framework.IngressNginxDescribe("Annotations - influxdb", func() {
Expect(len(errs)).Should(Equal(0))
Expect(res.StatusCode).Should(Equal(http.StatusOK))
time.Sleep(5 * time.Second)
time.Sleep(10 * time.Second)
var measurements string
var err error
@ -89,7 +89,7 @@ var _ = framework.IngressNginxDescribe("Annotations - influxdb", func() {
Expect(err).NotTo(HaveOccurred())
var results map[string][]map[string]interface{}
jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(measurements), &results)
_ = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(measurements), &results)
Expect(len(measurements)).ShouldNot(Equal(0))
for _, elem := range results["results"] {
@ -102,7 +102,7 @@ var _ = framework.IngressNginxDescribe("Annotations - influxdb", func() {
func createInfluxDBService(f *framework.Framework) *corev1.Service {
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "inflxudb-svc",
Name: "inflxudb",
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{Ports: []corev1.ServicePort{
@ -114,7 +114,7 @@ func createInfluxDBService(f *framework.Framework) *corev1.Service {
},
},
Selector: map[string]string{
"app": "influxdb-svc",
"app": "influxdb",
},
},
}
@ -134,7 +134,7 @@ func createInfluxDBIngress(f *framework.Framework, host, service string, port in
func extractInfluxDBMeasurements(f *framework.Framework) (string, error) {
l, err := f.KubeClientSet.CoreV1().Pods(f.Namespace).List(metav1.ListOptions{
LabelSelector: "app=influxdb-svc",
LabelSelector: "app=influxdb",
})
if err != nil {
return "", err

View file

@ -31,9 +31,6 @@ var _ = framework.IngressNginxDescribe("Annotations - IPWhiteList", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set valid ip whitelist range", func() {
host := "ipwhitelist.foo.com"
nameSpace := f.Namespace

View file

@ -30,9 +30,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Log", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("set access_log off", func() {
host := "log.foo.com"
annotations := map[string]string{

View file

@ -33,9 +33,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Mirror", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should set mirror-target to http://localhost/mirror", func() {
annotations := map[string]string{
"nginx.ingress.kubernetes.io/mirror-target": "http://localhost/mirror",

View file

@ -30,9 +30,6 @@ var _ = framework.IngressNginxDescribe("Annotations - ModSecurityLocation", func
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should enable modsecurity", func() {
host := "modsecurity.foo.com"
nameSpace := f.Namespace

View file

@ -33,9 +33,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Proxy", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set proxy_redirect to off", func() {
annotations := map[string]string{
"nginx.ingress.kubernetes.io/proxy-redirect-from": "off",

View file

@ -32,9 +32,6 @@ var _ = framework.IngressNginxDescribe("Annotations - ProxySSL", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should set valid proxy-ssl-secret", func() {
host := "proxyssl.foo.com"
annotations := map[string]string{

View file

@ -37,12 +37,6 @@ func noRedirectPolicyFunc(gorequest.Request, []gorequest.Request) error {
var _ = framework.IngressNginxDescribe("Annotations - Redirect", func() {
f := framework.NewDefaultFramework("redirect")
BeforeEach(func() {
})
AfterEach(func() {
})
It("should respond with a standard redirect code", func() {
By("setting permanent-redirect annotation")

View file

@ -36,9 +36,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Rewrite", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should write rewrite logs", func() {
By("setting enable-rewrite-log annotation")

View file

@ -37,9 +37,6 @@ var _ = framework.IngressNginxDescribe("Annotations - SATISFY", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should configure satisfy directive correctly", func() {
host := "satisfy"
annotationKey := "nginx.ingress.kubernetes.io/satisfy"

View file

@ -31,9 +31,6 @@ var _ = framework.IngressNginxDescribe("Annotations - ServerSnippet", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It(`add valid directives to server via server snippet"`, func() {
host := "serversnippet.foo.com"
annotations := map[string]string{

View file

@ -29,9 +29,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Configurationsnippet", fun
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It(`set snippet "more_set_headers "Request-Id: $req_id";" in all locations"`, func() {
host := "configurationsnippet.foo.com"
annotations := map[string]string{

View file

@ -30,9 +30,6 @@ var _ = framework.IngressNginxDescribe("Annotations - SSL CIPHERS", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("should change ssl ciphers", func() {
host := "ciphers.foo.com"
annotations := map[string]string{

View file

@ -79,9 +79,6 @@ var _ = framework.IngressNginxDescribe("Annotations - UpstreamHashBy", func() {
f.NewEchoDeploymentWithReplicas(6)
})
AfterEach(func() {
})
It("should connect to the same pod", func() {
annotations := map[string]string{
"nginx.ingress.kubernetes.io/upstream-hash-by": "$request_uri",
@ -101,6 +98,5 @@ var _ = framework.IngressNginxDescribe("Annotations - UpstreamHashBy", func() {
podMap := startIngress(f, annotations)
Expect(len(podMap)).Should(Equal(3))
})
})

View file

@ -29,9 +29,6 @@ var _ = framework.IngressNginxDescribe("Annotations - Upstreamvhost", func() {
f.NewEchoDeploymentWithReplicas(2)
})
AfterEach(func() {
})
It("set host to upstreamvhost.bar.com", func() {
host := "upstreamvhost.foo.com"
annotations := map[string]string{

View file

@ -32,9 +32,6 @@ var _ = framework.IngressNginxDescribe("Annotations - X-Forwarded-Prefix", func(
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should set the X-Forwarded-Prefix to the annotation value", func() {
host := "xfp.baz.com"
annotations := map[string]string{

View file

@ -34,9 +34,6 @@ var _ = framework.IngressNginxDescribe("Debug Tool", func() {
f.NewEchoDeploymentWithReplicas(1)
})
AfterEach(func() {
})
It("should list the backend servers", func() {
annotations := map[string]string{}

View file

@ -30,12 +30,6 @@ import (
var _ = framework.IngressNginxDescribe("Default backend", func() {
f := framework.NewDefaultFramework("default-backend")
BeforeEach(func() {
})
AfterEach(func() {
})
It("should return 404 sending requests when only a default backend is running", func() {
testCases := []struct {
Name string

View file

@ -29,12 +29,6 @@ import (
var _ = framework.IngressNginxDescribe("Default backend - SSL", func() {
f := framework.NewDefaultFramework("default-backend")
BeforeEach(func() {
})
AfterEach(func() {
})
It("should return a self generated SSL certificate", func() {
By("checking SSL Certificate using the NGINX IP address")
resp, _, errs := gorequest.New().

View file

@ -38,9 +38,6 @@ var _ = framework.IngressNginxDescribe("Default backend with hosts", func() {
f.NewEchoDeploymentWithReplicas(1)
})
AfterEach(func() {
})
It("should apply the annotation to the default backend", func() {
annotations := map[string]string{
"nginx.ingress.kubernetes.io/proxy-buffer-size": "8k",

View file

@ -66,9 +66,3 @@ func RunE2ETests(t *testing.T) {
framework.Logf("Starting e2e run %q on Ginkgo node %d", framework.RunID, config.GinkgoConfig.ParallelNode)
ginkgo.RunSpecs(t, "nginx-ingress-controller e2e suite")
}
var _ = ginkgo.SynchronizedAfterSuite(func() {
// Run on all Ginkgo nodes
framework.Logf("Running AfterSuite actions on all nodes")
framework.RunCleanupActions()
}, func() {})

View file

@ -1,61 +0,0 @@
/*
Copyright 2016 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 "sync"
// CleanupActionHandle is a handle used to perform a cleanup action.
type CleanupActionHandle *int
var cleanupActionsLock sync.Mutex
var cleanupActions = map[CleanupActionHandle]func(){}
// AddCleanupAction installs a function that will be called in the event of the
// whole test being terminated. This allows arbitrary pieces of the overall
// test to hook into SynchronizedAfterSuite().
func AddCleanupAction(fn func()) CleanupActionHandle {
p := CleanupActionHandle(new(int))
cleanupActionsLock.Lock()
defer cleanupActionsLock.Unlock()
cleanupActions[p] = fn
return p
}
// RemoveCleanupAction removes a function that was installed by AddCleanupAction.
func RemoveCleanupAction(p CleanupActionHandle) {
cleanupActionsLock.Lock()
defer cleanupActionsLock.Unlock()
delete(cleanupActions, p)
}
// RunCleanupActions runs all functions installed by AddCleanupAction. It does
// not remove them (see RemoveCleanupAction) but it does run unlocked, so they
// may remove themselves.
func RunCleanupActions() {
list := []func(){}
func() {
cleanupActionsLock.Lock()
defer cleanupActionsLock.Unlock()
for _, fn := range cleanupActions {
list = append(list, fn)
}
}()
// Run unlocked.
for _, fn := range list {
fn()
}
}

View file

@ -59,8 +59,7 @@ func (f *Framework) NewEchoDeploymentWithNameAndReplicas(name string, replicas i
[]corev1.Volume{},
)
d := f.EnsureDeployment(deployment)
Expect(d).NotTo(BeNil(), "expected a deployment but none returned")
f.EnsureDeployment(deployment)
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
@ -82,8 +81,7 @@ func (f *Framework) NewEchoDeploymentWithNameAndReplicas(name string, replicas i
},
}
s := f.EnsureService(service)
Expect(s).NotTo(BeNil(), "expected a service but none returned")
f.EnsureService(service)
err := WaitForEndpoints(f.KubeClientSet, DefaultTimeout, name, f.Namespace, replicas)
Expect(err).NotTo(HaveOccurred(), "failed to wait for endpoints to become ready")
@ -144,8 +142,7 @@ server {
},
)
d := f.EnsureDeployment(deployment)
Expect(d).NotTo(BeNil(), "expected a deployment but none returned")
f.EnsureDeployment(deployment)
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
@ -167,13 +164,105 @@ server {
},
}
s := f.EnsureService(service)
Expect(s).NotTo(BeNil(), "expected a service but none returned")
f.EnsureService(service)
err = WaitForEndpoints(f.KubeClientSet, DefaultTimeout, SlowEchoService, f.Namespace, 1)
Expect(err).NotTo(HaveOccurred(), "failed to wait for endpoints to become ready")
}
// NewGRPCBinDeployment creates a new deployment of the
// moul/grpcbin image for GRPC tests
func (f *Framework) NewGRPCBinDeployment() {
name := "grpcbin"
probe := &corev1.Probe{
InitialDelaySeconds: 5,
PeriodSeconds: 10,
SuccessThreshold: 1,
TimeoutSeconds: 1,
Handler: corev1.Handler{
TCPSocket: &corev1.TCPSocketAction{
Port: intstr.FromInt(9000),
},
},
}
sel := map[string]string{
"app": name,
}
f.EnsureDeployment(&appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: f.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: NewInt32(1),
Selector: &metav1.LabelSelector{
MatchLabels: sel,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: sel,
},
Spec: corev1.PodSpec{
TerminationGracePeriodSeconds: NewInt64(0),
Containers: []corev1.Container{
{
Name: name,
Image: "moul/grpcbin",
Env: []corev1.EnvVar{},
Ports: []corev1.ContainerPort{
{
Name: "insecure",
ContainerPort: 9000,
Protocol: corev1.ProtocolTCP,
},
{
Name: "secure",
ContainerPort: 9001,
Protocol: corev1.ProtocolTCP,
},
},
ReadinessProbe: probe,
LivenessProbe: probe,
},
},
},
},
},
})
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: f.Namespace,
},
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "insecure",
Port: 9000,
TargetPort: intstr.FromInt(9000),
Protocol: corev1.ProtocolTCP,
},
{
Name: "secure",
Port: 9001,
TargetPort: intstr.FromInt(9000),
Protocol: corev1.ProtocolTCP,
},
},
Selector: sel,
},
}
f.EnsureService(service)
err := WaitForEndpoints(f.KubeClientSet, DefaultTimeout, name, f.Namespace, 1)
Expect(err).NotTo(HaveOccurred(), "failed to wait for endpoints to become ready")
}
func newDeployment(name, namespace, image string, port int32, replicas int32, command []string,
volumeMounts []corev1.VolumeMount, volumes []corev1.Volume) *appsv1.Deployment {
probe := &corev1.Probe{
@ -247,8 +336,7 @@ func (f *Framework) NewHttpbinDeployment() {
func (f *Framework) NewDeployment(name, image string, port int32, replicas int32) {
deployment := newDeployment(name, f.Namespace, image, port, replicas, nil, nil, nil)
d := f.EnsureDeployment(deployment)
Expect(d).NotTo(BeNil(), "expected a deployment but none returned")
f.EnsureDeployment(deployment)
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
@ -270,8 +358,7 @@ func (f *Framework) NewDeployment(name, image string, port int32, replicas int32
},
}
s := f.EnsureService(service)
Expect(s).NotTo(BeNil(), "expected a service but none returned")
f.EnsureService(service)
err := WaitForEndpoints(f.KubeClientSet, DefaultTimeout, name, f.Namespace, int(replicas))
Expect(err).NotTo(HaveOccurred(), "failed to wait for endpoints to become ready")
@ -295,7 +382,10 @@ func (f *Framework) ScaleDeploymentToZero(name string) {
Expect(d).NotTo(BeNil(), "expected a deployment but none returned")
d.Spec.Replicas = NewInt32(0)
f.EnsureDeployment(d)
d, err = f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(d)
Expect(err).NotTo(HaveOccurred(), "failed to get a deployment")
Expect(d).NotTo(BeNil(), "expected a deployment but none returned")
err = WaitForEndpoints(f.KubeClientSet, DefaultTimeout, name, f.Namespace, 0)
Expect(err).NotTo(HaveOccurred(), "failed to wait for no endpoints")

View file

@ -87,8 +87,34 @@ func (f *Framework) ExecCommand(pod *corev1.Pod, command string) (string, error)
return execOut.String(), nil
}
// NewIngressController deploys a new NGINX Ingress controller in a namespace
func (f *Framework) NewIngressController(namespace string, namespaceOverlay string) error {
// NamespaceContent executes a kubectl command that returns information about
// pods, services, endpoint and deployments inside the current namespace
func (f *Framework) NamespaceContent() (string, error) {
var (
execOut bytes.Buffer
execErr bytes.Buffer
)
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("%v get pods,services,endpoints,deployments --namespace %s", KubectlPath, f.Namespace))
cmd.Stdout = &execOut
cmd.Stderr = &execErr
err := cmd.Run()
if err != nil {
return "", fmt.Errorf("could not execute '%s %s': %v", cmd.Path, cmd.Args, err)
}
eout := strings.TrimSpace(execErr.String())
if len(eout) > 0 {
return "", fmt.Errorf("stderr: %v", eout)
}
return execOut.String(), nil
}
// newIngressController deploys a new NGINX Ingress controller in a namespace
func (f *Framework) newIngressController(namespace string, namespaceOverlay string) error {
// Creates an nginx deployment
cmd := exec.Command("./wait-for-nginx.sh", namespace, namespaceOverlay)
out, err := cmd.CombinedOutput()

View file

@ -74,7 +74,6 @@ func (f *Framework) NewNewFastCGIHelloServerDeploymentWithReplicas(replicas int3
}
d := f.EnsureDeployment(deployment)
Expect(d).NotTo(BeNil(), "expected a fastcgi-helloserver deployment")
err := WaitForPodsReady(f.KubeClientSet, DefaultTimeout, int(replicas), f.Namespace, metav1.ListOptions{
LabelSelector: fields.SelectorFromSet(fields.Set(d.Spec.Template.ObjectMeta.Labels)).String(),

View file

@ -31,8 +31,8 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/klog"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
)
// RequestScheme define a scheme used in a test request.
@ -58,11 +58,6 @@ type Framework struct {
KubeConfig *restclient.Config
APIExtensionsClientSet apiextcs.Interface
// To make sure that this framework cleans up after itself, no matter what,
// we install a Cleanup action before each test and clear it after. If we
// should abort, the AfterSuite hook should run all Cleanup actions.
cleanupHandle CleanupActionHandle
Namespace string
}
@ -73,82 +68,89 @@ func NewDefaultFramework(baseName string) *Framework {
BaseName: baseName,
}
BeforeEach(f.BeforeEach)
AfterEach(f.AfterEach)
ginkgo.BeforeEach(f.BeforeEach)
ginkgo.AfterEach(f.AfterEach)
return f
}
// BeforeEach gets a client and makes a namespace.
func (f *Framework) BeforeEach() {
f.cleanupHandle = AddCleanupAction(f.AfterEach)
By("Creating a kubernetes client")
kubeConfig, err := restclient.InClusterConfig()
if err != nil {
panic(err.Error())
}
Expect(err).NotTo(HaveOccurred())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
f.KubeConfig = kubeConfig
f.KubeClientSet, err = kubernetes.NewForConfig(kubeConfig)
Expect(err).NotTo(HaveOccurred())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
By("Building a namespace api object")
ingressNamespace, err := CreateKubeNamespace(f.BaseName, f.KubeClientSet)
Expect(err).NotTo(HaveOccurred())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
f.Namespace = ingressNamespace
By("Starting new ingress controller")
err = f.NewIngressController(f.Namespace, f.BaseName)
Expect(err).NotTo(HaveOccurred())
err = f.newIngressController(f.Namespace, f.BaseName)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = WaitForPodsReady(f.KubeClientSet, DefaultTimeout, 1, f.Namespace, metav1.ListOptions{
LabelSelector: "app.kubernetes.io/name=ingress-nginx",
})
Expect(err).NotTo(HaveOccurred())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
}
// AfterEach deletes the namespace, after reading its events.
func (f *Framework) AfterEach() {
RemoveCleanupAction(f.cleanupHandle)
By("Waiting for test namespace to no longer exist")
err := DeleteKubeNamespace(f.KubeClientSet, f.Namespace)
Expect(err).NotTo(HaveOccurred())
if CurrentGinkgoTestDescription().Failed {
log, err := f.NginxLogs()
Expect(err).ToNot(HaveOccurred())
By("Dumping NGINX logs after a failure running a test")
Logf("%v", log)
if ginkgo.CurrentGinkgoTestDescription().Failed {
pod, err := getIngressNGINXPod(f.Namespace, f.KubeClientSet)
if err != nil {
Logf("Unexpected error searching for ingress controller pod: %v", err)
return
}
cmd := fmt.Sprintf("cat /etc/nginx/nginx.conf")
o, err := f.ExecCommand(pod, cmd)
if err != nil {
Logf("Unexpected error obtaining nginx.conf file: %v", err)
return
}
By("Dumping NGINX configuration after a failure running a test")
ginkgo.By("Dumping NGINX configuration after failure")
Logf("%v", o)
log, err := f.NginxLogs()
if err != nil {
Logf("Unexpected error obtaining NGINX logs: %v", err)
return
}
ginkgo.By("Dumping NGINX logs")
Logf("%v", log)
o, err = f.NamespaceContent()
if err != nil {
Logf("Unexpected error obtaining namespace information: %v", err)
return
}
ginkgo.By("Dumping namespace content")
Logf("%v", o)
}
err := DeleteKubeNamespace(f.KubeClientSet, f.Namespace)
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error deleting namespace %v", f.Namespace)
}
// IngressNginxDescribe wrapper function for ginkgo describe. Adds namespacing.
func IngressNginxDescribe(text string, body func()) bool {
return Describe("[ingress-nginx] "+text, body)
return ginkgo.Describe("[ingress-nginx] "+text, body)
}
// MemoryLeakIt is wrapper function for ginkgo It. Adds "[MemoryLeak]" tag and makes static analysis easier.
func MemoryLeakIt(text string, body interface{}, timeout ...float64) bool {
return It(text+" [MemoryLeak]", body, timeout...)
return ginkgo.It(text+" [MemoryLeak]", body, timeout...)
}
// GetNginxIP returns the number of TCP port where NGINX is running
@ -157,7 +159,7 @@ func (f *Framework) GetNginxIP() string {
CoreV1().
Services(f.Namespace).
Get("ingress-nginx", metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred(), "unexpected error obtaining NGINX IP address")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error obtaining NGINX IP address")
return s.Spec.ClusterIP
}
@ -167,7 +169,7 @@ func (f *Framework) GetNginxPodIP() []string {
CoreV1().
Endpoints(f.Namespace).
Get("ingress-nginx", metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred(), "unexpected error obtaining NGINX IP address")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error obtaining NGINX IP address")
eips := make([]string, 0)
for _, s := range e.Subsets {
for _, a := range s.Addresses {
@ -187,14 +189,14 @@ func (f *Framework) GetURL(scheme RequestScheme) string {
// WaitForNginxServer waits until the nginx configuration contains a particular server section
func (f *Framework) WaitForNginxServer(name string, matcher func(cfg string) bool) {
err := wait.Poll(Poll, DefaultTimeout, f.matchNginxConditions(name, matcher))
Expect(err).NotTo(HaveOccurred(), "unexpected error waiting for nginx server condition/s")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error waiting for nginx server condition/s")
time.Sleep(5 * time.Second)
}
// WaitForNginxConfiguration waits until the nginx configuration contains a particular configuration
func (f *Framework) WaitForNginxConfiguration(matcher func(cfg string) bool) {
err := wait.Poll(Poll, DefaultTimeout, f.matchNginxConditions("", matcher))
Expect(err).NotTo(HaveOccurred(), "unexpected error waiting for nginx server condition/s")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error waiting for nginx server condition/s")
time.Sleep(5 * time.Second)
}
@ -236,7 +238,7 @@ func (f *Framework) matchNginxConditions(name string, matcher func(cfg string) b
}
var match bool
errs := InterceptGomegaFailures(func() {
errs := gomega.InterceptGomegaFailures(func() {
if klog.V(10) && len(o) > 0 {
klog.Infof("nginx.conf:\n%v", o)
}
@ -299,8 +301,8 @@ func (f *Framework) SetNginxConfigMapData(cmData map[string]string) {
func (f *Framework) SetConfigMapData(name string, cmData map[string]string) {
config, err := f.getConfigMap(name)
Expect(err).NotTo(HaveOccurred())
Expect(config).NotTo(BeNil(), "expected a configmap but none returned")
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(config).NotTo(gomega.BeNil(), "expected a configmap but none returned")
config.Data = cmData
@ -308,7 +310,7 @@ func (f *Framework) SetConfigMapData(name string, cmData map[string]string) {
CoreV1().
ConfigMaps(f.Namespace).
Update(config)
Expect(err).NotTo(HaveOccurred())
gomega.Expect(err).NotTo(gomega.HaveOccurred())
time.Sleep(5 * time.Second)
}
@ -321,13 +323,13 @@ func (f *Framework) CreateConfigMap(name string, data map[string]string) {
},
Data: data,
})
Expect(err).NotTo(HaveOccurred(), "failed to create configMap")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "failed to create configMap")
}
// UpdateNginxConfigMapData updates single field in ingress-nginx's nginx-configuration map data
func (f *Framework) UpdateNginxConfigMapData(key string, value string) {
config, err := f.GetNginxConfigMapData()
Expect(err).NotTo(HaveOccurred(), "unexpected error reading configmap")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error reading configmap")
config[key] = value
@ -340,10 +342,10 @@ func (f *Framework) UpdateNginxConfigMapData(key string, value string) {
func (f *Framework) DeleteNGINXPod(grace int64) {
ns := f.Namespace
pod, err := getIngressNGINXPod(ns, f.KubeClientSet)
Expect(err).NotTo(HaveOccurred(), "expected ingress nginx pod to be running")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "expected ingress nginx pod to be running")
err = f.KubeClientSet.CoreV1().Pods(ns).Delete(pod.GetName(), metav1.NewDeleteOptions(grace))
Expect(err).NotTo(HaveOccurred(), "unexpected error deleting ingress nginx pod")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error deleting ingress nginx pod")
err = wait.Poll(Poll, DefaultTimeout, func() (bool, error) {
pod, err := getIngressNGINXPod(ns, f.KubeClientSet)
@ -352,7 +354,7 @@ func (f *Framework) DeleteNGINXPod(grace int64) {
}
return pod.GetName() != "", nil
})
Expect(err).NotTo(HaveOccurred(), "unexpected error while waiting for ingress nginx pod to come up again")
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "unexpected error while waiting for ingress nginx pod to come up again")
}
// UpdateDeployment runs the given updateFunc on the deployment and waits for it to be updated

View file

@ -74,7 +74,6 @@ func (f *Framework) NewNewGRPCFortuneTellerDeploymentWithReplicas(replicas int32
}
d := f.EnsureDeployment(deployment)
Expect(d).NotTo(BeNil(), "expected a fortune-teller deployment")
err := WaitForPodsReady(f.KubeClientSet, DefaultTimeout, int(replicas), f.Namespace, metav1.ListOptions{
LabelSelector: fields.SelectorFromSet(fields.Set(d.Spec.Template.ObjectMeta.Labels)).String(),

View file

@ -75,20 +75,20 @@ func (f *Framework) NewInfluxDBDeployment() {
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: "influxdb-svc",
Name: "influxdb",
Namespace: f.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: NewInt32(1),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "influxdb-svc",
"app": "influxdb",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "influxdb-svc",
"app": "influxdb",
},
},
Spec: corev1.PodSpec{
@ -107,7 +107,7 @@ func (f *Framework) NewInfluxDBDeployment() {
},
Containers: []corev1.Container{
{
Name: "influxdb-svc",
Name: "influxdb",
Image: "docker.io/influxdb:1.5",
Env: []corev1.EnvVar{},
Command: []string{"influxd", "-config", "/influxdb-config/influxd.conf"},
@ -136,7 +136,6 @@ func (f *Framework) NewInfluxDBDeployment() {
}
d := f.EnsureDeployment(deployment)
Expect(d).NotTo(BeNil(), "unexpected error creating deployment for influxdb")
err = WaitForPodsReady(f.KubeClientSet, DefaultTimeout, 1, f.Namespace, metav1.ListOptions{
LabelSelector: fields.SelectorFromSet(fields.Set(d.Spec.Template.ObjectMeta.Labels)).String(),

View file

@ -26,9 +26,11 @@ import (
appsv1 "k8s.io/api/apps/v1"
api "k8s.io/api/core/v1"
core "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1beta1"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/util/retry"
@ -37,18 +39,10 @@ import (
// EnsureSecret creates a Secret object or returns it if it already exists.
func (f *Framework) EnsureSecret(secret *api.Secret) *api.Secret {
s, err := f.KubeClientSet.CoreV1().Secrets(secret.Namespace).Create(secret)
if err != nil {
if k8sErrors.IsAlreadyExists(err) {
s, err := f.KubeClientSet.CoreV1().Secrets(secret.Namespace).Update(secret)
Expect(err).NotTo(HaveOccurred(), "unexpected error updating secret")
return s
}
Expect(err).NotTo(HaveOccurred(), "unexpected error creating secret")
}
err := createSecretWithRetries(f.KubeClientSet, f.Namespace, secret)
Expect(err).To(BeNil(), "unexpected error creating secret")
s, err := f.KubeClientSet.CoreV1().Secrets(secret.Namespace).Get(secret.Name, metav1.GetOptions{})
Expect(s).NotTo(BeNil())
Expect(s.ObjectMeta).NotTo(BeNil())
@ -57,10 +51,10 @@ func (f *Framework) EnsureSecret(secret *api.Secret) *api.Secret {
// EnsureConfigMap creates a ConfigMap object or returns it if it already exists.
func (f *Framework) EnsureConfigMap(configMap *api.ConfigMap) (*api.ConfigMap, error) {
cm, err := f.KubeClientSet.CoreV1().ConfigMaps(configMap.Namespace).Create(configMap)
cm, err := f.KubeClientSet.CoreV1().ConfigMaps(f.Namespace).Create(configMap)
if err != nil {
if k8sErrors.IsAlreadyExists(err) {
return f.KubeClientSet.CoreV1().ConfigMaps(configMap.Namespace).Update(configMap)
return f.KubeClientSet.CoreV1().ConfigMaps(f.Namespace).Update(configMap)
}
return nil, err
}
@ -70,12 +64,12 @@ func (f *Framework) EnsureConfigMap(configMap *api.ConfigMap) (*api.ConfigMap, e
// EnsureIngress creates an Ingress object or returns it if it already exists.
func (f *Framework) EnsureIngress(ingress *networking.Ingress) *networking.Ingress {
ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Create(ingress)
ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(ingress)
if err != nil {
if k8sErrors.IsAlreadyExists(err) {
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
var err error
ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Update(ingress)
ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(ingress)
if err != nil {
return err
}
@ -100,47 +94,28 @@ func (f *Framework) EnsureIngress(ingress *networking.Ingress) *networking.Ingre
// EnsureService creates a Service object or returns it if it already exists.
func (f *Framework) EnsureService(service *core.Service) *core.Service {
s, err := f.KubeClientSet.CoreV1().Services(service.Namespace).Create(service)
if err != nil {
if k8sErrors.IsAlreadyExists(err) {
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
var err error
s, err = f.KubeClientSet.CoreV1().Services(service.Namespace).Update(service)
if err != nil {
return err
}
err := createServiceWithRetries(f.KubeClientSet, f.Namespace, service)
Expect(err).To(BeNil(), "unexpected error creating service")
return nil
})
s, err := f.KubeClientSet.CoreV1().Services(f.Namespace).Get(service.Name, metav1.GetOptions{})
Expect(err).To(BeNil(), "unexpected error searching service")
Expect(s).NotTo(BeNil())
Expect(s.ObjectMeta).NotTo(BeNil())
Expect(err).NotTo(HaveOccurred())
}
}
Expect(s).NotTo(BeNil(), "expected a service but none returned")
return s
}
// EnsureDeployment creates a Deployment object or returns it if it already exists.
func (f *Framework) EnsureDeployment(deployment *appsv1.Deployment) *appsv1.Deployment {
d, err := f.KubeClientSet.AppsV1().Deployments(deployment.Namespace).Create(deployment)
if err != nil {
if k8sErrors.IsAlreadyExists(err) {
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
d, err = f.KubeClientSet.AppsV1().Deployments(deployment.Namespace).Update(deployment)
if err != nil {
return err
}
err := createDeploymentWithRetries(f.KubeClientSet, f.Namespace, deployment)
Expect(err).To(BeNil(), "unexpected error creating deployment")
return nil
})
s, err := f.KubeClientSet.AppsV1().Deployments(deployment.Namespace).Get(deployment.Name, metav1.GetOptions{})
Expect(err).To(BeNil(), "unexpected error searching deployment")
Expect(s).NotTo(BeNil())
Expect(s.ObjectMeta).NotTo(BeNil())
Expect(err).NotTo(HaveOccurred())
}
}
Expect(d).NotTo(BeNil(), "expected a deployment but none returned")
return d
return s
}
// WaitForPodsReady waits for a given amount of time until a group of Pods is running in the given namespace.
@ -257,3 +232,88 @@ func getIngressNGINXPod(ns string, kubeClientSet kubernetes.Interface) (*core.Po
return pod, nil
}
func createDeploymentWithRetries(c kubernetes.Interface, namespace string, obj *appsv1.Deployment) error {
if obj == nil {
return fmt.Errorf("Object provided to create is empty")
}
createFunc := func() (bool, error) {
_, err := c.AppsV1().Deployments(namespace).Create(obj)
if err == nil || k8sErrors.IsAlreadyExists(err) {
return true, nil
}
if isRetryableAPIError(err) {
return false, nil
}
return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
}
return retryWithExponentialBackOff(createFunc)
}
func createSecretWithRetries(c kubernetes.Interface, namespace string, obj *v1.Secret) error {
if obj == nil {
return fmt.Errorf("Object provided to create is empty")
}
createFunc := func() (bool, error) {
_, err := c.CoreV1().Secrets(namespace).Create(obj)
if err == nil || k8sErrors.IsAlreadyExists(err) {
return true, nil
}
if isRetryableAPIError(err) {
return false, nil
}
return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
}
return retryWithExponentialBackOff(createFunc)
}
func createServiceWithRetries(c kubernetes.Interface, namespace string, obj *v1.Service) error {
if obj == nil {
return fmt.Errorf("Object provided to create is empty")
}
createFunc := func() (bool, error) {
_, err := c.CoreV1().Services(namespace).Create(obj)
if err == nil || k8sErrors.IsAlreadyExists(err) {
return true, nil
}
if isRetryableAPIError(err) {
return false, nil
}
return false, fmt.Errorf("Failed to create object with non-retriable error: %v", err)
}
return retryWithExponentialBackOff(createFunc)
}
const (
// Parameters for retrying with exponential backoff.
retryBackoffInitialDuration = 100 * time.Millisecond
retryBackoffFactor = 3
retryBackoffJitter = 0
retryBackoffSteps = 6
)
// Utility for retrying the given function with exponential backoff.
func retryWithExponentialBackOff(fn wait.ConditionFunc) error {
backoff := wait.Backoff{
Duration: retryBackoffInitialDuration,
Factor: retryBackoffFactor,
Jitter: retryBackoffJitter,
Steps: retryBackoffSteps,
}
return wait.ExponentialBackoff(backoff, fn)
}
func isRetryableAPIError(err error) bool {
// These errors may indicate a transient error that we can retry in tests.
if k8sErrors.IsInternalError(err) || k8sErrors.IsTimeout(err) || k8sErrors.IsServerTimeout(err) ||
k8sErrors.IsTooManyRequests(err) || utilnet.IsProbableEOF(err) || utilnet.IsConnectionReset(err) {
return true
}
// If the error sends the Retry-After header, we respect it as an explicit confirmation we should retry.
if _, shouldRetry := k8sErrors.SuggestsClientDelay(err); shouldRetry {
return true
}
return false
}

View file

@ -107,7 +107,6 @@ func CreateKubeNamespace(baseName string, c kubernetes.Interface) (string, error
Logf("Unexpected error while creating namespace: %v", err)
return false, nil
}
Logf("Created namespace: %v", got.Name)
return true, nil
})
if err != nil {
@ -118,7 +117,12 @@ func CreateKubeNamespace(baseName string, c kubernetes.Interface) (string, error
// DeleteKubeNamespace deletes a namespace and all the objects inside
func DeleteKubeNamespace(c kubernetes.Interface, namespace string) error {
return c.CoreV1().Namespaces().Delete(namespace, metav1.NewDeleteOptions(0))
grace := int64(0)
pb := metav1.DeletePropagationBackground
return c.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{
GracePeriodSeconds: &grace,
PropagationPolicy: &pb,
})
}
// ExpectNoError tests whether an error occurred.

View file

@ -39,9 +39,6 @@ var _ = framework.IngressNginxDescribe("Shutdown ingress controller", func() {
f.NewSlowEchoDeployment()
})
AfterEach(func() {
})
It("should shutdown in less than 60 secons without pending connections", func() {
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.SlowEchoService, 80, nil))
@ -118,7 +115,7 @@ var _ = framework.IngressNginxDescribe("Shutdown ingress controller", func() {
case res := <-result:
Expect(res.errs).Should(BeEmpty())
Expect(res.status).To(Equal(http.StatusOK), "expecting a valid response from HTTP request")
Expect(time.Since(startTime).Seconds()).To(BeNumerically(">", 70), "waiting shutdown")
Expect(time.Since(startTime).Seconds()).To(BeNumerically(">", 60), "waiting shutdown")
ticker.Stop()
return
case <-ticker.C:

View file

@ -40,9 +40,6 @@ var _ = framework.IngressNginxDescribe("DynamicCertificates", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
framework.MemoryLeakIt("should not leak memory from ingress SSL certificates or configuration updates", func() {
hostCount := 1000
iterations := 10

View file

@ -32,9 +32,6 @@ var _ = framework.IngressNginxDescribe("Load Balance - Configmap value", func()
f.NewEchoDeploymentWithReplicas(1)
})
AfterEach(func() {
})
It("should apply the configmap load-balance setting", func() {
host := "load-balance.com"

View file

@ -100,7 +100,7 @@ kind load docker-image --name="${KIND_CLUSTER_NAME}" ${REGISTRY}/fastcgi-hellose
kind load docker-image --name="${KIND_CLUSTER_NAME}" openresty/openresty:1.15.8.2-alpine
kind load docker-image --name="${KIND_CLUSTER_NAME}" ${REGISTRY}/httpbin:${TAG}
kind load docker-image --name="${KIND_CLUSTER_NAME}" ${REGISTRY}/echo:${TAG}
kind load docker-image --name="${KIND_CLUSTER_NAME}" moul/grpcbin
" | parallel --joblog /tmp/log {} || cat /tmp/log
echo "[dev-env] running e2e tests..."

View file

@ -36,9 +36,6 @@ var _ = framework.IngressNginxDescribe("Request smuggling", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should not return body content from error_page", func() {
host := "foo.bar.com"

View file

@ -35,12 +35,6 @@ import (
var _ = framework.IngressNginxDescribe("Service backend - 503", func() {
f := framework.NewDefaultFramework("service-backend")
BeforeEach(func() {
})
AfterEach(func() {
})
It("should return 503 when backend service does not exist", func() {
host := "nonexistent.svc.com"
@ -65,9 +59,7 @@ var _ = framework.IngressNginxDescribe("Service backend - 503", func() {
bi, bs := buildIngressWithUnavailableServiceEndpoints(host, f.Namespace, "/")
svc := f.EnsureService(bs)
Expect(svc).NotTo(BeNil())
f.EnsureService(bs)
f.EnsureIngress(bi)
f.WaitForNginxServer(host,

View file

@ -35,12 +35,6 @@ import (
var _ = framework.IngressNginxDescribe("Service Type ExternalName", func() {
f := framework.NewDefaultFramework("type-externalname")
BeforeEach(func() {
})
AfterEach(func() {
})
It("works with external name set to incomplete fdqn", func() {
f.NewEchoDeployment()

View file

@ -33,9 +33,6 @@ var _ = framework.IngressNginxDescribe("Configmap change", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should reload after an update in the configuration", func() {
host := "configmap-change"

View file

@ -49,9 +49,6 @@ var _ = framework.IngressNginxDescribe("Disabled catch-all", func() {
Expect(err).NotTo(HaveOccurred(), "unexpected error updating ingress controller deployment flags")
})
AfterEach(func() {
})
It("should ignore catch all Ingress", func() {
host := "foo"

View file

@ -38,9 +38,6 @@ var _ = framework.IngressNginxDescribe("X-Forwarded headers", func() {
f.UpdateNginxConfigMapData(setting, "false")
})
AfterEach(func() {
})
It("should trust X-Forwarded headers when setting is true", func() {
host := "forwarded-headers"

View file

@ -37,9 +37,6 @@ var _ = framework.IngressNginxDescribe("Global access block", func() {
f.EnsureIngress(framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil))
})
AfterEach(func() {
})
It("should block CIDRs defined in the ConfigMap", func() {
f.UpdateNginxConfigMapData("block-cidrs", "172.16.0.0/12,192.168.0.0/16,10.0.0.0/8")

View file

@ -50,9 +50,6 @@ var _ = framework.IngressNginxDescribe("Global External Auth", func() {
f.NewHttpbinDeployment()
})
AfterEach(func() {
})
Context("when global external authentication is configured", func() {
BeforeEach(func() {

View file

@ -37,9 +37,6 @@ var _ = framework.IngressNginxDescribe("Ingress class", func() {
f.NewEchoDeploymentWithReplicas(1)
})
AfterEach(func() {
})
Context("Without a specific ingress-class", func() {
It("should ignore Ingress with class", func() {

View file

@ -31,9 +31,6 @@ var _ = framework.IngressNginxDescribe("LuaSharedDict", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("configures lua shared dicts", func() {
ingress := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil)
f.EnsureIngress(ingress)

View file

@ -53,9 +53,6 @@ var _ = framework.IngressNginxDescribe("No Auth locations", func() {
f.EnsureIngress(bi)
})
AfterEach(func() {
})
It("should return status code 401 when accessing '/' unauthentication", func() {
f.WaitForNginxServer(host,
func(server string) bool {

View file

@ -38,9 +38,6 @@ var _ = framework.IngressNginxDescribe("Proxy Protocol", func() {
f.UpdateNginxConfigMapData(setting, "false")
})
AfterEach(func() {
})
It("should respect port passed by the PROXY Protocol", func() {
host := "proxy-protocol"

View file

@ -35,9 +35,6 @@ var _ = framework.IngressNginxDescribe("Server Tokens", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should not exists Server header in the response", func() {
f.UpdateNginxConfigMapData(serverTokens, "false")

View file

@ -43,9 +43,6 @@ var _ = framework.IngressNginxDescribe("Settings - TLS)", func() {
f.UpdateNginxConfigMapData("use-forwarded-headers", "false")
})
AfterEach(func() {
})
It("should configure TLS protocol", func() {
sslCiphers := "ssl-ciphers"
sslProtocols := "ssl-protocols"

View file

@ -34,9 +34,6 @@ var _ = framework.IngressNginxDescribe("sslredirect", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should redirect from HTTP to HTTPS when secret is missing", func() {
host := "redirect.com"

View file

@ -39,9 +39,6 @@ var _ = framework.IngressNginxDescribe("SSL", func() {
f.NewEchoDeployment()
})
AfterEach(func() {
})
It("should not appear references to secret updates not used in ingress rules", func() {
host := "ssl-update"

View file

@ -39,12 +39,6 @@ var _ = framework.IngressNginxDescribe("Status Update [Status]", func() {
host := "status-update"
address := getHostIP()
BeforeEach(func() {
})
AfterEach(func() {
})
It("should update status field after client-go reconnection", func() {
port, cmd, err := f.KubectlProxy(0)
Expect(err).NotTo(HaveOccurred(), "unexpected error starting kubectl proxy")

View file

@ -37,12 +37,6 @@ import (
var _ = framework.IngressNginxDescribe("TCP Feature", func() {
f := framework.NewDefaultFramework("tcp")
BeforeEach(func() {
})
AfterEach(func() {
})
It("should expose a TCP service", func() {
f.NewEchoDeploymentWithReplicas(1)