mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
move test specific functions from rc_util.go
This commit is contained in:
parent
59e7a4f474
commit
24f374a395
@ -269,7 +269,7 @@ var _ = SIGDescribe("Network Partition [Disruptive] [Slow]", func() {
|
||||
ginkgo.By(fmt.Sprintf("blocking network traffic from node %s", node.Name))
|
||||
framework.TestUnderTemporaryNetworkFailure(c, ns, node, func() {
|
||||
framework.Logf("Waiting for pod %s to be removed", pods.Items[0].Name)
|
||||
err := framework.WaitForRCPodToDisappear(c, ns, name, pods.Items[0].Name)
|
||||
err := waitForRCPodToDisappear(c, ns, name, pods.Items[0].Name)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("verifying whether the pod from the unreachable node is recreated")
|
||||
@ -338,7 +338,7 @@ var _ = SIGDescribe("Network Partition [Disruptive] [Slow]", func() {
|
||||
ginkgo.By(fmt.Sprintf("blocking network traffic from node %s", node.Name))
|
||||
framework.TestUnderTemporaryNetworkFailure(c, ns, node, func() {
|
||||
framework.Logf("Waiting for pod %s to be removed", pods.Items[0].Name)
|
||||
err := framework.WaitForRCPodToDisappear(c, ns, name, pods.Items[0].Name)
|
||||
err := waitForRCPodToDisappear(c, ns, name, pods.Items[0].Name)
|
||||
framework.ExpectEqual(err, wait.ErrWaitTimeout, "Pod was not deleted during network partition.")
|
||||
|
||||
ginkgo.By(fmt.Sprintf("verifying that there are %v running pods during partition", replicas))
|
||||
@ -658,3 +658,13 @@ var _ = SIGDescribe("Network Partition [Disruptive] [Slow]", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// waitForRCPodToDisappear returns nil if the pod from the given replication controller (described by rcName) no longer exists.
|
||||
// In case of failure or too long waiting time, an error is returned.
|
||||
func waitForRCPodToDisappear(c clientset.Interface, ns, rcName, podName string) error {
|
||||
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": rcName}))
|
||||
// NodeController evicts pod after 5 minutes, so we need timeout greater than that to observe effects.
|
||||
// The grace period must be set to 0 on the pod for it to be deleted during the partition.
|
||||
// Otherwise, it goes to the 'Terminating' state till the kubelet confirms deletion.
|
||||
return e2epod.WaitForPodToDisappear(c, ns, podName, label, 20*time.Second, 10*time.Minute)
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/controller/replication"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
||||
@ -227,7 +228,7 @@ func testReplicationControllerConditionCheck(f *framework.Framework) {
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Scaling down rc %q to satisfy pod quota", name))
|
||||
rc, err = framework.UpdateReplicationControllerWithRetries(c, namespace, name, func(update *v1.ReplicationController) {
|
||||
rc, err = updateReplicationControllerWithRetries(c, namespace, name, func(update *v1.ReplicationController) {
|
||||
x := int32(2)
|
||||
update.Spec.Replicas = &x
|
||||
})
|
||||
@ -348,3 +349,32 @@ func testRCReleaseControlledNotMatching(f *framework.Framework) {
|
||||
})
|
||||
framework.ExpectNoError(err)
|
||||
}
|
||||
|
||||
type updateRcFunc func(d *v1.ReplicationController)
|
||||
|
||||
// updateReplicationControllerWithRetries retries updating the given rc on conflict with the following steps:
|
||||
// 1. Get latest resource
|
||||
// 2. applyUpdate
|
||||
// 3. Update the resource
|
||||
func updateReplicationControllerWithRetries(c clientset.Interface, namespace, name string, applyUpdate updateRcFunc) (*v1.ReplicationController, error) {
|
||||
var rc *v1.ReplicationController
|
||||
var updateErr error
|
||||
pollErr := wait.PollImmediate(10*time.Millisecond, 1*time.Minute, func() (bool, error) {
|
||||
var err error
|
||||
if rc, err = c.CoreV1().ReplicationControllers(namespace).Get(name, metav1.GetOptions{}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Apply the update, then attempt to push it to the apiserver.
|
||||
applyUpdate(rc)
|
||||
if rc, err = c.CoreV1().ReplicationControllers(namespace).Update(rc); err == nil {
|
||||
framework.Logf("Updating replication controller %q", name)
|
||||
return true, nil
|
||||
}
|
||||
updateErr = err
|
||||
return false, nil
|
||||
})
|
||||
if pollErr == wait.ErrWaitTimeout {
|
||||
pollErr = fmt.Errorf("couldn't apply the provided updated to rc %q: %v", name, updateErr)
|
||||
}
|
||||
return rc, pollErr
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ go_library(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/discovery:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//test/e2e/chaosmonkey:go_default_library",
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
|
||||
@ -345,7 +346,7 @@ func waitForServiceInAddonTest(c clientset.Interface, addonNamespace, name strin
|
||||
}
|
||||
|
||||
func waitForReplicationControllerInAddonTest(c clientset.Interface, addonNamespace, name string, exist bool) {
|
||||
framework.ExpectNoError(framework.WaitForReplicationController(c, addonNamespace, name, exist, addonTestPollInterval, addonTestPollTimeout))
|
||||
framework.ExpectNoError(waitForReplicationController(c, addonNamespace, name, exist, addonTestPollInterval, addonTestPollTimeout))
|
||||
}
|
||||
|
||||
func waitForServicewithSelectorInAddonTest(c clientset.Interface, addonNamespace string, exist bool, selector labels.Selector) {
|
||||
@ -353,10 +354,52 @@ func waitForServicewithSelectorInAddonTest(c clientset.Interface, addonNamespace
|
||||
}
|
||||
|
||||
func waitForReplicationControllerwithSelectorInAddonTest(c clientset.Interface, addonNamespace string, exist bool, selector labels.Selector) {
|
||||
framework.ExpectNoError(framework.WaitForReplicationControllerwithSelector(c, addonNamespace, selector, exist, addonTestPollInterval,
|
||||
framework.ExpectNoError(waitForReplicationControllerWithSelector(c, addonNamespace, selector, exist, addonTestPollInterval,
|
||||
addonTestPollTimeout))
|
||||
}
|
||||
|
||||
// waitForReplicationController waits until the RC appears (exist == true), or disappears (exist == false)
|
||||
func waitForReplicationController(c clientset.Interface, namespace, name string, exist bool, interval, timeout time.Duration) error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
_, err := c.CoreV1().ReplicationControllers(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
framework.Logf("Get ReplicationController %s in namespace %s failed (%v).", name, namespace, err)
|
||||
return !exist, nil
|
||||
}
|
||||
framework.Logf("ReplicationController %s in namespace %s found.", name, namespace)
|
||||
return exist, nil
|
||||
})
|
||||
if err != nil {
|
||||
stateMsg := map[bool]string{true: "to appear", false: "to disappear"}
|
||||
return fmt.Errorf("error waiting for ReplicationController %s/%s %s: %v", namespace, name, stateMsg[exist], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// waitForReplicationControllerWithSelector waits until any RC with given selector appears (exist == true), or disappears (exist == false)
|
||||
func waitForReplicationControllerWithSelector(c clientset.Interface, namespace string, selector labels.Selector, exist bool, interval,
|
||||
timeout time.Duration) error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
rcs, err := c.CoreV1().ReplicationControllers(namespace).List(metav1.ListOptions{LabelSelector: selector.String()})
|
||||
switch {
|
||||
case len(rcs.Items) != 0:
|
||||
framework.Logf("ReplicationController with %s in namespace %s found.", selector.String(), namespace)
|
||||
return exist, nil
|
||||
case len(rcs.Items) == 0:
|
||||
framework.Logf("ReplicationController with %s in namespace %s disappeared.", selector.String(), namespace)
|
||||
return !exist, nil
|
||||
default:
|
||||
framework.Logf("List ReplicationController with %s in namespace %s failed: %v", selector.String(), namespace, err)
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
stateMsg := map[bool]string{true: "to appear", false: "to disappear"}
|
||||
return fmt.Errorf("error waiting for ReplicationControllers with %s in namespace %s %s: %v", selector.String(), namespace, stateMsg[exist], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO use the ssh.SSH code, either adding an SCP to it or copying files
|
||||
// differently.
|
||||
func getMasterSSHClient() (*ssh.Client, error) {
|
||||
|
@ -146,7 +146,7 @@ func NewRCByName(c clientset.Interface, ns, name string, replicas int32, gracePe
|
||||
containerArgs = []string{"serve-hostname"}
|
||||
}
|
||||
|
||||
return c.CoreV1().ReplicationControllers(ns).Create(framework.RcByNamePort(
|
||||
return c.CoreV1().ReplicationControllers(ns).Create(rcByNamePort(
|
||||
name, replicas, framework.ServeHostnameImage, containerArgs, 9376, v1.ProtocolTCP, map[string]string{}, gracePeriod))
|
||||
}
|
||||
|
||||
@ -194,3 +194,15 @@ func RestartNodes(c clientset.Interface, nodes []v1.Node) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rcByNamePort returns a ReplicationController with specified name and port
|
||||
func rcByNamePort(name string, replicas int32, image string, containerArgs []string, port int, protocol v1.Protocol,
|
||||
labels map[string]string, gracePeriod *int64) *v1.ReplicationController {
|
||||
|
||||
return framework.RcByNameContainer(name, replicas, image, labels, v1.Container{
|
||||
Name: name,
|
||||
Image: image,
|
||||
Args: containerArgs,
|
||||
Ports: []v1.ContainerPort{{ContainerPort: int32(port), Protocol: protocol}},
|
||||
}, gracePeriod)
|
||||
}
|
||||
|
@ -18,34 +18,17 @@ package framework
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
scaleclient "k8s.io/client-go/scale"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
||||
testutils "k8s.io/kubernetes/test/utils"
|
||||
)
|
||||
|
||||
// RcByNamePort returns a ReplicationController with specified name and port
|
||||
func RcByNamePort(name string, replicas int32, image string, containerArgs []string, port int, protocol v1.Protocol,
|
||||
labels map[string]string, gracePeriod *int64) *v1.ReplicationController {
|
||||
|
||||
return RcByNameContainer(name, replicas, image, labels, v1.Container{
|
||||
Name: name,
|
||||
Image: image,
|
||||
Args: containerArgs,
|
||||
Ports: []v1.ContainerPort{{ContainerPort: int32(port), Protocol: protocol}},
|
||||
}, gracePeriod)
|
||||
}
|
||||
|
||||
// RcByNameContainer returns a ReplicationController with specified name and container
|
||||
func RcByNameContainer(name string, replicas int32, image string, labels map[string]string, c v1.Container,
|
||||
gracePeriod *int64) *v1.ReplicationController {
|
||||
@ -83,35 +66,6 @@ func RcByNameContainer(name string, replicas int32, image string, labels map[str
|
||||
}
|
||||
}
|
||||
|
||||
type updateRcFunc func(d *v1.ReplicationController)
|
||||
|
||||
// UpdateReplicationControllerWithRetries retries updating the given rc on conflict with the following steps:
|
||||
// 1. Get latest resource
|
||||
// 2. applyUpdate
|
||||
// 3. Update the resource
|
||||
func UpdateReplicationControllerWithRetries(c clientset.Interface, namespace, name string, applyUpdate updateRcFunc) (*v1.ReplicationController, error) {
|
||||
var rc *v1.ReplicationController
|
||||
var updateErr error
|
||||
pollErr := wait.PollImmediate(10*time.Millisecond, 1*time.Minute, func() (bool, error) {
|
||||
var err error
|
||||
if rc, err = c.CoreV1().ReplicationControllers(namespace).Get(name, metav1.GetOptions{}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Apply the update, then attempt to push it to the apiserver.
|
||||
applyUpdate(rc)
|
||||
if rc, err = c.CoreV1().ReplicationControllers(namespace).Update(rc); err == nil {
|
||||
Logf("Updating replication controller %q", name)
|
||||
return true, nil
|
||||
}
|
||||
updateErr = err
|
||||
return false, nil
|
||||
})
|
||||
if pollErr == wait.ErrWaitTimeout {
|
||||
pollErr = fmt.Errorf("couldn't apply the provided updated to rc %q: %v", name, updateErr)
|
||||
}
|
||||
return rc, pollErr
|
||||
}
|
||||
|
||||
// DeleteRCAndWaitForGC deletes only the Replication Controller and waits for GC to delete the pods.
|
||||
func DeleteRCAndWaitForGC(c clientset.Interface, ns, name string) error {
|
||||
return DeleteResourceAndWaitForGC(c, api.Kind("ReplicationController"), ns, name)
|
||||
@ -130,131 +84,3 @@ func RunRC(config testutils.RCConfig) error {
|
||||
config.ContainerDumpFunc = LogFailedContainers
|
||||
return testutils.RunRC(config)
|
||||
}
|
||||
|
||||
// WaitForRCPodToDisappear returns nil if the pod from the given replication controller (described by rcName) no longer exists.
|
||||
// In case of failure or too long waiting time, an error is returned.
|
||||
func WaitForRCPodToDisappear(c clientset.Interface, ns, rcName, podName string) error {
|
||||
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": rcName}))
|
||||
// NodeController evicts pod after 5 minutes, so we need timeout greater than that to observe effects.
|
||||
// The grace period must be set to 0 on the pod for it to be deleted during the partition.
|
||||
// Otherwise, it goes to the 'Terminating' state till the kubelet confirms deletion.
|
||||
return e2epod.WaitForPodToDisappear(c, ns, podName, label, 20*time.Second, 10*time.Minute)
|
||||
}
|
||||
|
||||
// WaitForReplicationController waits until the RC appears (exist == true), or disappears (exist == false)
|
||||
func WaitForReplicationController(c clientset.Interface, namespace, name string, exist bool, interval, timeout time.Duration) error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
_, err := c.CoreV1().ReplicationControllers(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
Logf("Get ReplicationController %s in namespace %s failed (%v).", name, namespace, err)
|
||||
return !exist, nil
|
||||
}
|
||||
Logf("ReplicationController %s in namespace %s found.", name, namespace)
|
||||
return exist, nil
|
||||
})
|
||||
if err != nil {
|
||||
stateMsg := map[bool]string{true: "to appear", false: "to disappear"}
|
||||
return fmt.Errorf("error waiting for ReplicationController %s/%s %s: %v", namespace, name, stateMsg[exist], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForReplicationControllerwithSelector waits until any RC with given selector appears (exist == true), or disappears (exist == false)
|
||||
func WaitForReplicationControllerwithSelector(c clientset.Interface, namespace string, selector labels.Selector, exist bool, interval,
|
||||
timeout time.Duration) error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
rcs, err := c.CoreV1().ReplicationControllers(namespace).List(metav1.ListOptions{LabelSelector: selector.String()})
|
||||
switch {
|
||||
case len(rcs.Items) != 0:
|
||||
Logf("ReplicationController with %s in namespace %s found.", selector.String(), namespace)
|
||||
return exist, nil
|
||||
case len(rcs.Items) == 0:
|
||||
Logf("ReplicationController with %s in namespace %s disappeared.", selector.String(), namespace)
|
||||
return !exist, nil
|
||||
default:
|
||||
Logf("List ReplicationController with %s in namespace %s failed: %v", selector.String(), namespace, err)
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
stateMsg := map[bool]string{true: "to appear", false: "to disappear"}
|
||||
return fmt.Errorf("error waiting for ReplicationControllers with %s in namespace %s %s: %v", selector.String(), namespace, stateMsg[exist], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// trimDockerRegistry is the function for trimming the docker.io/library from the beginning of the imagename.
|
||||
// If community docker installed it will not prefix the registry names with the dockerimages vs registry names prefixed with other runtimes or docker installed via RHEL extra repo.
|
||||
// So this function will help to trim the docker.io/library if exists
|
||||
func trimDockerRegistry(imagename string) string {
|
||||
imagename = strings.Replace(imagename, "docker.io/", "", 1)
|
||||
return strings.Replace(imagename, "library/", "", 1)
|
||||
}
|
||||
|
||||
// validatorFn is the function which is individual tests will implement.
|
||||
// we may want it to return more than just an error, at some point.
|
||||
type validatorFn func(c clientset.Interface, podID string) error
|
||||
|
||||
// ValidateController is a generic mechanism for testing RC's that are running.
|
||||
// It takes a container name, a test name, and a validator function which is plugged in by a specific test.
|
||||
// "containername": this is grepped for.
|
||||
// "containerImage" : this is the name of the image we expect to be launched. Not to confuse w/ images (kitten.jpg) which are validated.
|
||||
// "testname": which gets bubbled up to the logging/failure messages if errors happen.
|
||||
// "validator" function: This function is given a podID and a client, and it can do some specific validations that way.
|
||||
func ValidateController(c clientset.Interface, containerImage string, replicas int, containername string, testname string, validator validatorFn, ns string) {
|
||||
containerImage = trimDockerRegistry(containerImage)
|
||||
getPodsTemplate := "--template={{range.items}}{{.metadata.name}} {{end}}"
|
||||
// NB: kubectl adds the "exists" function to the standard template functions.
|
||||
// This lets us check to see if the "running" entry exists for each of the containers
|
||||
// we care about. Exists will never return an error and it's safe to check a chain of
|
||||
// things, any one of which may not exist. In the below template, all of info,
|
||||
// containername, and running might be nil, so the normal index function isn't very
|
||||
// helpful.
|
||||
// This template is unit-tested in kubectl, so if you change it, update the unit test.
|
||||
// You can read about the syntax here: http://golang.org/pkg/text/template/.
|
||||
getContainerStateTemplate := fmt.Sprintf(`--template={{if (exists . "status" "containerStatuses")}}{{range .status.containerStatuses}}{{if (and (eq .name "%s") (exists . "state" "running"))}}true{{end}}{{end}}{{end}}`, containername)
|
||||
|
||||
getImageTemplate := fmt.Sprintf(`--template={{if (exists . "spec" "containers")}}{{range .spec.containers}}{{if eq .name "%s"}}{{.image}}{{end}}{{end}}{{end}}`, containername)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("waiting for all containers in %s pods to come up.", testname)) //testname should be selector
|
||||
waitLoop:
|
||||
for start := time.Now(); time.Since(start) < PodStartTimeout; time.Sleep(5 * time.Second) {
|
||||
getPodsOutput := RunKubectlOrDie("get", "pods", "-o", "template", getPodsTemplate, "-l", testname, fmt.Sprintf("--namespace=%v", ns))
|
||||
pods := strings.Fields(getPodsOutput)
|
||||
if numPods := len(pods); numPods != replicas {
|
||||
ginkgo.By(fmt.Sprintf("Replicas for %s: expected=%d actual=%d", testname, replicas, numPods))
|
||||
continue
|
||||
}
|
||||
var runningPods []string
|
||||
for _, podID := range pods {
|
||||
running := RunKubectlOrDie("get", "pods", podID, "-o", "template", getContainerStateTemplate, fmt.Sprintf("--namespace=%v", ns))
|
||||
if running != "true" {
|
||||
Logf("%s is created but not running", podID)
|
||||
continue waitLoop
|
||||
}
|
||||
|
||||
currentImage := RunKubectlOrDie("get", "pods", podID, "-o", "template", getImageTemplate, fmt.Sprintf("--namespace=%v", ns))
|
||||
currentImage = trimDockerRegistry(currentImage)
|
||||
if currentImage != containerImage {
|
||||
Logf("%s is created but running wrong image; expected: %s, actual: %s", podID, containerImage, currentImage)
|
||||
continue waitLoop
|
||||
}
|
||||
|
||||
// Call the generic validator function here.
|
||||
// This might validate for example, that (1) getting a url works and (2) url is serving correct content.
|
||||
if err := validator(c, podID); err != nil {
|
||||
Logf("%s is running right image but validator function failed: %v", podID, err)
|
||||
continue waitLoop
|
||||
}
|
||||
|
||||
Logf("%s is verified up and running", podID)
|
||||
runningPods = append(runningPods, podID)
|
||||
}
|
||||
// If we reach here, then all our checks passed.
|
||||
if len(runningPods) == replicas {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Reaching here means that one of more checks failed multiple times. Assuming its not a race condition, something is broken.
|
||||
Failf("Timed out after %v seconds waiting for %s pods to reach valid state", PodStartTimeout.Seconds(), testname)
|
||||
}
|
||||
|
@ -116,6 +116,53 @@ var (
|
||||
cronJobGroupVersionResourceBeta = schema.GroupVersionResource{Group: "batch", Version: "v1beta1", Resource: "cronjobs"}
|
||||
)
|
||||
|
||||
var schemaFoo = []byte(`description: Foo CRD for Testing
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
description: Specification of Foo
|
||||
properties:
|
||||
bars:
|
||||
description: List of Bars and their specs.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
description: Name of Bar.
|
||||
type: string
|
||||
age:
|
||||
description: Age of Bar.
|
||||
type: string
|
||||
bazs:
|
||||
description: List of Bazs.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
status:
|
||||
description: Status of Foo
|
||||
type: object
|
||||
properties:
|
||||
bars:
|
||||
description: List of Bars and their statuses.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Name of Bar.
|
||||
type: string
|
||||
available:
|
||||
description: Whether the Bar is installed.
|
||||
type: boolean
|
||||
quxType:
|
||||
description: Indicates to external qux type.
|
||||
pattern: in-tree|out-of-tree
|
||||
type: string`)
|
||||
|
||||
// Stops everything from filePath from namespace ns and checks if everything matching selectors from the given namespace is correctly stopped.
|
||||
// Aware of the kubectl example files map.
|
||||
func cleanupKubectlInputs(fileContents string, ns string, selectors ...string) {
|
||||
@ -286,7 +333,7 @@ var _ = SIGDescribe("Kubectl client", func() {
|
||||
|
||||
ginkgo.By("creating a replication controller")
|
||||
framework.RunKubectlOrDieInput(nautilus, "create", "-f", "-", fmt.Sprintf("--namespace=%v", ns))
|
||||
framework.ValidateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
})
|
||||
|
||||
/*
|
||||
@ -299,15 +346,15 @@ var _ = SIGDescribe("Kubectl client", func() {
|
||||
|
||||
ginkgo.By("creating a replication controller")
|
||||
framework.RunKubectlOrDieInput(nautilus, "create", "-f", "-", fmt.Sprintf("--namespace=%v", ns))
|
||||
framework.ValidateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
ginkgo.By("scaling down the replication controller")
|
||||
debugDiscovery()
|
||||
framework.RunKubectlOrDie("scale", "rc", "update-demo-nautilus", "--replicas=1", "--timeout=5m", fmt.Sprintf("--namespace=%v", ns))
|
||||
framework.ValidateController(c, nautilusImage, 1, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
validateController(c, nautilusImage, 1, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
ginkgo.By("scaling up the replication controller")
|
||||
debugDiscovery()
|
||||
framework.RunKubectlOrDie("scale", "rc", "update-demo-nautilus", "--replicas=2", "--timeout=5m", fmt.Sprintf("--namespace=%v", ns))
|
||||
framework.ValidateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
})
|
||||
|
||||
/*
|
||||
@ -318,11 +365,11 @@ var _ = SIGDescribe("Kubectl client", func() {
|
||||
framework.ConformanceIt("should do a rolling update of a replication controller ", func() {
|
||||
ginkgo.By("creating the initial replication controller")
|
||||
framework.RunKubectlOrDieInput(string(nautilus[:]), "create", "-f", "-", fmt.Sprintf("--namespace=%v", ns))
|
||||
framework.ValidateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
validateController(c, nautilusImage, 2, "update-demo", updateDemoSelector, getUDData("nautilus.jpg", ns), ns)
|
||||
ginkgo.By("rolling-update to new replication controller")
|
||||
debugDiscovery()
|
||||
framework.RunKubectlOrDieInput(string(kitten[:]), "rolling-update", "update-demo-nautilus", "--update-period=1s", "-f", "-", fmt.Sprintf("--namespace=%v", ns))
|
||||
framework.ValidateController(c, kittenImage, 2, "update-demo", updateDemoSelector, getUDData("kitten.jpg", ns), ns)
|
||||
validateController(c, kittenImage, 2, "update-demo", updateDemoSelector, getUDData("kitten.jpg", ns), ns)
|
||||
// Everything will hopefully be cleaned up when the namespace is deleted.
|
||||
})
|
||||
})
|
||||
@ -1565,7 +1612,7 @@ metadata:
|
||||
|
||||
debugDiscovery()
|
||||
runKubectlRetryOrDie("rolling-update", rcName, "--update-period=1s", "--image="+httpdImage, "--image-pull-policy="+string(v1.PullIfNotPresent), nsFlag)
|
||||
framework.ValidateController(c, httpdImage, 1, rcName, "run="+rcName, noOpValidatorFn, ns)
|
||||
validateController(c, httpdImage, 1, rcName, "run="+rcName, noOpValidatorFn, ns)
|
||||
})
|
||||
})
|
||||
|
||||
@ -2367,49 +2414,71 @@ func createApplyCustomResource(resource, namespace, name string, crd *crd.TestCr
|
||||
return nil
|
||||
}
|
||||
|
||||
var schemaFoo = []byte(`description: Foo CRD for Testing
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
description: Specification of Foo
|
||||
properties:
|
||||
bars:
|
||||
description: List of Bars and their specs.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
description: Name of Bar.
|
||||
type: string
|
||||
age:
|
||||
description: Age of Bar.
|
||||
type: string
|
||||
bazs:
|
||||
description: List of Bazs.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
status:
|
||||
description: Status of Foo
|
||||
type: object
|
||||
properties:
|
||||
bars:
|
||||
description: List of Bars and their statuses.
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Name of Bar.
|
||||
type: string
|
||||
available:
|
||||
description: Whether the Bar is installed.
|
||||
type: boolean
|
||||
quxType:
|
||||
description: Indicates to external qux type.
|
||||
pattern: in-tree|out-of-tree
|
||||
type: string`)
|
||||
// trimDockerRegistry is the function for trimming the docker.io/library from the beginning of the imagename.
|
||||
// If community docker installed it will not prefix the registry names with the dockerimages vs registry names prefixed with other runtimes or docker installed via RHEL extra repo.
|
||||
// So this function will help to trim the docker.io/library if exists
|
||||
func trimDockerRegistry(imagename string) string {
|
||||
imagename = strings.Replace(imagename, "docker.io/", "", 1)
|
||||
return strings.Replace(imagename, "library/", "", 1)
|
||||
}
|
||||
|
||||
// validatorFn is the function which is individual tests will implement.
|
||||
// we may want it to return more than just an error, at some point.
|
||||
type validatorFn func(c clientset.Interface, podID string) error
|
||||
|
||||
// validateController is a generic mechanism for testing RC's that are running.
|
||||
// It takes a container name, a test name, and a validator function which is plugged in by a specific test.
|
||||
// "containername": this is grepped for.
|
||||
// "containerImage" : this is the name of the image we expect to be launched. Not to confuse w/ images (kitten.jpg) which are validated.
|
||||
// "testname": which gets bubbled up to the logging/failure messages if errors happen.
|
||||
// "validator" function: This function is given a podID and a client, and it can do some specific validations that way.
|
||||
func validateController(c clientset.Interface, containerImage string, replicas int, containername string, testname string, validator validatorFn, ns string) {
|
||||
containerImage = trimDockerRegistry(containerImage)
|
||||
getPodsTemplate := "--template={{range.items}}{{.metadata.name}} {{end}}"
|
||||
|
||||
getContainerStateTemplate := fmt.Sprintf(`--template={{if (exists . "status" "containerStatuses")}}{{range .status.containerStatuses}}{{if (and (eq .name "%s") (exists . "state" "running"))}}true{{end}}{{end}}{{end}}`, containername)
|
||||
|
||||
getImageTemplate := fmt.Sprintf(`--template={{if (exists . "spec" "containers")}}{{range .spec.containers}}{{if eq .name "%s"}}{{.image}}{{end}}{{end}}{{end}}`, containername)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("waiting for all containers in %s pods to come up.", testname)) //testname should be selector
|
||||
waitLoop:
|
||||
for start := time.Now(); time.Since(start) < framework.PodStartTimeout; time.Sleep(5 * time.Second) {
|
||||
getPodsOutput := framework.RunKubectlOrDie("get", "pods", "-o", "template", getPodsTemplate, "-l", testname, fmt.Sprintf("--namespace=%v", ns))
|
||||
pods := strings.Fields(getPodsOutput)
|
||||
if numPods := len(pods); numPods != replicas {
|
||||
ginkgo.By(fmt.Sprintf("Replicas for %s: expected=%d actual=%d", testname, replicas, numPods))
|
||||
continue
|
||||
}
|
||||
var runningPods []string
|
||||
for _, podID := range pods {
|
||||
running := framework.RunKubectlOrDie("get", "pods", podID, "-o", "template", getContainerStateTemplate, fmt.Sprintf("--namespace=%v", ns))
|
||||
if running != "true" {
|
||||
framework.Logf("%s is created but not running", podID)
|
||||
continue waitLoop
|
||||
}
|
||||
|
||||
currentImage := framework.RunKubectlOrDie("get", "pods", podID, "-o", "template", getImageTemplate, fmt.Sprintf("--namespace=%v", ns))
|
||||
currentImage = trimDockerRegistry(currentImage)
|
||||
if currentImage != containerImage {
|
||||
framework.Logf("%s is created but running wrong image; expected: %s, actual: %s", podID, containerImage, currentImage)
|
||||
continue waitLoop
|
||||
}
|
||||
|
||||
// Call the generic validator function here.
|
||||
// This might validate for example, that (1) getting a url works and (2) url is serving correct content.
|
||||
if err := validator(c, podID); err != nil {
|
||||
framework.Logf("%s is running right image but validator function failed: %v", podID, err)
|
||||
continue waitLoop
|
||||
}
|
||||
|
||||
framework.Logf("%s is verified up and running", podID)
|
||||
runningPods = append(runningPods, podID)
|
||||
}
|
||||
// If we reach here, then all our checks passed.
|
||||
if len(runningPods) == replicas {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Reaching here means that one of more checks failed multiple times. Assuming its not a race condition, something is broken.
|
||||
framework.Failf("Timed out after %v seconds waiting for %s pods to reach valid state", framework.PodStartTimeout.Seconds(), testname)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user