From 4c1c707e9c802703939ed05a40b205b42c202b20 Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Thu, 9 Nov 2017 23:00:38 -0300 Subject: [PATCH] Add tests for alias annotation --- internal/ingress/controller/controller.go | 3 +- test/e2e/annotations/alias.go | 150 +++++++++++++++++++++ test/e2e/annotations/auth.go | 15 +++ test/e2e/defaultbackend/default_backend.go | 47 +++---- test/e2e/defaultbackend/ssl.go | 34 ++--- test/e2e/e2e.go | 1 + test/e2e/framework/echo.go | 118 ++++++++++++++++ test/e2e/framework/framework.go | 30 ++++- test/e2e/framework/k8s.go | 95 +++++++++++++ test/e2e/framework/util.go | 43 +++++- 10 files changed, 479 insertions(+), 57 deletions(-) create mode 100644 test/e2e/annotations/alias.go create mode 100644 test/e2e/annotations/auth.go create mode 100644 test/e2e/framework/echo.go create mode 100644 test/e2e/framework/k8s.go diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index d71d4bfbd..0aece8cf5 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -1016,8 +1016,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress, } if !found { - glog.Warningf("ingress %v/%v for host %v contains a TLS section but none of the host match", - ing.Namespace, ing.Name, host) + // does not contains a TLS section but none of the host match continue } diff --git a/test/e2e/annotations/alias.go b/test/e2e/annotations/alias.go new file mode 100644 index 000000000..c0fb4b5d0 --- /dev/null +++ b/test/e2e/annotations/alias.go @@ -0,0 +1,150 @@ +/* +Copyright 2017 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 ( + "fmt" + "net/http" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/parnurzeal/gorequest" + + v1beta1 "k8s.io/api/extensions/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + + "k8s.io/ingress-nginx/test/e2e/framework" +) + +var _ = framework.IngressNginxDescribe("Annotations - Alias", func() { + f := framework.NewDefaultFramework("alias") + + BeforeEach(func() { + err := f.NewEchoDeployment() + Expect(err).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + }) + + It("should return status code 200 for host 'foo' and 404 for 'bar'", func() { + host := "foo" + + ing, err := f.EnsureIngress(&v1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: host, + Namespace: f.Namespace.Name, + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: host, + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/", + Backend: v1beta1.IngressBackend{ + ServiceName: "http-svc", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + }, + }) + + Expect(err).NotTo(HaveOccurred()) + Expect(ing).NotTo(BeNil()) + + err = f.WaitForNginxServer(host) + Expect(err).NotTo(HaveOccurred()) + + resp, body, errs := gorequest.New(). + Get(f.NginxHTTPURL). + Set("Host", host). + End() + + Expect(len(errs)).Should(BeNumerically("==", 0)) + Expect(resp.StatusCode).Should(Equal(http.StatusOK)) + Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", host))) + + resp, body, errs = gorequest.New(). + Get(f.NginxHTTPURL). + Set("Host", "bar"). + End() + + Expect(len(errs)).Should(BeNumerically("==", 0)) + Expect(resp.StatusCode).Should(Equal(http.StatusNotFound)) + Expect(body).Should(ContainSubstring("default backend - 404")) + }) + + It("should return status code 200 for host 'foo' and 'bar'", func() { + host := "bar" + ing, err := f.EnsureIngress(&v1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: host, + Namespace: f.Namespace.Name, + Annotations: map[string]string{ + "nginx.ingress.kubernetes.io/server-alias": host, + }, + }, + Spec: v1beta1.IngressSpec{ + Rules: []v1beta1.IngressRule{ + { + Host: "foo", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Path: "/", + Backend: v1beta1.IngressBackend{ + ServiceName: "http-svc", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, + }, + }, + }) + + Expect(err).NotTo(HaveOccurred()) + Expect(ing).NotTo(BeNil()) + + err = f.WaitForNginxServer(host) + Expect(err).NotTo(HaveOccurred()) + + hosts := []string{"foo", "bar"} + for _, host := range hosts { + resp, body, errs := gorequest.New(). + Get(f.NginxHTTPURL). + Set("Host", host). + End() + + Expect(len(errs)).Should(BeNumerically("==", 0)) + Expect(resp.StatusCode).Should(Equal(http.StatusOK)) + Expect(body).Should(ContainSubstring(fmt.Sprintf("host=%v", host))) + } + }) +}) diff --git a/test/e2e/annotations/auth.go b/test/e2e/annotations/auth.go new file mode 100644 index 000000000..1ee7e1546 --- /dev/null +++ b/test/e2e/annotations/auth.go @@ -0,0 +1,15 @@ +package annotations + +// Tests: +// No auth +// Basic +// 401 +// Realm name +// Auth ok +// Auth error +// Digest +// 401 +// Realm name +// Auth ok +// Auth error +// Check return 403 if there's an error retrieving the secret diff --git a/test/e2e/defaultbackend/default_backend.go b/test/e2e/defaultbackend/default_backend.go index dc07f3841..824a70609 100644 --- a/test/e2e/defaultbackend/default_backend.go +++ b/test/e2e/defaultbackend/default_backend.go @@ -39,14 +39,6 @@ var _ = framework.IngressNginxDescribe("Default backend", func() { }) It("should return 404 sending requests when only a default backend is running", func() { - httpURL, err := f.GetNginxURL(framework.HTTP) - Expect(err).NotTo(HaveOccurred()) - - httpsURL, err := f.GetNginxURL(framework.HTTPS) - Expect(err).NotTo(HaveOccurred()) - - request := gorequest.New() - testCases := []struct { Name string Host string @@ -55,38 +47,39 @@ var _ = framework.IngressNginxDescribe("Default backend", func() { Path string Status int }{ - {"basic HTTP GET request without host to path / should return 404", "", framework.HTTP, "GET", "/", 404}, - {"basic HTTP GET request without host to path /demo should return 404", "", framework.HTTP, "GET", "/demo", 404}, - {"basic HTTPS GET request without host to path / should return 404", "", framework.HTTPS, "GET", "/", 404}, - {"basic HTTPS GET request without host to path /demo should return 404", "", framework.HTTPS, "GET", "/demo", 404}, + {"basic HTTP GET request without host to path / should return 404", "", framework.HTTP, "GET", "/", http.StatusNotFound}, + {"basic HTTP GET request without host to path /demo should return 404", "", framework.HTTP, "GET", "/demo", http.StatusNotFound}, + {"basic HTTPS GET request without host to path / should return 404", "", framework.HTTPS, "GET", "/", http.StatusNotFound}, + {"basic HTTPS GET request without host to path /demo should return 404", "", framework.HTTPS, "GET", "/demo", http.StatusNotFound}, - {"basic HTTP POST request without host to path / should return 404", "", framework.HTTP, "POST", "/", 404}, - {"basic HTTP POST request without host to path /demo should return 404", "", framework.HTTP, "POST", "/demo", 404}, - {"basic HTTPS POST request without host to path / should return 404", "", framework.HTTPS, "POST", "/", 404}, - {"basic HTTPS POST request without host to path /demo should return 404", "", framework.HTTPS, "POST", "/demo", 404}, + {"basic HTTP POST request without host to path / should return 404", "", framework.HTTP, "POST", "/", http.StatusNotFound}, + {"basic HTTP POST request without host to path /demo should return 404", "", framework.HTTP, "POST", "/demo", http.StatusNotFound}, + {"basic HTTPS POST request without host to path / should return 404", "", framework.HTTPS, "POST", "/", http.StatusNotFound}, + {"basic HTTPS POST request without host to path /demo should return 404", "", framework.HTTPS, "POST", "/demo", http.StatusNotFound}, - {"basic HTTP GET request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTP, "GET", "/", 404}, - {"basic HTTP GET request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTP, "GET", "/demo", 404}, - {"basic HTTPS GET request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTPS, "GET", "/", 404}, - {"basic HTTPS GET request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTPS, "GET", "/demo", 404}, + {"basic HTTP GET request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTP, "GET", "/", http.StatusNotFound}, + {"basic HTTP GET request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTP, "GET", "/demo", http.StatusNotFound}, + {"basic HTTPS GET request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTPS, "GET", "/", http.StatusNotFound}, + {"basic HTTPS GET request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTPS, "GET", "/demo", http.StatusNotFound}, - {"basic HTTP POST request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTP, "POST", "/", 404}, - {"basic HTTP POST request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTP, "POST", "/demo", 404}, - {"basic HTTPS POST request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTPS, "POST", "/", 404}, - {"basic HTTPS POST request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTPS, "POST", "/demo", 404}, + {"basic HTTP POST request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTP, "POST", "/", http.StatusNotFound}, + {"basic HTTP POST request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTP, "POST", "/demo", http.StatusNotFound}, + {"basic HTTPS POST request to host foo.bar.com and path / should return 404", " foo.bar.com", framework.HTTPS, "POST", "/", http.StatusNotFound}, + {"basic HTTPS POST request to host foo.bar.com and path /demo should return 404", " foo.bar.com", framework.HTTPS, "POST", "/demo", http.StatusNotFound}, } for _, test := range testCases { By(test.Name) - var errs []error + + request := gorequest.New() var cm *gorequest.SuperAgent switch test.Scheme { case framework.HTTP: - cm = request.CustomMethod(test.Method, httpURL) + cm = request.CustomMethod(test.Method, f.NginxHTTPURL) break case framework.HTTPS: - cm = request.CustomMethod(test.Method, httpsURL) + cm = request.CustomMethod(test.Method, f.NginxHTTPSURL) // the default backend uses a self generated certificate cm.Transport = &http.Transport{ TLSClientConfig: &tls.Config{ diff --git a/test/e2e/defaultbackend/ssl.go b/test/e2e/defaultbackend/ssl.go index 8773600cb..49511d491 100644 --- a/test/e2e/defaultbackend/ssl.go +++ b/test/e2e/defaultbackend/ssl.go @@ -18,7 +18,6 @@ package defaultbackend import ( "crypto/tls" - "net/http" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -37,36 +36,29 @@ var _ = framework.IngressNginxDescribe("Default backend - SSL", func() { }) It("should return a self generated SSL certificate", func() { - httpsURL, err := f.GetNginxURL(framework.HTTPS) - Expect(err).NotTo(HaveOccurred()) - - request := gorequest.New() - By("checking SSL Certificate using the NGINX IP address") - cm := request.Post(httpsURL) - // the default backend uses a self generated certificate - cm.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ + resp, _, errs := gorequest.New(). + Post(f.NginxHTTPSURL). + TLSClientConfig(&tls.Config{ + // the default backend uses a self generated certificate InsecureSkipVerify: true, - }, - } - resp, _, errs := cm.End() + }).End() + Expect(len(errs)).Should(BeNumerically("==", 0)) Expect(len(resp.TLS.PeerCertificates)).Should(BeNumerically("==", 1)) + for _, pc := range resp.TLS.PeerCertificates { Expect(pc.Issuer.CommonName).Should(Equal("Kubernetes Ingress Controller Fake Certificate")) } By("checking SSL Certificate using the NGINX catch all server") - cm = request.Post(httpsURL) - // the default backend uses a self generated certificate - cm.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ + resp, _, errs = gorequest.New(). + Post(f.NginxHTTPSURL). + TLSClientConfig(&tls.Config{ + // the default backend uses a self generated certificate InsecureSkipVerify: true, - }, - } - cm.Set("Host", "foo.bar.com") - resp, _, errs = cm.End() + }). + Set("Host", "foo.bar.com").End() Expect(len(errs)).Should(BeNumerically("==", 0)) Expect(len(resp.TLS.PeerCertificates)).Should(BeNumerically("==", 1)) for _, pc := range resp.TLS.PeerCertificates { diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index b98766c60..4f0601687 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -26,6 +26,7 @@ import ( "k8s.io/apiserver/pkg/util/logs" _ "k8s.io/client-go/plugin/pkg/client/auth" + _ "k8s.io/ingress-nginx/test/e2e/annotations" _ "k8s.io/ingress-nginx/test/e2e/defaultbackend" "k8s.io/ingress-nginx/test/e2e/framework" ) diff --git a/test/e2e/framework/echo.go b/test/e2e/framework/echo.go new file mode 100644 index 000000000..7d9cdc966 --- /dev/null +++ b/test/e2e/framework/echo.go @@ -0,0 +1,118 @@ +/* +Copyright 2017 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 ( + "fmt" + "time" + + "github.com/pkg/errors" + + corev1 "k8s.io/api/core/v1" + extensions "k8s.io/api/extensions/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// NewEchoDeployment creates a new deployment of the echoserver image in a particular namespace +func (f *Framework) NewEchoDeployment() error { + deployment := &extensions.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-svc", + Namespace: f.Namespace.Name, + DeletionGracePeriodSeconds: NewInt64(5), + }, + Spec: extensions.DeploymentSpec{ + Replicas: NewInt32(1), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "http-svc", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "http-svc", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "http-svc", + Image: "gcr.io/google_containers/echoserver:1.8", + Env: []corev1.EnvVar{}, + Ports: []corev1.ContainerPort{ + { + Name: "http", + ContainerPort: 8080, + }, + }, + }, + }, + }, + }, + }, + } + + d, err := f.EnsureDeployment(deployment) + if err != nil { + return err + } + + if d == nil { + return fmt.Errorf("unexpected error creating deployement for echoserver") + } + + err = f.WaitForPodsReady(10*time.Second, 1, metav1.ListOptions{ + LabelSelector: fields.SelectorFromSet(fields.Set(d.Spec.Template.ObjectMeta.Labels)).String(), + }) + if err != nil { + return errors.Wrap(err, "failed to wait for to become ready") + } + + service := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "http-svc", + Namespace: f.Namespace.Name, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Name: "http", + Port: 80, + TargetPort: intstr.FromInt(8080), + Protocol: "TCP", + }, + }, + Selector: map[string]string{ + "app": "http-svc", + }, + }, + } + + s, err := f.EnsureService(service) + if err != nil { + return err + } + + if s == nil { + return fmt.Errorf("unexpected error creating service for echoserver deployment") + } + + return nil +} diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index b697b3945..d26c7b07d 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -17,10 +17,11 @@ import ( "fmt" "os/exec" "strings" + "time" "k8s.io/api/core/v1" apiextcs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" . "github.com/onsi/ginkgo" @@ -31,6 +32,11 @@ const ( podName = "test-ingress-controller" ) +const ( + MaxRetry = 200 + NoRetry = 1 +) + type RequestScheme string // These are valid test request schemes. @@ -54,9 +60,12 @@ type Framework struct { // 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 + + NginxHTTPURL string + NginxHTTPSURL string } -// NewFramework makes a new framework and sets up a BeforeEach/AfterEach for +// 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 { f := &Framework{ @@ -83,6 +92,14 @@ func (f *Framework) BeforeEach() { By("Building a namespace api object") f.Namespace, err = CreateKubeNamespace(f.BaseName, f.KubeClientSet) Expect(err).NotTo(HaveOccurred()) + + By("Building NGINX HTTP URL") + f.NginxHTTPURL, err = f.GetNginxURL(HTTP) + Expect(err).NotTo(HaveOccurred()) + + By("Building NGINX HTTPS URL") + f.NginxHTTPSURL, err = f.GetNginxURL(HTTPS) + Expect(err).NotTo(HaveOccurred()) } // AfterEach deletes the namespace, after reading its events. @@ -94,7 +111,7 @@ func (f *Framework) AfterEach() { Expect(err).NotTo(HaveOccurred()) By("Waiting for test namespace to no longer exist") - err = WaitForKubeNamespaceNotExist(f.KubeClientSet, f.Namespace.Name) + err = WaitForNoPodsInNamespace(f.KubeClientSet, f.Namespace.Name) Expect(err).NotTo(HaveOccurred()) } @@ -115,7 +132,7 @@ func (f *Framework) GetNginxIP() (string, error) { // GetNginxPort returns the number of TCP port where NGINX is running func (f *Framework) GetNginxPort(name string) (int, error) { - s, err := f.KubeClientSet.CoreV1().Services("ingress-nginx").Get("ingress-nginx", meta_v1.GetOptions{}) + s, err := f.KubeClientSet.CoreV1().Services("ingress-nginx").Get("ingress-nginx", metav1.GetOptions{}) if err != nil { return -1, err } @@ -143,3 +160,8 @@ func (f *Framework) GetNginxURL(scheme RequestScheme) (string, error) { return fmt.Sprintf("%v://%v:%v", scheme, ip, port), nil } + +func (f *Framework) WaitForNginxServer(name string) error { + time.Sleep(5 * time.Second) + return nil +} diff --git a/test/e2e/framework/k8s.go b/test/e2e/framework/k8s.go new file mode 100644 index 000000000..8ce459fb4 --- /dev/null +++ b/test/e2e/framework/k8s.go @@ -0,0 +1,95 @@ +/* +Copyright 2017 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 ( + "time" + + api "k8s.io/api/core/v1" + core "k8s.io/api/core/v1" + extensions "k8s.io/api/extensions/v1beta1" + k8sErrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" +) + +func (f *Framework) EnsureSecret(secret *api.Secret) (*api.Secret, error) { + s, err := f.KubeClientSet.CoreV1().Secrets(secret.Namespace).Create(secret) + if err != nil { + if k8sErrors.IsAlreadyExists(err) { + return f.KubeClientSet.CoreV1().Secrets(secret.Namespace).Update(secret) + } + return nil, err + } + return s, nil +} + +func (f *Framework) EnsureIngress(ingress *extensions.Ingress) (*extensions.Ingress, error) { + s, err := f.KubeClientSet.ExtensionsV1beta1().Ingresses(ingress.Namespace).Update(ingress) + if err != nil { + if k8sErrors.IsNotFound(err) { + return f.KubeClientSet.ExtensionsV1beta1().Ingresses(ingress.Namespace).Create(ingress) + } + return nil, err + } + return s, nil +} + +func (f *Framework) EnsureService(service *core.Service) (*core.Service, error) { + s, err := f.KubeClientSet.CoreV1().Services(service.Namespace).Update(service) + if err != nil { + if k8sErrors.IsNotFound(err) { + return f.KubeClientSet.CoreV1().Services(service.Namespace).Create(service) + } + return nil, err + } + return s, nil +} + +func (f *Framework) EnsureDeployment(deployment *extensions.Deployment) (*extensions.Deployment, error) { + d, err := f.KubeClientSet.Extensions().Deployments(deployment.Namespace).Update(deployment) + if err != nil { + if k8sErrors.IsNotFound(err) { + return f.KubeClientSet.Extensions().Deployments(deployment.Namespace).Create(deployment) + } + return nil, err + } + return d, nil +} + +func (f *Framework) WaitForPodsReady(timeout time.Duration, expectedReplicas int, opts metav1.ListOptions) error { + return wait.Poll(time.Second, timeout, func() (bool, error) { + pl, err := f.KubeClientSet.Core().Pods(f.Namespace.Name).List(opts) + if err != nil { + return false, err + } + + r := 0 + for _, p := range pl.Items { + if p.Status.Phase != core.PodRunning { + continue + } + r++ + } + + if r == expectedReplicas { + return true, nil + } + + return false, nil + }) +} diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index 907539e32..bad785de1 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -120,7 +120,11 @@ func CreateKubeNamespace(baseName string, c kubernetes.Interface) (*v1.Namespace } func DeleteKubeNamespace(c kubernetes.Interface, namespace string) error { - return c.Core().Namespaces().Delete(namespace, nil) + deletePolicy := metav1.DeletePropagationForeground + return c.Core().Namespaces().Delete(namespace, &metav1.DeleteOptions{ + GracePeriodSeconds: NewInt64(0), + PropagationPolicy: &deletePolicy, + }) } func ExpectNoError(err error, explain ...interface{}) { @@ -131,7 +135,7 @@ func ExpectNoError(err error, explain ...interface{}) { } func WaitForKubeNamespaceNotExist(c kubernetes.Interface, namespace string) error { - return wait.PollImmediate(Poll, time.Minute*2, namespaceNotExist(c, namespace)) + return wait.PollImmediate(Poll, time.Minute*1, namespaceNotExist(c, namespace)) } func namespaceNotExist(c kubernetes.Interface, namespace string) wait.ConditionFunc { @@ -147,7 +151,28 @@ func namespaceNotExist(c kubernetes.Interface, namespace string) wait.ConditionF } } -// Waits default amount of time (PodStartTimeout) for the specified pod to become running. +func WaitForNoPodsInNamespace(c kubernetes.Interface, namespace string) error { + return wait.PollImmediate(Poll, time.Minute*2, noPodsInNamespace(c, namespace)) +} + +func noPodsInNamespace(c kubernetes.Interface, namespace string) wait.ConditionFunc { + return func() (bool, error) { + items, err := c.CoreV1().Pods(namespace).List(metav1.ListOptions{}) + if apierrors.IsNotFound(err) { + return true, nil + } + if err != nil { + return false, err + } + + if len(items.Items) == 0 { + return true, nil + } + return false, nil + } +} + +// WaitForPodRunningInNamespace waits default amount of time (PodStartTimeout) for the specified pod to become running. // Returns an error if timeout occurs first, or pod goes in to failed state. func WaitForPodRunningInNamespace(c kubernetes.Interface, pod *v1.Pod) error { if pod.Status.Phase == v1.PodRunning { @@ -175,3 +200,15 @@ func podRunning(c kubernetes.Interface, podName, namespace string) wait.Conditio return false, nil } } + +func NewInt32(val int32) *int32 { + p := new(int32) + *p = val + return p +} + +func NewInt64(val int64) *int64 { + p := new(int64) + *p = val + return p +}