...

Source file src/k8s.io/kubectl/pkg/cmd/util/podcmd/podcmd.go

Documentation: k8s.io/kubectl/pkg/cmd/util/podcmd

     1  /*
     2  Copyright 2021 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package podcmd
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"strings"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	"k8s.io/klog/v2"
    26  )
    27  
    28  // DefaultContainerAnnotationName is an annotation name that can be used to preselect the interesting container
    29  // from a pod when running kubectl.
    30  const DefaultContainerAnnotationName = "kubectl.kubernetes.io/default-container"
    31  
    32  // FindContainerByName selects the named container from the spec of
    33  // the provided pod or return nil if no such container exists.
    34  func FindContainerByName(pod *v1.Pod, name string) (*v1.Container, string) {
    35  	for i := range pod.Spec.Containers {
    36  		if pod.Spec.Containers[i].Name == name {
    37  			return &pod.Spec.Containers[i], fmt.Sprintf("spec.containers{%s}", name)
    38  		}
    39  	}
    40  	for i := range pod.Spec.InitContainers {
    41  		if pod.Spec.InitContainers[i].Name == name {
    42  			return &pod.Spec.InitContainers[i], fmt.Sprintf("spec.initContainers{%s}", name)
    43  		}
    44  	}
    45  	for i := range pod.Spec.EphemeralContainers {
    46  		if pod.Spec.EphemeralContainers[i].Name == name {
    47  			return (*v1.Container)(&pod.Spec.EphemeralContainers[i].EphemeralContainerCommon), fmt.Sprintf("spec.ephemeralContainers{%s}", name)
    48  		}
    49  	}
    50  	return nil, ""
    51  }
    52  
    53  // FindOrDefaultContainerByName defaults a container for a pod to the first container if any
    54  // exists, or returns an error. It will print a message to the user indicating a default was
    55  // selected if there was more than one container.
    56  func FindOrDefaultContainerByName(pod *v1.Pod, name string, quiet bool, warn io.Writer) (*v1.Container, error) {
    57  	var container *v1.Container
    58  
    59  	if len(name) > 0 {
    60  		container, _ = FindContainerByName(pod, name)
    61  		if container == nil {
    62  			return nil, fmt.Errorf("container %s not found in pod %s", name, pod.Name)
    63  		}
    64  		return container, nil
    65  	}
    66  
    67  	// this should never happen, but just in case
    68  	if len(pod.Spec.Containers) == 0 {
    69  		return nil, fmt.Errorf("pod %s/%s does not have any containers", pod.Namespace, pod.Name)
    70  	}
    71  
    72  	// read the default container the annotation as per
    73  	// https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/2227-kubectl-default-container
    74  	if name := pod.Annotations[DefaultContainerAnnotationName]; len(name) > 0 {
    75  		if container, _ = FindContainerByName(pod, name); container != nil {
    76  			klog.V(4).Infof("Defaulting container name from annotation %s", container.Name)
    77  			return container, nil
    78  		}
    79  		klog.V(4).Infof("Default container name from annotation %s was not found in the pod", name)
    80  	}
    81  
    82  	// pick the first container as per existing behavior
    83  	container = &pod.Spec.Containers[0]
    84  	if !quiet && (len(pod.Spec.Containers) > 1 || len(pod.Spec.InitContainers) > 0 || len(pod.Spec.EphemeralContainers) > 0) {
    85  		fmt.Fprintf(warn, "Defaulted container %q out of: %s\n", container.Name, AllContainerNames(pod))
    86  	}
    87  
    88  	klog.V(4).Infof("Defaulting container name to %s", container.Name)
    89  	return &pod.Spec.Containers[0], nil
    90  }
    91  
    92  func AllContainerNames(pod *v1.Pod) string {
    93  	var containers []string
    94  	for _, container := range pod.Spec.Containers {
    95  		containers = append(containers, container.Name)
    96  	}
    97  	for _, container := range pod.Spec.EphemeralContainers {
    98  		containers = append(containers, fmt.Sprintf("%s (ephem)", container.Name))
    99  	}
   100  	for _, container := range pod.Spec.InitContainers {
   101  		containers = append(containers, fmt.Sprintf("%s (init)", container.Name))
   102  	}
   103  	return strings.Join(containers, ", ")
   104  }
   105  

View as plain text