mirror of https://github.com/k3s-io/k3s
fix logs command to be generic for all resources again
parent
8770d12494
commit
5ba07364ee
|
@ -236,20 +236,22 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
|||
writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
||||
defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
||||
|
||||
request, err := o.LogsForObject(o.RESTClientGetter, pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
||||
requests, err := o.LogsForObject(o.RESTClientGetter, pod, &api.PodLogOptions{Container: container.Name}, timeout, false)
|
||||
if err != nil {
|
||||
// Print error and return.
|
||||
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
data, err := request.DoRaw()
|
||||
if err != nil {
|
||||
// Print error and return.
|
||||
writer.Write([]byte(fmt.Sprintf("Request log error: %s\n", err.Error())))
|
||||
return
|
||||
for _, request := range requests {
|
||||
data, err := request.DoRaw()
|
||||
if err != nil {
|
||||
// Print error and return.
|
||||
writer.Write([]byte(fmt.Sprintf("Request log error: %s\n", err.Error())))
|
||||
return
|
||||
}
|
||||
writer.Write(data)
|
||||
}
|
||||
writer.Write(data)
|
||||
}
|
||||
|
||||
for ix := range pods.Items {
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
|
@ -244,55 +245,27 @@ func (o LogsOptions) Validate() error {
|
|||
|
||||
// RunLogs retrieves a pod log
|
||||
func (o LogsOptions) RunLogs() error {
|
||||
switch t := o.Object.(type) {
|
||||
case *api.PodList:
|
||||
for _, p := range t.Items {
|
||||
if err := o.getPodLogs(&p); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case *api.Pod:
|
||||
return o.getPodLogs(t)
|
||||
default:
|
||||
return o.getLogs(o.Object)
|
||||
}
|
||||
}
|
||||
|
||||
// getPodLogs checks whether o.AllContainers is set to true.
|
||||
// If so, it retrives all containers' log in the pod.
|
||||
func (o LogsOptions) getPodLogs(pod *api.Pod) error {
|
||||
if !o.AllContainers {
|
||||
return o.getLogs(pod)
|
||||
}
|
||||
|
||||
for _, c := range pod.Spec.InitContainers {
|
||||
o.Options.(*api.PodLogOptions).Container = c.Name
|
||||
if err := o.getLogs(pod); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, c := range pod.Spec.Containers {
|
||||
o.Options.(*api.PodLogOptions).Container = c.Name
|
||||
if err := o.getLogs(pod); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o LogsOptions) getLogs(obj runtime.Object) error {
|
||||
req, err := o.LogsForObject(o.RESTClientGetter, obj, o.Options, o.GetPodTimeout)
|
||||
requests, err := o.LogsForObject(o.RESTClientGetter, o.Object, o.Options, o.GetPodTimeout, o.AllContainers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
readCloser, err := req.Stream()
|
||||
for _, request := range requests {
|
||||
if err := consumeRequest(request, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func consumeRequest(request *rest.Request, out io.Writer) error {
|
||||
readCloser, err := request.Stream()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer readCloser.Close()
|
||||
|
||||
_, err = io.Copy(o.Out, readCloser)
|
||||
_, err = io.Copy(out, readCloser)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -244,14 +244,14 @@ type logTestMock struct {
|
|||
client internalclientset.Interface
|
||||
}
|
||||
|
||||
func (m logTestMock) logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*restclient.Request, error) {
|
||||
func (m logTestMock) logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration, allContainers bool) ([]*restclient.Request, error) {
|
||||
switch t := object.(type) {
|
||||
case *api.Pod:
|
||||
opts, ok := options.(*api.PodLogOptions)
|
||||
if !ok {
|
||||
return nil, errors.New("provided options object is not a PodLogOptions")
|
||||
}
|
||||
return m.client.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||
return []*restclient.Request{m.client.Core().Pods(t.Namespace).GetLogs(t.Name, opts)}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot get the logs from %T", object)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -523,21 +522,16 @@ func logOpts(restClientGetter genericclioptions.RESTClientGetter, pod *api.Pod,
|
|||
return err
|
||||
}
|
||||
|
||||
req, err := polymorphichelpers.LogsForObjectFn(restClientGetter, pod, &api.PodLogOptions{Container: ctrName}, opts.GetPodTimeout)
|
||||
requests, err := polymorphichelpers.LogsForObjectFn(restClientGetter, pod, &api.PodLogOptions{Container: ctrName}, opts.GetPodTimeout, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, request := range requests {
|
||||
if err := consumeRequest(request, opts.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
readCloser, err := req.Stream()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer readCloser.Close()
|
||||
|
||||
_, err = io.Copy(opts.Out, readCloser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
)
|
||||
|
||||
// LogsForObjectFunc is a function type that can tell you how to get logs for a runtime.object
|
||||
type LogsForObjectFunc func(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*rest.Request, error)
|
||||
type LogsForObjectFunc func(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration, allContainers bool) ([]*rest.Request, error)
|
||||
|
||||
// LogsForObjectFn gives a way to easily override the function for unit testing if needed.
|
||||
var LogsForObjectFn LogsForObjectFunc = logsForObject
|
||||
|
|
|
@ -33,7 +33,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
)
|
||||
|
||||
func logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*rest.Request, error) {
|
||||
func logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration, allContainers bool) ([]*rest.Request, error) {
|
||||
clientConfig, err := restClientGetter.ToRESTConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -42,21 +42,94 @@ func logsForObject(restClientGetter genericclioptions.RESTClientGetter, object,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return logsForObjectWithClient(clientset, object, options, timeout)
|
||||
return logsForObjectWithClient(clientset, object, options, timeout, allContainers)
|
||||
}
|
||||
|
||||
// this is split for easy test-ability
|
||||
func logsForObjectWithClient(clientset internalclientset.Interface, object, options runtime.Object, timeout time.Duration) (*rest.Request, error) {
|
||||
func logsForObjectWithClient(clientset internalclientset.Interface, object, options runtime.Object, timeout time.Duration, allContainers bool) ([]*rest.Request, error) {
|
||||
opts, ok := options.(*coreinternal.PodLogOptions)
|
||||
if !ok {
|
||||
return nil, errors.New("provided options object is not a PodLogOptions")
|
||||
}
|
||||
|
||||
switch t := object.(type) {
|
||||
case *coreinternal.PodList:
|
||||
ret := []*rest.Request{}
|
||||
for i := range t.Items {
|
||||
currRet, err := logsForObjectWithClient(clientset, &t.Items[i], options, timeout, allContainers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, currRet...)
|
||||
}
|
||||
return ret, nil
|
||||
|
||||
case *corev1.PodList:
|
||||
ret := []*rest.Request{}
|
||||
for i := range t.Items {
|
||||
currRet, err := logsForObjectWithClient(clientset, &t.Items[i], options, timeout, allContainers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, currRet...)
|
||||
}
|
||||
return ret, nil
|
||||
|
||||
case *coreinternal.Pod:
|
||||
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||
// if allContainers is true, then we're going to locate all containers and then iterate through them. At that point, "allContainers" is false
|
||||
if !allContainers {
|
||||
return []*rest.Request{clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts)}, nil
|
||||
}
|
||||
|
||||
ret := []*rest.Request{}
|
||||
for _, c := range t.Spec.InitContainers {
|
||||
currOpts := opts.DeepCopy()
|
||||
currOpts.Container = c.Name
|
||||
currRet, err := logsForObjectWithClient(clientset, t, options, timeout, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, currRet...)
|
||||
}
|
||||
for _, c := range t.Spec.Containers {
|
||||
currOpts := opts.DeepCopy()
|
||||
currOpts.Container = c.Name
|
||||
currRet, err := logsForObjectWithClient(clientset, t, options, timeout, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, currRet...)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
||||
case *corev1.Pod:
|
||||
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||
// if allContainers is true, then we're going to locate all containers and then iterate through them. At that point, "allContainers" is false
|
||||
if !allContainers {
|
||||
return []*rest.Request{clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts)}, nil
|
||||
}
|
||||
|
||||
ret := []*rest.Request{}
|
||||
for _, c := range t.Spec.InitContainers {
|
||||
currOpts := opts.DeepCopy()
|
||||
currOpts.Container = c.Name
|
||||
currRet, err := logsForObjectWithClient(clientset, t, options, timeout, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, currRet...)
|
||||
}
|
||||
for _, c := range t.Spec.Containers {
|
||||
currOpts := opts.DeepCopy()
|
||||
currOpts.Container = c.Name
|
||||
currRet, err := logsForObjectWithClient(clientset, t, options, timeout, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, currRet...)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
namespace, selector, err := SelectorsForObject(object)
|
||||
|
@ -71,5 +144,6 @@ func logsForObjectWithClient(clientset internalclientset.Interface, object, opti
|
|||
if numPods > 1 {
|
||||
fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name)
|
||||
}
|
||||
return clientset.Core().Pods(pod.Namespace).GetLogs(pod.Name, opts), nil
|
||||
|
||||
return logsForObjectWithClient(clientset, pod, options, timeout, allContainers)
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ func TestLogsForObject(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
fakeClientset := fake.NewSimpleClientset(test.pods...)
|
||||
_, err := logsForObjectWithClient(fakeClientset, test.obj, test.opts, 20*time.Second)
|
||||
_, err := logsForObjectWithClient(fakeClientset, test.obj, test.opts, 20*time.Second, false)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
continue
|
||||
|
|
Loading…
Reference in New Issue