...

Source file src/k8s.io/kubectl/pkg/polymorphichelpers/logsforobject.go

Documentation: k8s.io/kubectl/pkg/polymorphichelpers

     1  /*
     2  Copyright 2018 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 polymorphichelpers
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"sort"
    24  	"time"
    25  
    26  	corev1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/cli-runtime/pkg/genericclioptions"
    29  	corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
    30  	"k8s.io/client-go/rest"
    31  	"k8s.io/client-go/tools/reference"
    32  	"k8s.io/kubectl/pkg/cmd/util/podcmd"
    33  	"k8s.io/kubectl/pkg/scheme"
    34  	"k8s.io/kubectl/pkg/util/podutils"
    35  )
    36  
    37  func logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration, allContainers bool) (map[corev1.ObjectReference]rest.ResponseWrapper, error) {
    38  	clientConfig, err := restClientGetter.ToRESTConfig()
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	clientset, err := corev1client.NewForConfig(clientConfig)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	return logsForObjectWithClient(clientset, object, options, timeout, allContainers)
    48  }
    49  
    50  // this is split for easy test-ability
    51  func logsForObjectWithClient(clientset corev1client.CoreV1Interface, object, options runtime.Object, timeout time.Duration, allContainers bool) (map[corev1.ObjectReference]rest.ResponseWrapper, error) {
    52  	opts, ok := options.(*corev1.PodLogOptions)
    53  	if !ok {
    54  		return nil, errors.New("provided options object is not a PodLogOptions")
    55  	}
    56  
    57  	switch t := object.(type) {
    58  	case *corev1.PodList:
    59  		ret := make(map[corev1.ObjectReference]rest.ResponseWrapper)
    60  		for i := range t.Items {
    61  			currRet, err := logsForObjectWithClient(clientset, &t.Items[i], options, timeout, allContainers)
    62  			if err != nil {
    63  				return nil, err
    64  			}
    65  			for k, v := range currRet {
    66  				ret[k] = v
    67  			}
    68  		}
    69  		return ret, nil
    70  
    71  	case *corev1.Pod:
    72  		// if allContainers is true, then we're going to locate all containers and then iterate through them. At that point, "allContainers" is false
    73  		if !allContainers {
    74  			currOpts := new(corev1.PodLogOptions)
    75  			if opts != nil {
    76  				opts.DeepCopyInto(currOpts)
    77  			}
    78  			// in case the "kubectl.kubernetes.io/default-container" annotation is present, we preset the opts.Containers to default to selected
    79  			// container. This gives users ability to preselect the most interesting container in pod.
    80  			if annotations := t.GetAnnotations(); annotations != nil && currOpts.Container == "" {
    81  				var defaultContainer string
    82  				if len(annotations[podcmd.DefaultContainerAnnotationName]) > 0 {
    83  					defaultContainer = annotations[podcmd.DefaultContainerAnnotationName]
    84  				}
    85  				if len(defaultContainer) > 0 {
    86  					if exists, _ := podcmd.FindContainerByName(t, defaultContainer); exists == nil {
    87  						fmt.Fprintf(os.Stderr, "Default container name %q not found in pod %s\n", defaultContainer, t.Name)
    88  					} else {
    89  						currOpts.Container = defaultContainer
    90  					}
    91  				}
    92  			}
    93  
    94  			if currOpts.Container == "" {
    95  				// Default to the first container name(aligning behavior with `kubectl exec').
    96  				currOpts.Container = t.Spec.Containers[0].Name
    97  				if len(t.Spec.Containers) > 1 || len(t.Spec.InitContainers) > 0 || len(t.Spec.EphemeralContainers) > 0 {
    98  					fmt.Fprintf(os.Stderr, "Defaulted container %q out of: %s\n", currOpts.Container, podcmd.AllContainerNames(t))
    99  				}
   100  			}
   101  
   102  			container, fieldPath := podcmd.FindContainerByName(t, currOpts.Container)
   103  			if container == nil {
   104  				return nil, fmt.Errorf("container %s is not valid for pod %s", currOpts.Container, t.Name)
   105  			}
   106  			ref, err := reference.GetPartialReference(scheme.Scheme, t, fieldPath)
   107  			if err != nil {
   108  				return nil, fmt.Errorf("Unable to construct reference to '%#v': %v", t, err)
   109  			}
   110  
   111  			ret := make(map[corev1.ObjectReference]rest.ResponseWrapper, 1)
   112  			ret[*ref] = clientset.Pods(t.Namespace).GetLogs(t.Name, currOpts)
   113  			return ret, nil
   114  		}
   115  
   116  		ret := make(map[corev1.ObjectReference]rest.ResponseWrapper)
   117  		for _, c := range t.Spec.InitContainers {
   118  			currOpts := opts.DeepCopy()
   119  			currOpts.Container = c.Name
   120  			currRet, err := logsForObjectWithClient(clientset, t, currOpts, timeout, false)
   121  			if err != nil {
   122  				return nil, err
   123  			}
   124  			for k, v := range currRet {
   125  				ret[k] = v
   126  			}
   127  		}
   128  		for _, c := range t.Spec.Containers {
   129  			currOpts := opts.DeepCopy()
   130  			currOpts.Container = c.Name
   131  			currRet, err := logsForObjectWithClient(clientset, t, currOpts, timeout, false)
   132  			if err != nil {
   133  				return nil, err
   134  			}
   135  			for k, v := range currRet {
   136  				ret[k] = v
   137  			}
   138  		}
   139  		for _, c := range t.Spec.EphemeralContainers {
   140  			currOpts := opts.DeepCopy()
   141  			currOpts.Container = c.Name
   142  			currRet, err := logsForObjectWithClient(clientset, t, currOpts, timeout, false)
   143  			if err != nil {
   144  				return nil, err
   145  			}
   146  			for k, v := range currRet {
   147  				ret[k] = v
   148  			}
   149  		}
   150  
   151  		return ret, nil
   152  	}
   153  
   154  	namespace, selector, err := SelectorsForObject(object)
   155  	if err != nil {
   156  		return nil, fmt.Errorf("cannot get the logs from %T: %v", object, err)
   157  	}
   158  
   159  	sortBy := func(pods []*corev1.Pod) sort.Interface { return podutils.ByLogging(pods) }
   160  	pod, numPods, err := GetFirstPod(clientset, namespace, selector.String(), timeout, sortBy)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	if numPods > 1 {
   165  		fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name)
   166  	}
   167  
   168  	return logsForObjectWithClient(clientset, pod, options, timeout, allContainers)
   169  }
   170  

View as plain text