Skip to content

Commit

Permalink
Create node_e2e test for ephemeral containers
Browse files Browse the repository at this point in the history
  • Loading branch information
verb committed Sep 27, 2021
1 parent 6a71f85 commit da8ddb7
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 0 deletions.
17 changes: 17 additions & 0 deletions test/e2e/framework/pod/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,23 @@ func podContainerStarted(c clientset.Interface, namespace, podName string, conta
}
}

func isContainerRunning(c clientset.Interface, namespace, podName, containerName string) wait.ConditionFunc {
return func() (bool, error) {
pod, err := c.CoreV1().Pods(namespace).Get(context.TODO(), podName, metav1.GetOptions{})
if err != nil {
return false, err
}
for _, statuses := range [][]v1.ContainerStatus{pod.Status.ContainerStatuses, pod.Status.InitContainerStatuses, pod.Status.EphemeralContainerStatuses} {
for _, cs := range statuses {
if cs.Name == containerName {
return cs.State.Running != nil, nil
}
}
}
return false, nil
}
}

// LogPodStates logs basic info of provided pods for debugging.
func LogPodStates(pods []v1.Pod) {
// Find maximum widths for pod, node, and phase strings for column printing.
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/framework/pod/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,8 @@ func WaitForPodFailedReason(c clientset.Interface, pod *v1.Pod, reason string, t
}
return nil
}

// WaitForContainerRunning waits for the given Pod container to have a state of running
func WaitForContainerRunning(c clientset.Interface, namespace, podName, containerName string, timeout time.Duration) error {
return wait.PollImmediate(poll, timeout, isContainerRunning(c, namespace, podName, containerName))
}
24 changes: 24 additions & 0 deletions test/e2e/framework/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package framework

import (
"context"
"encoding/json"
"fmt"
"regexp"
"sync"
Expand All @@ -27,7 +28,9 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes/scheme"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
Expand Down Expand Up @@ -146,6 +149,27 @@ func (c *PodClient) Update(name string, updateFn func(pod *v1.Pod)) {
}))
}

// AddEphemeralContainerSync adds an EphemeralContainer to a pod and waits for it to be running.
func (c *PodClient) AddEphemeralContainerSync(pod *v1.Pod, ec *v1.EphemeralContainer, timeout time.Duration) {
namespace := c.f.Namespace.Name

podJS, err := json.Marshal(pod)
ExpectNoError(err, "error creating JSON for pod: %v", err)

ecPod := pod.DeepCopy()
ecPod.Spec.EphemeralContainers = append(ecPod.Spec.EphemeralContainers, *ec)
ecJS, err := json.Marshal(ecPod)
ExpectNoError(err, "error creating JSON for pod with ephemeral container: %v", err)

patch, err := strategicpatch.CreateTwoWayMergePatch(podJS, ecJS, pod)
ExpectNoError(err, "error creating patch to add ephemeral container: %v", err)

_, err = c.Patch(context.TODO(), pod.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{}, "ephemeralcontainers")
ExpectNoError(err, "Failed to patch ephemeral containers in pod %q: %v", pod.Name, err)

ExpectNoError(e2epod.WaitForContainerRunning(c.f.ClientSet, namespace, pod.Name, ec.Name, timeout))
}

// DeleteSync deletes the pod and wait for the pod to disappear for `timeout`. If the pod doesn't
// disappear before the timeout, it will fail the test.
func (c *PodClient) DeleteSync(name string, options metav1.DeleteOptions, timeout time.Duration) {
Expand Down
69 changes: 69 additions & 0 deletions test/e2e_node/ephemeral_containers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
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 e2enode

import (
"time"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/test/e2e/framework"
imageutils "k8s.io/kubernetes/test/utils/image"

"github.com/onsi/ginkgo"
)

var _ = SIGDescribe("Ephemeral Containers [Feature:EphemeralContainers][NodeAlphaFeature:EphemeralContainers]", func() {
f := framework.NewDefaultFramework("ephemeral-containers-test")
var podClient *framework.PodClient
ginkgo.BeforeEach(func() {
podClient = f.PodClient()
})

ginkgo.It("will start an ephemeral container in an existing pod", func() {
ginkgo.By("creating a target pod")
pod := podClient.CreateSync(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "ephemeral-containers-target-pod"},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "test-container-1",
Image: imageutils.GetE2EImage(imageutils.BusyBox),
Command: []string{"/bin/sleep"},
Args: []string{"10000"},
},
},
},
})

ginkgo.By("adding an ephemeral container")
ec := &v1.EphemeralContainer{
EphemeralContainerCommon: v1.EphemeralContainerCommon{
Name: "debugger",
Image: imageutils.GetE2EImage(imageutils.BusyBox),
Command: []string{"/bin/sh"},
Stdin: true,
TTY: true,
},
}
podClient.AddEphemeralContainerSync(pod, ec, time.Minute)

ginkgo.By("confirm that the container is really running")
marco := f.ExecCommandInContainer(pod.Name, "debugger", "/bin/echo", "polo")
framework.ExpectEqual(marco, "polo")
})
})

0 comments on commit da8ddb7

Please sign in to comment.