mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-10 20:42:26 +00:00
Start e2e framework; print events
This commit is contained in:
parent
2a6cf783ec
commit
28b3224b72
96
test/e2e/framework.go
Normal file
96
test/e2e/framework.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
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 e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Framework supports common operations used by e2e tests; it will keep a client & a namespace for you.
|
||||||
|
// Eventual goal is to merge this with integration test framework.
|
||||||
|
type Framework struct {
|
||||||
|
BaseName string
|
||||||
|
|
||||||
|
Namespace *api.Namespace
|
||||||
|
Client *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFramework makes a new framework and sets up a BeforeEach/AfterEach for
|
||||||
|
// you (you can write additional before/after each functions).
|
||||||
|
func NewFramework(baseName string) *Framework {
|
||||||
|
f := &Framework{
|
||||||
|
BaseName: baseName,
|
||||||
|
}
|
||||||
|
|
||||||
|
BeforeEach(f.beforeEach)
|
||||||
|
AfterEach(f.afterEach)
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// beforeEach gets a client and makes a namespace.
|
||||||
|
func (f *Framework) beforeEach() {
|
||||||
|
By("Creating a kubernetes client")
|
||||||
|
c, err := loadClient()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
f.Client = c
|
||||||
|
|
||||||
|
By("Building a namespace api object")
|
||||||
|
namespace, err := createTestingNS(f.BaseName, f.Client)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
f.Namespace = namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// afterEach deletes the namespace, after reading its events.
|
||||||
|
func (f *Framework) afterEach() {
|
||||||
|
// Print events if the test failed.
|
||||||
|
if CurrentGinkgoTestDescription().Failed {
|
||||||
|
By(fmt.Sprintf("Collecting events from namespace %q.", f.Namespace.Name))
|
||||||
|
events, err := f.Client.Events(f.Namespace.Name).List(labels.Everything(), fields.Everything())
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
for _, e := range events.Items {
|
||||||
|
Logf("event for %v: %v %v: %v", e.InvolvedObject.Name, e.Source, e.Reason, e.Message)
|
||||||
|
}
|
||||||
|
// Note that we don't wait for any cleanup to propagate, which means
|
||||||
|
// that if you delete a bunch of pods right before ending your test,
|
||||||
|
// you may or may not see the killing/deletion/cleanup events.
|
||||||
|
}
|
||||||
|
|
||||||
|
By(fmt.Sprintf("Destroying namespace %q for this suite.", f.Namespace.Name))
|
||||||
|
if err := f.Client.Namespaces().Delete(f.Namespace.Name); err != nil {
|
||||||
|
Failf("Couldn't delete ns %q: %s", f.Namespace.Name, err)
|
||||||
|
}
|
||||||
|
// Paranoia-- prevent reuse!
|
||||||
|
f.Namespace = nil
|
||||||
|
f.Client = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForPodRunning waits for the pod to run in the namespace.
|
||||||
|
func (f *Framework) WaitForPodRunning(podName string) error {
|
||||||
|
return waitForPodRunningInNamespace(f.Client, podName, f.Namespace.Name)
|
||||||
|
}
|
@ -19,10 +19,10 @@ package e2e
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
@ -31,20 +31,17 @@ import (
|
|||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LaunchNetTestPodPerNode(nodes *api.NodeList, name string, c *client.Client, ns string) []string {
|
func LaunchNetTestPodPerNode(f *Framework, nodes *api.NodeList, name string) []string {
|
||||||
podNames := []string{}
|
podNames := []string{}
|
||||||
|
|
||||||
totalPods := len(nodes.Items)
|
totalPods := len(nodes.Items)
|
||||||
|
|
||||||
Expect(totalPods).NotTo(Equal(0))
|
Expect(totalPods).NotTo(Equal(0))
|
||||||
|
|
||||||
for i, node := range nodes.Items {
|
for _, node := range nodes.Items {
|
||||||
podName := fmt.Sprintf("%s-%d", name, i)
|
pod, err := f.Client.Pods(f.Namespace.Name).Create(&api.Pod{
|
||||||
podNames = append(podNames, podName)
|
|
||||||
Logf("Creating pod %s on node %s", podName, node.Name)
|
|
||||||
_, err := c.Pods(ns).Create(&api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: podName,
|
GenerateName: name + "-",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"name": name,
|
"name": name,
|
||||||
},
|
},
|
||||||
@ -59,7 +56,7 @@ func LaunchNetTestPodPerNode(nodes *api.NodeList, name string, c *client.Client,
|
|||||||
//peers >= totalPods should be asserted by the container.
|
//peers >= totalPods should be asserted by the container.
|
||||||
//the nettest container finds peers by looking up list of svc endpoints.
|
//the nettest container finds peers by looking up list of svc endpoints.
|
||||||
fmt.Sprintf("-peers=%d", totalPods),
|
fmt.Sprintf("-peers=%d", totalPods),
|
||||||
"-namespace=" + ns},
|
"-namespace=" + f.Namespace.Name},
|
||||||
Ports: []api.ContainerPort{{ContainerPort: 8080}},
|
Ports: []api.ContainerPort{{ContainerPort: 8080}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -68,16 +65,16 @@ func LaunchNetTestPodPerNode(nodes *api.NodeList, name string, c *client.Client,
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Logf("Created pod %s on node %s", pod.ObjectMeta.Name, node.Name)
|
||||||
|
podNames = append(podNames, pod.ObjectMeta.Name)
|
||||||
}
|
}
|
||||||
return podNames
|
return podNames
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Describe("Networking", func() {
|
var _ = Describe("Networking", func() {
|
||||||
|
f := NewFramework("nettest")
|
||||||
|
|
||||||
//This namespace is modified throughout the course of the test.
|
|
||||||
var namespace *api.Namespace
|
|
||||||
var svcname = "nettest"
|
var svcname = "nettest"
|
||||||
var c *client.Client = nil
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
//Assert basic external connectivity.
|
//Assert basic external connectivity.
|
||||||
@ -91,22 +88,6 @@ var _ = Describe("Networking", func() {
|
|||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
Failf("Unexpected error code, expected 200, got, %v (%v)", resp.StatusCode, resp)
|
Failf("Unexpected error code, expected 200, got, %v (%v)", resp.StatusCode, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
By("Creating a kubernetes client")
|
|
||||||
c, err = loadClient()
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
By("Building a namespace api object")
|
|
||||||
namespace, err = createTestingNS("nettest", c)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
By(fmt.Sprintf("Destroying namespace for this suite %v", namespace.Name))
|
|
||||||
if err := c.Namespaces().Delete(namespace.Name); err != nil {
|
|
||||||
Failf("Couldn't delete ns %s", err)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// First test because it has no dependencies on variables created later on.
|
// First test because it has no dependencies on variables created later on.
|
||||||
@ -120,8 +101,8 @@ var _ = Describe("Networking", func() {
|
|||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
By(fmt.Sprintf("testing: %s", test.path))
|
By(fmt.Sprintf("testing: %s", test.path))
|
||||||
data, err := c.RESTClient.Get().
|
data, err := f.Client.RESTClient.Get().
|
||||||
Namespace(namespace.Name).
|
Namespace(f.Namespace.Name).
|
||||||
AbsPath(test.path).
|
AbsPath(test.path).
|
||||||
DoRaw()
|
DoRaw()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -139,8 +120,8 @@ var _ = Describe("Networking", func() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
By(fmt.Sprintf("Creating a service named [%s] in namespace %s", svcname, namespace.Name))
|
By(fmt.Sprintf("Creating a service named %q in namespace %q", svcname, f.Namespace.Name))
|
||||||
svc, err := c.Services(namespace.Name).Create(&api.Service{
|
svc, err := f.Client.Services(f.Namespace.Name).Create(&api.Service{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: svcname,
|
Name: svcname,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -166,26 +147,26 @@ var _ = Describe("Networking", func() {
|
|||||||
defer func() {
|
defer func() {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
By("Cleaning up the service")
|
By("Cleaning up the service")
|
||||||
if err = c.Services(namespace.Name).Delete(svc.Name); err != nil {
|
if err = f.Client.Services(f.Namespace.Name).Delete(svc.Name); err != nil {
|
||||||
Failf("unable to delete svc %v: %v", svc.Name, err)
|
Failf("unable to delete svc %v: %v", svc.Name, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
By("Creating a webserver (pending) pod on each node")
|
By("Creating a webserver (pending) pod on each node")
|
||||||
|
|
||||||
nodes, err := c.Nodes().List(labels.Everything(), fields.Everything())
|
nodes, err := f.Client.Nodes().List(labels.Everything(), fields.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Failf("Failed to list nodes: %v", err)
|
Failf("Failed to list nodes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
podNames := LaunchNetTestPodPerNode(nodes, svcname, c, namespace.Name)
|
podNames := LaunchNetTestPodPerNode(f, nodes, svcname)
|
||||||
|
|
||||||
// Clean up the pods
|
// Clean up the pods
|
||||||
defer func() {
|
defer func() {
|
||||||
defer GinkgoRecover()
|
defer GinkgoRecover()
|
||||||
By("Cleaning up the webserver pods")
|
By("Cleaning up the webserver pods")
|
||||||
for _, podName := range podNames {
|
for _, podName := range podNames {
|
||||||
if err = c.Pods(namespace.Name).Delete(podName, nil); err != nil {
|
if err = f.Client.Pods(f.Namespace.Name).Delete(podName, nil); err != nil {
|
||||||
Logf("Failed to delete pod %s: %v", podName, err)
|
Logf("Failed to delete pod %s: %v", podName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,63 +174,67 @@ var _ = Describe("Networking", func() {
|
|||||||
|
|
||||||
By("Waiting for the webserver pods to transition to Running state")
|
By("Waiting for the webserver pods to transition to Running state")
|
||||||
for _, podName := range podNames {
|
for _, podName := range podNames {
|
||||||
err = waitForPodRunningInNamespace(c, podName, namespace.Name)
|
err = f.WaitForPodRunning(podName)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
By("Waiting for connectivity to be verified")
|
By("Waiting for connectivity to be verified")
|
||||||
const maxAttempts = 60
|
|
||||||
passed := false
|
passed := false
|
||||||
|
|
||||||
//once response OK, evaluate response body for pass/fail.
|
//once response OK, evaluate response body for pass/fail.
|
||||||
var body []byte
|
var body []byte
|
||||||
|
getDetails := func() ([]byte, error) {
|
||||||
|
return f.Client.Get().
|
||||||
|
Namespace(f.Namespace.Name).
|
||||||
|
Prefix("proxy").
|
||||||
|
Resource("services").
|
||||||
|
Name(svc.Name).
|
||||||
|
Suffix("read").
|
||||||
|
DoRaw()
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < maxAttempts && !passed; i++ {
|
getStatus := func() ([]byte, error) {
|
||||||
time.Sleep(2 * time.Second)
|
return f.Client.Get().
|
||||||
Logf("About to make a proxy status call")
|
Namespace(f.Namespace.Name).
|
||||||
start := time.Now()
|
|
||||||
body, err = c.Get().
|
|
||||||
Namespace(namespace.Name).
|
|
||||||
Prefix("proxy").
|
Prefix("proxy").
|
||||||
Resource("services").
|
Resource("services").
|
||||||
Name(svc.Name).
|
Name(svc.Name).
|
||||||
Suffix("status").
|
Suffix("status").
|
||||||
DoRaw()
|
DoRaw()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; !passed; i++ { // Timeout will keep us from going forever.
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
Logf("About to make a proxy status call")
|
||||||
|
start := time.Now()
|
||||||
|
body, err = getStatus()
|
||||||
Logf("Proxy status call returned in %v", time.Since(start))
|
Logf("Proxy status call returned in %v", time.Since(start))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logf("Attempt %v/%v: service/pod still starting. (error: '%v')", i, maxAttempts, err)
|
Logf("Attempt %v: service/pod still starting. (error: '%v')", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
|
// Finally, we pass/fail the test based on if the container's response body, as to wether or not it was able to find peers.
|
||||||
switch string(body) {
|
switch {
|
||||||
case "pass":
|
case string(body) == "pass":
|
||||||
Logf("Passed on attempt %v. Cleaning up.", i)
|
Logf("Passed on attempt %v. Cleaning up.", i)
|
||||||
passed = true
|
passed = true
|
||||||
case "running":
|
case string(body) == "running":
|
||||||
Logf("Attempt %v/%v: test still running", i, maxAttempts)
|
Logf("Attempt %v: test still running", i)
|
||||||
case "fail":
|
case string(body) == "fail":
|
||||||
if body, err = c.Get().
|
if body, err = getDetails(); err != nil {
|
||||||
Namespace(namespace.Name).Prefix("proxy").
|
|
||||||
Resource("services").
|
|
||||||
Name(svc.Name).Suffix("read").
|
|
||||||
DoRaw(); err != nil {
|
|
||||||
Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
|
Failf("Failed on attempt %v. Cleaning up. Error reading details: %v", i, err)
|
||||||
} else {
|
} else {
|
||||||
Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
|
Failf("Failed on attempt %v. Cleaning up. Details:\n%s", i, string(body))
|
||||||
}
|
}
|
||||||
|
case strings.Contains(string(body), "no endpoints available"):
|
||||||
|
Logf("Attempt %v: waiting on service/endpoints", i)
|
||||||
default:
|
default:
|
||||||
Logf("Unexpected response: %q", body)
|
Logf("Unexpected response:\n%s", body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !passed {
|
if !passed {
|
||||||
if body, err = c.Get().
|
if body, err = getDetails(); err != nil {
|
||||||
Namespace(namespace.Name).
|
|
||||||
Prefix("proxy").
|
|
||||||
Resource("services").
|
|
||||||
Name(svc.Name).
|
|
||||||
Suffix("read").
|
|
||||||
DoRaw(); err != nil {
|
|
||||||
Failf("Timed out. Cleaning up. Error reading details: %v", err)
|
Failf("Timed out. Cleaning up. Error reading details: %v", err)
|
||||||
} else {
|
} else {
|
||||||
Failf("Timed out. Cleaning up. Details:\n%s", string(body))
|
Failf("Timed out. Cleaning up. Details:\n%s", string(body))
|
||||||
|
@ -55,8 +55,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Reboot", func() {
|
var _ = Describe("Reboot", func() {
|
||||||
|
var c *client.Client
|
||||||
var c *client.Client = nil
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
var err error
|
var err error
|
||||||
|
@ -27,8 +27,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("SSH", func() {
|
var _ = Describe("SSH", func() {
|
||||||
|
var c *client.Client
|
||||||
var c *client.Client = nil
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
var err error
|
var err error
|
||||||
|
Loading…
Reference in New Issue
Block a user