mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
Merge pull request #90448 from soltysh/issue87851
Fix run command when waiting for pods
This commit is contained in:
commit
b68bf25531
@ -355,21 +355,6 @@ func waitForEphemeralContainer(ctx context.Context, podClient corev1client.PodsG
|
|||||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(ctx, 0*time.Second)
|
ctx, cancel := watchtools.ContextWithOptionalTimeout(ctx, 0*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
preconditionFunc := func(store cache.Store) (bool, error) {
|
|
||||||
_, exists, err := store.Get(&metav1.ObjectMeta{Namespace: ns, Name: podName})
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
// We need to make sure we see the object in the cache before we start waiting for events
|
|
||||||
// or we would be waiting for the timeout if such object didn't exist.
|
|
||||||
// (e.g. it was deleted before we started informers so they wouldn't even see the delete event)
|
|
||||||
return true, errors.NewNotFound(corev1.Resource("pods"), podName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldSelector := fields.OneTermEqualSelector("metadata.name", podName).String()
|
fieldSelector := fields.OneTermEqualSelector("metadata.name", podName).String()
|
||||||
lw := &cache.ListWatch{
|
lw := &cache.ListWatch{
|
||||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||||
@ -385,7 +370,7 @@ func waitForEphemeralContainer(ctx context.Context, podClient corev1client.PodsG
|
|||||||
intr := interrupt.New(nil, cancel)
|
intr := interrupt.New(nil, cancel)
|
||||||
var result *corev1.Pod
|
var result *corev1.Pod
|
||||||
err := intr.Run(func() error {
|
err := intr.Run(func() error {
|
||||||
ev, err := watchtools.UntilWithSync(ctx, lw, &corev1.Pod{}, preconditionFunc, func(ev watch.Event) (bool, error) {
|
ev, err := watchtools.UntilWithSync(ctx, lw, &corev1.Pod{}, nil, func(ev watch.Event) (bool, error) {
|
||||||
switch ev.Type {
|
switch ev.Type {
|
||||||
case watch.Deleted:
|
case watch.Deleted:
|
||||||
return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
|
return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
|
||||||
|
@ -21,7 +21,6 @@ go_library(
|
|||||||
"//build/visible_to:pkg_kubectl_cmd_rollout_CONSUMERS",
|
"//build/visible_to:pkg_kubectl_cmd_rollout_CONSUMERS",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
@ -200,25 +199,11 @@ func (o *RolloutStatusOptions) Run() error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
preconditionFunc := func(store cache.Store) (bool, error) {
|
|
||||||
_, exists, err := store.Get(&metav1.ObjectMeta{Namespace: info.Namespace, Name: info.Name})
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
// We need to make sure we see the object in the cache before we start waiting for events
|
|
||||||
// or we would be waiting for the timeout if such object didn't exist.
|
|
||||||
return true, apierrors.NewNotFound(mapping.Resource.GroupResource(), info.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the rollout isn't done yet, keep watching deployment status
|
// if the rollout isn't done yet, keep watching deployment status
|
||||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), o.Timeout)
|
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), o.Timeout)
|
||||||
intr := interrupt.New(nil, cancel)
|
intr := interrupt.New(nil, cancel)
|
||||||
return intr.Run(func() error {
|
return intr.Run(func() error {
|
||||||
_, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, preconditionFunc, func(e watch.Event) (bool, error) {
|
_, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, nil, func(e watch.Event) (bool, error) {
|
||||||
switch t := e.Type; t {
|
switch t := e.Type; t {
|
||||||
case watch.Added, watch.Modified:
|
case watch.Added, watch.Modified:
|
||||||
status, done, err := statusViewer.Status(e.Object.(runtime.Unstructured), o.Revision)
|
status, done, err := statusViewer.Status(e.Object.(runtime.Unstructured), o.Revision)
|
||||||
|
@ -381,17 +381,21 @@ func (o *RunOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pod *corev1.Pod
|
var pod *corev1.Pod
|
||||||
leaveStdinOpen := o.LeaveStdinOpen
|
waitForExitCode := !o.LeaveStdinOpen && (restartPolicy == corev1.RestartPolicyNever || restartPolicy == corev1.RestartPolicyOnFailure)
|
||||||
waitForExitCode := !leaveStdinOpen && restartPolicy == corev1.RestartPolicyNever
|
|
||||||
if waitForExitCode {
|
if waitForExitCode {
|
||||||
pod, err = waitForPod(clientset.CoreV1(), attachablePod.Namespace, attachablePod.Name, opts.GetPodTimeout, podCompleted)
|
// we need different exit condition depending on restart policy
|
||||||
|
// for Never it can either fail or succeed, for OnFailure only
|
||||||
|
// success matters
|
||||||
|
exitCondition := podCompleted
|
||||||
|
if restartPolicy == corev1.RestartPolicyOnFailure {
|
||||||
|
exitCondition = podSucceeded
|
||||||
|
}
|
||||||
|
pod, err = waitForPod(clientset.CoreV1(), attachablePod.Namespace, attachablePod.Name, opts.GetPodTimeout, exitCondition)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// after removal is done, return successfully if we are not interested in the exit code
|
// after removal is done, return successfully if we are not interested in the exit code
|
||||||
if !waitForExitCode {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,21 +461,6 @@ func waitForPod(podClient corev1client.PodsGetter, ns, name string, timeout time
|
|||||||
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
|
ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
preconditionFunc := func(store cache.Store) (bool, error) {
|
|
||||||
_, exists, err := store.Get(&metav1.ObjectMeta{Namespace: ns, Name: name})
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
// We need to make sure we see the object in the cache before we start waiting for events
|
|
||||||
// or we would be waiting for the timeout if such object didn't exist.
|
|
||||||
// (e.g. it was deleted before we started informers so they wouldn't even see the delete event)
|
|
||||||
return true, errors.NewNotFound(corev1.Resource("pods"), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldSelector := fields.OneTermEqualSelector("metadata.name", name).String()
|
fieldSelector := fields.OneTermEqualSelector("metadata.name", name).String()
|
||||||
lw := &cache.ListWatch{
|
lw := &cache.ListWatch{
|
||||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||||
@ -487,9 +476,7 @@ func waitForPod(podClient corev1client.PodsGetter, ns, name string, timeout time
|
|||||||
intr := interrupt.New(nil, cancel)
|
intr := interrupt.New(nil, cancel)
|
||||||
var result *corev1.Pod
|
var result *corev1.Pod
|
||||||
err := intr.Run(func() error {
|
err := intr.Run(func() error {
|
||||||
ev, err := watchtools.UntilWithSync(ctx, lw, &corev1.Pod{}, preconditionFunc, func(ev watch.Event) (bool, error) {
|
ev, err := watchtools.UntilWithSync(ctx, lw, &corev1.Pod{}, nil, exitCondition)
|
||||||
return exitCondition(ev)
|
|
||||||
})
|
|
||||||
if ev != nil {
|
if ev != nil {
|
||||||
result = ev.Object.(*corev1.Pod)
|
result = ev.Object.(*corev1.Pod)
|
||||||
}
|
}
|
||||||
@ -708,6 +695,20 @@ func podCompleted(event watch.Event) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// podSucceeded returns true if the pod has run to completion, false if the pod has not yet
|
||||||
|
// reached running state, or an error in any other case.
|
||||||
|
func podSucceeded(event watch.Event) (bool, error) {
|
||||||
|
switch event.Type {
|
||||||
|
case watch.Deleted:
|
||||||
|
return false, errors.NewNotFound(schema.GroupResource{Resource: "pods"}, "")
|
||||||
|
}
|
||||||
|
switch t := event.Object.(type) {
|
||||||
|
case *corev1.Pod:
|
||||||
|
return t.Status.Phase == corev1.PodSucceeded, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// podRunningAndReady returns true if the pod is running and ready, false if the pod has not
|
// podRunningAndReady returns true if the pod is running and ready, false if the pod has not
|
||||||
// yet reached those states, returns ErrPodCompleted if the pod has run to completion, or
|
// yet reached those states, returns ErrPodCompleted if the pod has run to completion, or
|
||||||
// an error in any other case.
|
// an error in any other case.
|
||||||
|
@ -522,13 +522,21 @@ var _ = SIGDescribe("Kubectl client", func() {
|
|||||||
_, err = framework.NewKubectlCommand(ns, nsFlag, "run", "-i", "--image="+busyboxImage, "--restart=OnFailure", "failure-2", "--", "/bin/sh", "-c", "cat && exit 42").
|
_, err = framework.NewKubectlCommand(ns, nsFlag, "run", "-i", "--image="+busyboxImage, "--restart=OnFailure", "failure-2", "--", "/bin/sh", "-c", "cat && exit 42").
|
||||||
WithStdinData("abcd1234").
|
WithStdinData("abcd1234").
|
||||||
Exec()
|
Exec()
|
||||||
framework.ExpectNoError(err)
|
ee, ok = err.(uexec.ExitError)
|
||||||
|
framework.ExpectEqual(ok, true)
|
||||||
|
if !strings.Contains(ee.String(), "timed out") {
|
||||||
|
framework.Failf("Missing expected 'timed out' error, got: %#v", ee)
|
||||||
|
}
|
||||||
|
|
||||||
ginkgo.By("running a failing command without --restart=Never, but with --rm")
|
ginkgo.By("running a failing command without --restart=Never, but with --rm")
|
||||||
_, err = framework.NewKubectlCommand(ns, nsFlag, "run", "-i", "--image="+busyboxImage, "--restart=OnFailure", "--rm", "failure-3", "--", "/bin/sh", "-c", "cat && exit 42").
|
_, err = framework.NewKubectlCommand(ns, nsFlag, "run", "-i", "--image="+busyboxImage, "--restart=OnFailure", "--rm", "failure-3", "--", "/bin/sh", "-c", "cat && exit 42").
|
||||||
WithStdinData("abcd1234").
|
WithStdinData("abcd1234").
|
||||||
Exec()
|
Exec()
|
||||||
framework.ExpectNoError(err)
|
ee, ok = err.(uexec.ExitError)
|
||||||
|
framework.ExpectEqual(ok, true)
|
||||||
|
if !strings.Contains(ee.String(), "timed out") {
|
||||||
|
framework.Failf("Missing expected 'timed out' error, got: %#v", ee)
|
||||||
|
}
|
||||||
e2epod.WaitForPodToDisappear(f.ClientSet, ns, "failure-3", labels.Everything(), 2*time.Second, wait.ForeverTestTimeout)
|
e2epod.WaitForPodToDisappear(f.ClientSet, ns, "failure-3", labels.Everything(), 2*time.Second, wait.ForeverTestTimeout)
|
||||||
|
|
||||||
ginkgo.By("running a failing command with --leave-stdin-open")
|
ginkgo.By("running a failing command with --leave-stdin-open")
|
||||||
|
Loading…
Reference in New Issue
Block a user