1
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
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
73 if !allContainers {
74 currOpts := new(corev1.PodLogOptions)
75 if opts != nil {
76 opts.DeepCopyInto(currOpts)
77 }
78
79
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
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