Merge pull request #99004 from smarterclayton/simplify_debug

kubectl: exec and attach break scripting and should honor `--quiet`
This commit is contained in:
Kubernetes Prow Robot 2021-03-05 11:21:53 -08:00 committed by GitHub
commit 9cc3665bd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 191 additions and 131 deletions

View File

@ -23,7 +23,6 @@ import (
"time"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -33,6 +32,7 @@ import (
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/cmd/exec"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
@ -68,9 +68,7 @@ type AttachOptions struct {
// whether to disable use of standard error when streaming output from tty
DisableStderr bool
CommandName string
ParentCommandName string
EnableSuggestedCmdUsage bool
CommandName string
Pod *corev1.Pod
@ -115,6 +113,7 @@ func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
cmd.Flags().StringVarP(&o.ContainerName, "container", "c", o.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")
cmd.Flags().BoolVarP(&o.Stdin, "stdin", "i", o.Stdin, "Pass stdin to the container")
cmd.Flags().BoolVarP(&o.TTY, "tty", "t", o.TTY, "Stdin is a TTY")
cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "Only print output from the remote session")
return cmd
}
@ -184,14 +183,6 @@ func (o *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []s
o.Resources = args
o.restClientGetter = f
cmdParent := cmd.Parent()
if cmdParent != nil {
o.ParentCommandName = cmdParent.CommandPath()
}
if len(o.ParentCommandName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "describe") {
o.EnableSuggestedCmdUsage = true
}
config, err := f.ToRESTConfig()
if err != nil {
return err
@ -257,8 +248,8 @@ func (o *AttachOptions) Run() error {
}
if o.TTY && !containerToAttach.TTY {
o.TTY = false
if o.ErrOut != nil {
fmt.Fprintf(o.ErrOut, "Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
if !o.Quiet && o.ErrOut != nil {
fmt.Fprintf(o.ErrOut, "error: Unable to use a TTY - container %s did not allocate one\n", containerToAttach.Name)
}
} else if !o.TTY && containerToAttach.TTY {
// the container was launched with a TTY, so we have to force a TTY here, otherwise you'll get
@ -292,7 +283,7 @@ func (o *AttachOptions) Run() error {
return err
}
if o.Stdin && t.Raw && o.Pod.Spec.RestartPolicy == corev1.RestartPolicyAlways {
if !o.Quiet && o.Stdin && t.Raw && o.Pod.Spec.RestartPolicy == corev1.RestartPolicyAlways {
fmt.Fprintf(o.Out, "Session ended, resume using '%s %s -c %s -i -t' command when the pod is running\n", o.CommandName, o.Pod.Name, containerToAttach.Name)
}
return nil
@ -311,32 +302,7 @@ func (o *AttachOptions) findAttachablePod(obj runtime.Object) (*corev1.Pod, erro
// containerToAttach returns a reference to the container to attach to, given
// by name or the first container if name is empty.
func (o *AttachOptions) containerToAttachTo(pod *corev1.Pod) (*corev1.Container, error) {
if len(o.ContainerName) > 0 {
for i := range pod.Spec.Containers {
if pod.Spec.Containers[i].Name == o.ContainerName {
return &pod.Spec.Containers[i], nil
}
}
for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].Name == o.ContainerName {
return &pod.Spec.InitContainers[i], nil
}
}
for i := range pod.Spec.EphemeralContainers {
if pod.Spec.EphemeralContainers[i].Name == o.ContainerName {
return (*corev1.Container)(&pod.Spec.EphemeralContainers[i].EphemeralContainerCommon), nil
}
}
return nil, fmt.Errorf("container not found (%s)", o.ContainerName)
}
if o.EnableSuggestedCmdUsage {
fmt.Fprintf(o.ErrOut, "Defaulting container name to %s.\n", pod.Spec.Containers[0].Name)
fmt.Fprintf(o.ErrOut, "Use '%s describe pod/%s -n %s' to see all of the containers in this pod.\n", o.ParentCommandName, o.PodName, o.Namespace)
}
klog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
return &pod.Spec.Containers[0], nil
return podcmd.FindOrDefaultContainerByName(pod, o.ContainerName, o.Quiet, o.ErrOut)
}
// GetContainerName returns the name of the container to attach to, with a fallback.

View File

@ -17,6 +17,7 @@ limitations under the License.
package attach
import (
"bytes"
"fmt"
"io"
"net/http"
@ -35,6 +36,7 @@ import (
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/cmd/exec"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
)
@ -65,6 +67,7 @@ func TestPodAndContainerAttach(t *testing.T) {
expectError string
expectedPodName string
expectedContainerName string
expectOut string
obj *corev1.Pod
}{
{
@ -85,6 +88,25 @@ func TestPodAndContainerAttach(t *testing.T) {
expectedPodName: "foo",
expectedContainerName: "bar",
obj: attachPod(),
expectOut: `Defaulted container "bar" out of: bar, debugger (ephem), initfoo (init)`,
},
{
name: "no container, no flags, sets default expected container as annotation",
options: &AttachOptions{GetPodTimeout: defaultPodLogsTimeout},
args: []string{"foo"},
expectedPodName: "foo",
expectedContainerName: "bar",
obj: setDefaultContainer(attachPod(), "initfoo"),
expectOut: ``,
},
{
name: "no container, no flags, sets default missing container as annotation",
options: &AttachOptions{GetPodTimeout: defaultPodLogsTimeout},
args: []string{"foo"},
expectedPodName: "foo",
expectedContainerName: "bar",
obj: setDefaultContainer(attachPod(), "does-not-exist"),
expectOut: `Defaulted container "bar" out of: bar, debugger (ephem), initfoo (init)`,
},
{
name: "container in flag",
@ -115,7 +137,7 @@ func TestPodAndContainerAttach(t *testing.T) {
options: &AttachOptions{StreamOptions: exec.StreamOptions{ContainerName: "wrong"}, GetPodTimeout: 10},
args: []string{"foo"},
expectedPodName: "foo",
expectError: "container not found",
expectError: "container wrong not found in pod foo",
obj: attachPod(),
},
{
@ -153,11 +175,23 @@ func TestPodAndContainerAttach(t *testing.T) {
pod, err := test.options.findAttachablePod(&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "test"},
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{
{
Name: "initfoo",
},
},
Containers: []corev1.Container{
{
Name: "foobar",
},
},
EphemeralContainers: []corev1.EphemeralContainer{
{
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Name: "ephemfoo",
},
},
},
},
})
if err != nil {
@ -171,10 +205,17 @@ func TestPodAndContainerAttach(t *testing.T) {
t.Errorf("unexpected pod name: expected %q, got %q", test.expectedContainerName, pod.Name)
}
var buf bytes.Buffer
test.options.ErrOut = &buf
container, err := test.options.containerToAttachTo(attachPod())
if len(test.expectOut) > 0 && !strings.Contains(buf.String(), test.expectOut) {
t.Errorf("unexpected output: output did not contain %q\n---\n%s", test.expectOut, buf.String())
}
if err != nil {
if test.expectError == "" || !strings.Contains(err.Error(), test.expectError) {
t.Errorf("unexpected error: expected %q, got %q", err, test.expectError)
t.Errorf("unexpected error: expected %q, got %q", test.expectError, err)
}
return
}
@ -230,7 +271,7 @@ func TestAttach(t *testing.T) {
attachPath: "/api/" + version + "/namespaces/test/pods/foo/attach",
pod: attachPod(),
container: "foo",
expectedErr: "cannot attach to the container: container not found (foo)",
expectedErr: "cannot attach to the container: container foo not found in pod foo",
},
}
for _, test := range tests {
@ -435,3 +476,11 @@ func attachPod() *corev1.Pod {
},
}
}
func setDefaultContainer(pod *corev1.Pod, name string) *corev1.Pod {
if pod.Annotations == nil {
pod.Annotations = make(map[string]string)
}
pod.Annotations[podcmd.DefaultContainerAnnotationName] = name
return pod
}

View File

@ -34,6 +34,7 @@ import (
"k8s.io/client-go/tools/remotecommand"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
@ -100,6 +101,7 @@ func NewCmdExec(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
cmd.Flags().StringVarP(&options.ContainerName, "container", "c", options.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", options.Stdin, "Pass stdin to the container")
cmd.Flags().BoolVarP(&options.TTY, "tty", "t", options.TTY, "Stdin is a TTY")
cmd.Flags().BoolVarP(&options.Quiet, "quiet", "q", options.Quiet, "Only print output from the remote session")
return cmd
}
@ -152,9 +154,6 @@ type ExecOptions struct {
Command []string
EnforceNamespace bool
ParentCommandName string
EnableSuggestedCmdUsage bool
Builder func() *resource.Builder
ExecutablePodFn polymorphichelpers.AttachablePodForObjectFunc
restClientGetter genericclioptions.RESTClientGetter
@ -174,10 +173,14 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
if argsLenAtDash > -1 {
p.Command = argsIn[argsLenAtDash:]
} else if len(argsIn) > 1 {
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.\n")
if !p.Quiet {
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.\n")
}
p.Command = argsIn[1:]
} else if len(argsIn) > 0 && len(p.FilenameOptions.Filenames) != 0 {
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.\n")
if !p.Quiet {
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.\n")
}
p.Command = argsIn[0:]
p.ResourceName = ""
}
@ -198,14 +201,6 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
p.Builder = f.NewBuilder
p.restClientGetter = f
cmdParent := cmd.Parent()
if cmdParent != nil {
p.ParentCommandName = cmdParent.CommandPath()
}
if len(p.ParentCommandName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "describe") {
p.EnableSuggestedCmdUsage = true
}
p.Config, err = f.ToRESTConfig()
if err != nil {
return err
@ -260,7 +255,7 @@ func (o *StreamOptions) SetupTTY() term.TTY {
if !o.isTerminalIn(t) {
o.TTY = false
if o.ErrOut != nil {
if !o.Quiet && o.ErrOut != nil {
fmt.Fprintln(o.ErrOut, "Unable to use a TTY - input is not a terminal or the right kind of file")
}
@ -323,7 +318,14 @@ func (p *ExecOptions) Run() error {
return fmt.Errorf("cannot exec into a container in a completed pod; current phase is %s", pod.Status.Phase)
}
containerName := getDefaultContainerName(p, pod)
containerName := p.ContainerName
if len(containerName) == 0 {
container, err := podcmd.FindOrDefaultContainerByName(pod, containerName, p.Quiet, p.ErrOut)
if err != nil {
return err
}
containerName = container.Name
}
// ensure we can recover the terminal while attached
t := p.SetupTTY()
@ -368,12 +370,3 @@ func (p *ExecOptions) Run() error {
return nil
}
func getDefaultContainerName(p *ExecOptions, pod *corev1.Pod) string {
containerName := p.ContainerName
if len(containerName) != 0 {
return containerName
}
return cmdutil.GetDefaultContainerName(pod, p.EnableSuggestedCmdUsage, p.ErrOut)
}

View File

@ -30,7 +30,6 @@ import (
jsonpatch "github.com/evanphx/json-patch"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -45,7 +44,6 @@ import (
"k8s.io/client-go/scale"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/util/podutils"
utilexec "k8s.io/utils/exec"
)
@ -746,28 +744,3 @@ func Warning(cmdErr io.Writer, newGeneratorName, oldGeneratorName string) {
oldGeneratorName,
)
}
// GetDefaultContainerName returns the default container name for a pod.
// it checks the annotation kubectl.kubernetes.io/default-container at first and then the first container name.
func GetDefaultContainerName(pod *corev1.Pod, enableSuggestedCmdUsage bool, w io.Writer) string {
if len(pod.Spec.Containers) > 1 {
// in case the "kubectl.kubernetes.io/default-container" annotation is present, we preset the opts.Containers to default to selected
// container. This gives users ability to preselect the most interesting container in pod.
if annotations := pod.Annotations; annotations != nil && len(annotations[podutils.DefaultContainerAnnotationName]) > 0 {
containerName := annotations[podutils.DefaultContainerAnnotationName]
if exists, _ := podutils.FindContainerByName(pod, containerName); exists != nil {
fmt.Fprintf(w, "Defaulting container name to container %s.\n", containerName)
return containerName
} else {
fmt.Fprintf(w, "Default container name %q in annotation not found in a pod\n", containerName)
}
}
fmt.Fprintf(w, "Defaulting container name to first container %s.\n", pod.Spec.Containers[0].Name)
if enableSuggestedCmdUsage {
fmt.Fprintf(w, "Use 'kubectl describe pod/%s -n %s' to see all of the containers in this pod.\n", pod.Name, pod.Namespace)
}
}
return pod.Spec.Containers[0].Name
}

View File

@ -0,0 +1,104 @@
/*
Copyright 2021 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 podcmd
import (
"fmt"
"io"
"strings"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
)
// DefaultContainerAnnotationName is an annotation name that can be used to preselect the interesting container
// from a pod when running kubectl.
const DefaultContainerAnnotationName = "kubectl.kubernetes.io/default-container"
// FindContainerByName selects the named container from the spec of
// the provided pod or return nil if no such container exists.
func FindContainerByName(pod *v1.Pod, name string) (*v1.Container, string) {
for i := range pod.Spec.Containers {
if pod.Spec.Containers[i].Name == name {
return &pod.Spec.Containers[i], fmt.Sprintf("spec.containers{%s}", name)
}
}
for i := range pod.Spec.InitContainers {
if pod.Spec.InitContainers[i].Name == name {
return &pod.Spec.InitContainers[i], fmt.Sprintf("spec.initContainers{%s}", name)
}
}
for i := range pod.Spec.EphemeralContainers {
if pod.Spec.EphemeralContainers[i].Name == name {
return (*v1.Container)(&pod.Spec.EphemeralContainers[i].EphemeralContainerCommon), fmt.Sprintf("spec.ephemeralContainers{%s}", name)
}
}
return nil, ""
}
// FindOrDefaultContainerByName defaults a container for a pod to the first container if any
// exists, or returns an error. It will print a message to the user indicating a default was
// selected if there was more than one container.
func FindOrDefaultContainerByName(pod *v1.Pod, name string, quiet bool, warn io.Writer) (*v1.Container, error) {
var container *v1.Container
if len(name) > 0 {
container, _ = FindContainerByName(pod, name)
if container == nil {
return nil, fmt.Errorf("container %s not found in pod %s", name, pod.Name)
}
return container, nil
}
// this should never happen, but just in case
if len(pod.Spec.Containers) == 0 {
return nil, fmt.Errorf("pod %s/%s does not have any containers", pod.Namespace, pod.Name)
}
// read the default container the annotation as per
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/2227-kubectl-default-container
if name := pod.Annotations[DefaultContainerAnnotationName]; len(name) > 0 {
if container, _ = FindContainerByName(pod, name); container != nil {
klog.V(4).Infof("Defaulting container name from annotation %s", container.Name)
return container, nil
}
klog.V(4).Infof("Default container name from annotation %s was not found in the pod", name)
}
// pick the first container as per existing behavior
container = &pod.Spec.Containers[0]
if !quiet && (len(pod.Spec.Containers) > 1 || len(pod.Spec.InitContainers) > 0 || len(pod.Spec.EphemeralContainers) > 0) {
fmt.Fprintf(warn, "Defaulted container %q out of: %s\n", container.Name, allContainerNames(pod))
}
klog.V(4).Infof("Defaulting container name to %s", container.Name)
return &pod.Spec.Containers[0], nil
}
func allContainerNames(pod *v1.Pod) string {
var containers []string
for _, container := range pod.Spec.Containers {
containers = append(containers, container.Name)
}
for _, container := range pod.Spec.EphemeralContainers {
containers = append(containers, fmt.Sprintf("%s (ephem)", container.Name))
}
for _, container := range pod.Spec.InitContainers {
containers = append(containers, fmt.Sprintf("%s (init)", container.Name))
}
return strings.Join(containers, ", ")
}

View File

@ -30,6 +30,7 @@ import (
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/reference"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/podutils"
)
@ -79,8 +80,8 @@ func logsForObjectWithClient(clientset corev1client.CoreV1Interface, object, opt
// container. This gives users ability to preselect the most interesting container in pod.
if annotations := t.GetAnnotations(); annotations != nil && len(opts.Container) == 0 {
var containerName string
if len(annotations[podutils.DefaultContainerAnnotationName]) > 0 {
containerName = annotations[podutils.DefaultContainerAnnotationName]
if len(annotations[podcmd.DefaultContainerAnnotationName]) > 0 {
containerName = annotations[podcmd.DefaultContainerAnnotationName]
} else if len(annotations[defaultLogsContainerAnnotationName]) > 0 {
// Only log deprecation if we have only the old annotation. This allows users to
// set both to support multiple versions of kubectl; if they are setting both
@ -90,7 +91,7 @@ func logsForObjectWithClient(clientset corev1client.CoreV1Interface, object, opt
fmt.Fprintf(os.Stderr, "Using deprecated annotation `kubectl.kubernetes.io/default-logs-container` in pod/%v. Please use `kubectl.kubernetes.io/default-container` instead\n", t.Name)
}
if len(containerName) > 0 {
if exists, _ := podutils.FindContainerByName(t, containerName); exists != nil {
if exists, _ := podcmd.FindContainerByName(t, containerName); exists != nil {
opts.Container = containerName
} else {
fmt.Fprintf(os.Stderr, "Default container name %q not found in a pod\n", containerName)
@ -121,7 +122,7 @@ func logsForObjectWithClient(clientset corev1client.CoreV1Interface, object, opt
containerName = opts.Container
}
container, fieldPath := podutils.FindContainerByName(t, containerName)
container, fieldPath := podcmd.FindContainerByName(t, containerName)
if container == nil {
return nil, fmt.Errorf("container %s is not valid for pod %s", opts.Container, t.Name)
}

View File

@ -32,7 +32,7 @@ import (
"k8s.io/apimachinery/pkg/util/diff"
fakeexternal "k8s.io/client-go/kubernetes/fake"
testclient "k8s.io/client-go/testing"
"k8s.io/kubectl/pkg/util/podutils"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
)
var (
@ -430,7 +430,7 @@ func TestLogsForObjectWithClient(t *testing.T) {
name: "two container pod with default container selected",
podFn: func() *corev1.Pod {
pod := testPodWithTwoContainers()
pod.Annotations = map[string]string{podutils.DefaultContainerAnnotationName: "foo-2-c1"}
pod.Annotations = map[string]string{podcmd.DefaultContainerAnnotationName: "foo-2-c1"}
return pod
},
podLogOptions: &corev1.PodLogOptions{},
@ -440,7 +440,7 @@ func TestLogsForObjectWithClient(t *testing.T) {
name: "two container pod with default container selected but also container set explicitly",
podFn: func() *corev1.Pod {
pod := testPodWithTwoContainers()
pod.Annotations = map[string]string{podutils.DefaultContainerAnnotationName: "foo-2-c1"}
pod.Annotations = map[string]string{podcmd.DefaultContainerAnnotationName: "foo-2-c1"}
return pod
},
podLogOptions: &corev1.PodLogOptions{
@ -452,7 +452,7 @@ func TestLogsForObjectWithClient(t *testing.T) {
name: "two container pod with non-existing default container selected",
podFn: func() *corev1.Pod {
pod := testPodWithTwoContainers()
pod.Annotations = map[string]string{podutils.DefaultContainerAnnotationName: "non-existing"}
pod.Annotations = map[string]string{podcmd.DefaultContainerAnnotationName: "non-existing"}
return pod
},
podLogOptions: &corev1.PodLogOptions{},
@ -462,7 +462,7 @@ func TestLogsForObjectWithClient(t *testing.T) {
name: "two container pod with default container set, but allContainers also set",
podFn: func() *corev1.Pod {
pod := testPodWithTwoContainers()
pod.Annotations = map[string]string{podutils.DefaultContainerAnnotationName: "foo-2-c1"}
pod.Annotations = map[string]string{podcmd.DefaultContainerAnnotationName: "foo-2-c1"}
return pod
},
allContainers: true,

View File

@ -17,7 +17,6 @@ limitations under the License.
package podutils
import (
"fmt"
"time"
corev1 "k8s.io/api/core/v1"
@ -25,10 +24,6 @@ import (
"k8s.io/utils/integer"
)
// DefaultContainerAnnotationName is an annotation name that can be used to preselect the interesting container
// from a pod when running kubectl.
const DefaultContainerAnnotationName = "kubectl.kubernetes.io/default-container"
// IsPodAvailable returns true if a pod is available; false otherwise.
// Precondition for an available pod is that it must be ready. On top
// of that, there are two cases when a pod can be considered available:
@ -191,25 +186,3 @@ func maxContainerRestarts(pod *corev1.Pod) int {
}
return maxRestarts
}
// FindContainerByName searches for a container by name amongst all containers in a pod.
// Returns a pointer to a container and a field path.
func FindContainerByName(pod *corev1.Pod, name string) (container *corev1.Container, fieldPath string) {
for _, c := range pod.Spec.InitContainers {
if c.Name == name {
return &c, fmt.Sprintf("spec.initContainers{%s}", c.Name)
}
}
for _, c := range pod.Spec.Containers {
if c.Name == name {
return &c, fmt.Sprintf("spec.containers{%s}", c.Name)
}
}
for _, c := range pod.Spec.EphemeralContainers {
if c.Name == name {
containerCommon := corev1.Container(c.EphemeralContainerCommon)
return &containerCommon, fmt.Sprintf("spec.ephemeralContainers{%s}", containerCommon.Name)
}
}
return nil, ""
}

1
vendor/modules.txt vendored
View File

@ -2407,6 +2407,7 @@ k8s.io/kubectl/pkg/cmd/top
k8s.io/kubectl/pkg/cmd/util
k8s.io/kubectl/pkg/cmd/util/editor
k8s.io/kubectl/pkg/cmd/util/editor/crlf
k8s.io/kubectl/pkg/cmd/util/podcmd
k8s.io/kubectl/pkg/cmd/util/sanity
k8s.io/kubectl/pkg/cmd/version
k8s.io/kubectl/pkg/cmd/wait