From 6a5da9ee1964eead9fd1cd6301f7050b92f5ff74 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 14 Nov 2014 11:56:41 -0800 Subject: [PATCH] Add events to kubectl describe --- pkg/kubectl/describe.go | 65 ++++++++++++++++++++++++++++++--- pkg/kubectl/resource_printer.go | 2 +- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/pkg/kubectl/describe.go b/pkg/kubectl/describe.go index 4ca06681fa7..dec398aac31 100644 --- a/pkg/kubectl/describe.go +++ b/pkg/kubectl/describe.go @@ -18,8 +18,9 @@ package kubectl import ( "fmt" + "io" + "sort" "strings" - "text/tabwriter" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" @@ -61,6 +62,21 @@ func (d *PodDescriber) Describe(namespace, name string) (string, error) { pod, err := pc.Get(name) if err != nil { + events, err2 := d.Events(namespace).List( + labels.Everything(), + labels.Set{ + "involvedObject.name": name, + "involvedObject.kind": "Pod", + "involvedObject.namespace": namespace, + }.AsSelector(), + ) + if err2 == nil && len(events.Items) > 0 { + return tabbedString(func(out io.Writer) error { + fmt.Fprintf(out, "Pod '%v': error '%v', but found events.\n", name, err) + describeEvents(events, out) + return nil + }) + } return "", err } @@ -70,13 +86,18 @@ func (d *PodDescriber) Describe(namespace, name string) (string, error) { glog.Errorf("Unable to convert pod manifest: %v", err) } - return tabbedString(func(out *tabwriter.Writer) error { + events, _ := d.Events(namespace).Search(pod) + + return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "Name:\t%s\n", pod.Name) fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(spec)) fmt.Fprintf(out, "Host:\t%s\n", pod.CurrentState.Host+"/"+pod.CurrentState.HostIP) fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(pod.Labels)) fmt.Fprintf(out, "Status:\t%s\n", string(pod.CurrentState.Status)) fmt.Fprintf(out, "Replication Controllers:\t%s\n", getReplicationControllersForLabels(rc, labels.Set(pod.Labels))) + if events != nil { + describeEvents(events, out) + } return nil }) } @@ -101,13 +122,18 @@ func (d *ReplicationControllerDescriber) Describe(namespace, name string) (strin return "", err } - return tabbedString(func(out *tabwriter.Writer) error { + events, _ := d.Events(namespace).Search(controller) + + return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "Name:\t%s\n", controller.Name) fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&controller.Spec.Template.Spec)) fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(controller.Spec.Selector)) fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(controller.Labels)) fmt.Fprintf(out, "Replicas:\t%d current / %d desired\n", controller.Status.Replicas, controller.Spec.Replicas) fmt.Fprintf(out, "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n", running, waiting, succeeded, failed) + if events != nil { + describeEvents(events, out) + } return nil }) } @@ -125,11 +151,16 @@ func (d *ServiceDescriber) Describe(namespace, name string) (string, error) { return "", err } - return tabbedString(func(out *tabwriter.Writer) error { + events, _ := d.Events(namespace).Search(service) + + return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "Name:\t%s\n", service.Name) fmt.Fprintf(out, "Labels:\t%s\n", formatLabels(service.Labels)) fmt.Fprintf(out, "Selector:\t%s\n", formatLabels(service.Spec.Selector)) fmt.Fprintf(out, "Port:\t%d\n", service.Spec.Port) + if events != nil { + describeEvents(events, out) + } return nil }) } @@ -146,12 +177,36 @@ func (d *MinionDescriber) Describe(namespace, name string) (string, error) { return "", err } - return tabbedString(func(out *tabwriter.Writer) error { + events, _ := d.Events(namespace).Search(minion) + + return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "Name:\t%s\n", minion.Name) + if events != nil { + describeEvents(events, out) + } return nil }) } +type sortableEvents []api.Event + +func (s sortableEvents) Len() int { return len(s) } +func (s sortableEvents) Less(i, j int) bool { return s[i].Timestamp.Before(s[j].Timestamp.Time) } +func (s sortableEvents) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func describeEvents(el *api.EventList, w io.Writer) { + if len(el.Items) == 0 { + fmt.Fprint(w, "No events.") + return + } + sort.Sort(sortableEvents(el.Items)) + fmt.Fprint(w, "Events:\nFrom\tSubobjectPath\tStatus\tReason\tMessage\n") + for _, e := range el.Items { + fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%v\n", + e.Source, e.InvolvedObject.FieldPath, e.Status, e.Reason, e.Message) + } +} + // Get all replication controllers whose selectors would match a given set of // labels. // TODO Move this to pkg/client and ideally implement it server-side (instead diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index a39fa555458..51eccc1c0cf 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -396,7 +396,7 @@ func (t *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error { return t.template.Execute(w, outObj) } -func tabbedString(f func(*tabwriter.Writer) error) (string, error) { +func tabbedString(f func(io.Writer) error) (string, error) { out := new(tabwriter.Writer) b := make([]byte, 1024) buf := bytes.NewBuffer(b)