From 2b91c1417c4acb5cdfbd235671ffa738a0252555 Mon Sep 17 00:00:00 2001 From: Dawn Chen Date: Mon, 5 Jan 2015 11:03:51 -0800 Subject: [PATCH 1/2] Create selfLink for pods from config files and indicate hostname as part of event source. --- pkg/kubectl/resource_printer.go | 5 +++-- pkg/kubelet/config/file.go | 5 +++++ pkg/kubelet/config/file_test.go | 3 +++ pkg/kubelet/util.go | 3 ++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index e05b2c42be0..60d28933b5e 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -193,7 +193,7 @@ var replicationControllerColumns = []string{"CONTROLLER", "CONTAINER(S)", "IMAGE var serviceColumns = []string{"NAME", "LABELS", "SELECTOR", "IP", "PORT"} var minionColumns = []string{"NAME", "LABELS"} var statusColumns = []string{"STATUS"} -var eventColumns = []string{"TIME", "NAME", "KIND", "SUBOBJECT", "CONDITION", "REASON", "MESSAGE"} +var eventColumns = []string{"TIME", "NAME", "KIND", "SUBOBJECT", "CONDITION", "REASON", "SOURCE", "MESSAGE"} // addDefaultHandlers adds print handlers for default Kubernetes types. func (h *HumanReadablePrinter) addDefaultHandlers() { @@ -339,13 +339,14 @@ func printStatus(status *api.Status, w io.Writer) error { func printEvent(event *api.Event, w io.Writer) error { _, err := fmt.Fprintf( - w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", event.Timestamp.Time.Format(time.RFC1123Z), event.InvolvedObject.Name, event.InvolvedObject.Kind, event.InvolvedObject.FieldPath, event.Condition, event.Reason, + event.Source, event.Message, ) return err diff --git a/pkg/kubelet/config/file.go b/pkg/kubelet/config/file.go index fd08fced3ff..84667dad592 100644 --- a/pkg/kubelet/config/file.go +++ b/pkg/kubelet/config/file.go @@ -159,6 +159,11 @@ func extractFromFile(filename string) (api.BoundPod, error) { if len(pod.Namespace) == 0 { pod.Namespace = api.NamespaceDefault } + // TODO(dchen1107): BoundPod is not type of runtime.Object. Once we allow kubelet talks + // about Pod directly, we can use SelfLinker defined in package: latest + // Currently just simply follow the same format in resthandler.go + pod.ObjectMeta.SelfLink = fmt.Sprintf("/api/v1beta2/pods/%s?namespace=%s", + pod.Name, pod.Namespace) if glog.V(4) { glog.Infof("Got pod from file %q: %#v", filename, pod) diff --git a/pkg/kubelet/config/file_test.go b/pkg/kubelet/config/file_test.go index 22d48e703dd..135bdea5467 100644 --- a/pkg/kubelet/config/file_test.go +++ b/pkg/kubelet/config/file_test.go @@ -124,6 +124,7 @@ func TestReadFromFile(t *testing.T) { Name: "test", UID: simpleSubdomainSafeHash(file.Name()), Namespace: "default", + SelfLink: "/api/v1beta2/pods/test?namespace=default", }, Spec: api.PodSpec{ Containers: []api.Container{{Image: "test/image", TerminationMessagePath: "/dev/termination-log"}}, @@ -161,6 +162,7 @@ func TestExtractFromValidDataFile(t *testing.T) { file := writeTestFile(t, os.TempDir(), "test_pod_config", string(text)) defer os.Remove(file.Name()) + expectedPod.ObjectMeta.SelfLink = "/api/v1beta2/pods/" + expectedPod.Name + "?namespace=default" ch := make(chan interface{}, 1) c := sourceFile{file.Name(), ch} err = c.extractFromPath() @@ -226,6 +228,7 @@ func TestExtractFromDir(t *testing.T) { } ioutil.WriteFile(name, data, 0755) files[i] = file + pods[i].ObjectMeta.SelfLink = "/api/v1beta2/pods/" + pods[i].Name + "?namespace=default" } ch := make(chan interface{}, 1) diff --git a/pkg/kubelet/util.go b/pkg/kubelet/util.go index fdb6b4afd6f..5a400df46d3 100644 --- a/pkg/kubelet/util.go +++ b/pkg/kubelet/util.go @@ -130,8 +130,9 @@ func SetupEventSending(authPath string, apiServerList util.StringList) { glog.Errorf("Unable to make apiserver client: %v", err) } else { // Send events to APIserver if there is a client. + hostname := util.GetHostname("") glog.Infof("Sending events to APIserver.") - record.StartRecording(apiClient.Events(""), "kubelet") + record.StartRecording(apiClient.Events(""), "kubelet:"+hostname) } } } From e3c019128e5666039270b6c42bae8264b43ca925 Mon Sep 17 00:00:00 2001 From: Dawn Chen Date: Tue, 6 Jan 2015 13:22:58 -0800 Subject: [PATCH 2/2] Add EventSource to api to have both Component and Host information. --- pkg/api/types.go | 10 ++++++++-- pkg/api/v1beta1/conversion.go | 10 +++++++--- pkg/api/v1beta1/types.go | 2 ++ pkg/api/v1beta2/conversion.go | 10 +++++++--- pkg/api/v1beta2/types.go | 3 +++ pkg/api/v1beta3/types.go | 10 ++++++++-- pkg/client/record/event.go | 4 ++-- pkg/client/record/event_test.go | 8 ++++---- pkg/kubectl/describe_test.go | 6 +++--- pkg/kubectl/resource_printer_test.go | 6 +++--- pkg/kubectl/sorted_event_list_test.go | 6 +++--- pkg/kubelet/util.go | 7 ++++++- pkg/registry/event/rest.go | 2 +- pkg/registry/event/rest_test.go | 2 +- plugin/cmd/kube-scheduler/scheduler.go | 3 ++- 15 files changed, 60 insertions(+), 29 deletions(-) diff --git a/pkg/api/types.go b/pkg/api/types.go index 219dbf997c5..d7c0e6e3cf6 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -985,6 +985,13 @@ type ObjectReference struct { FieldPath string `json:"fieldPath,omitempty"` } +type EventSource struct { + // Component from which the event is generated. + Component string `json:"component,omitempty"` + // Host name on which the event is generated. + Host string `json:"host,omitempty"` +} + // Event is a report of an event somewhere in the cluster. // TODO: Decide whether to store these separately or with the object they apply to. type Event struct { @@ -1014,8 +1021,7 @@ type Event struct { Message string `json:"message,omitempty"` // Optional. The component reporting this event. Should be a short machine understandable string. - // TODO: provide exact specification for format. - Source string `json:"source,omitempty"` + Source EventSource `json:"source,omitempty"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) Timestamp util.Time `json:"timestamp,omitempty"` diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index 9d9789aa74a..f4ff1f5a854 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -548,7 +548,9 @@ func init() { return nil }, - // Event Status -> Condition + // Event Status <-> Condition + // Event Source <-> Source.Component + // Event Host <-> Source.Host // TODO: remove this when it becomes possible to specify a field name conversion on a specific type func(in *newer.Event, out *Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { @@ -560,7 +562,8 @@ func init() { out.Status = in.Condition out.Reason = in.Reason out.Message = in.Message - out.Source = in.Source + out.Source = in.Source.Component + out.Host = in.Source.Host out.Timestamp = in.Timestamp return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, @@ -574,7 +577,8 @@ func init() { out.Condition = in.Status out.Reason = in.Reason out.Message = in.Message - out.Source = in.Source + out.Source.Component = in.Source + out.Source.Host = in.Host out.Timestamp = in.Timestamp return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index a4a747df47d..fa4eebac2f3 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -817,6 +817,8 @@ type Event struct { // Optional. The component reporting this event. Should be a short machine understandable string. // TODO: provide exact specification for format. Source string `json:"source,omitempty" description:"component reporting this event; short machine understandable string"` + // Host name on which the event is generated. + Host string `json:"host,omitempty"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) Timestamp util.Time `json:"timestamp,omitempty" description:"time at which the client recorded the event"` diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index 51874f36eff..10e4ad98b0c 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -464,7 +464,9 @@ func init() { return nil }, - // Event Status -> Condition + // Event Status <-> Condition + // Event Source <-> Source.Component + // Event Host <-> Source.Host // TODO: remove this when it becomes possible to specify a field name conversion on a specific type func(in *newer.Event, out *Event, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { @@ -476,7 +478,8 @@ func init() { out.Status = in.Condition out.Reason = in.Reason out.Message = in.Message - out.Source = in.Source + out.Source = in.Source.Component + out.Host = in.Source.Host out.Timestamp = in.Timestamp return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, @@ -490,7 +493,8 @@ func init() { out.Condition = in.Status out.Reason = in.Reason out.Message = in.Message - out.Source = in.Source + out.Source.Component = in.Source + out.Source.Host = in.Host out.Timestamp = in.Timestamp return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) }, diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index fcbb4c05a7f..7438f264fa8 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -791,6 +791,9 @@ type Event struct { // TODO: provide exact specification for format. Source string `json:"source,omitempty" description:"component reporting this event; short machine understandable string"` + // Host name on which the event is generated. + Host string `json:"host,omitempty"` + // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) Timestamp util.Time `json:"timestamp,omitempty" description:"time at which the client recorded the event"` } diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index c1f3da6c8d8..daf7b01b42d 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -1003,6 +1003,13 @@ type ObjectReference struct { FieldPath string `json:"fieldPath,omitempty"` } +type EventSource struct { + // Component from which the event is generated. + Component string `json:"component,omitempty"` + // Host name on which the event is generated. + Host string `json:"host,omitempty"` +} + // Event is a report of an event somewhere in the cluster. // TODO: Decide whether to store these separately or with the object they apply to. type Event struct { @@ -1032,8 +1039,7 @@ type Event struct { Message string `json:"message,omitempty"` // Optional. The component reporting this event. Should be a short machine understandable string. - // TODO: provide exact specification for format. - Source string `json:"source,omitempty"` + Source EventSource `json:"source,omitempty"` // The time at which the client recorded the event. (Time of server receipt is in TypeMeta.) Timestamp util.Time `json:"timestamp,omitempty"` diff --git a/pkg/client/record/event.go b/pkg/client/record/event.go index d86aee0340b..0cd6a3df403 100644 --- a/pkg/client/record/event.go +++ b/pkg/client/record/event.go @@ -41,13 +41,13 @@ type EventRecorder interface { // StartRecording starts sending events to recorder. Call once while initializing // your binary. Subsequent calls will be ignored. The return value can be ignored // or used to stop recording, if desired. -func StartRecording(recorder EventRecorder, sourceName string) watch.Interface { +func StartRecording(recorder EventRecorder, source api.EventSource) watch.Interface { return GetEvents(func(event *api.Event) { // Make a copy before modification, because there could be multiple listeners. // Events are safe to copy like this. eventCopy := *event event = &eventCopy - event.Source = sourceName + event.Source = source try := 0 for { try++ diff --git a/pkg/client/record/event_test.go b/pkg/client/record/event_test.go index bf2a62abf5d..8383424a509 100644 --- a/pkg/client/record/event_test.go +++ b/pkg/client/record/event_test.go @@ -89,7 +89,7 @@ func TestEventf(t *testing.T) { Condition: "Running", Reason: "Started", Message: "some verbose message: 1", - Source: "eventTest", + Source: api.EventSource{Component: "eventTest"}, }, expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"v1beta1", ResourceVersion:"", FieldPath:"desiredState.manifest.containers[2]"}): status: 'Running', reason: 'Started' some verbose message: 1`, }, @@ -114,7 +114,7 @@ func TestEventf(t *testing.T) { Condition: "Running", Reason: "Started", Message: "some verbose message: 1", - Source: "eventTest", + Source: api.EventSource{Component: "eventTest"}, }, expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"v1beta1", ResourceVersion:"", FieldPath:""}): status: 'Running', reason: 'Started' some verbose message: 1`, }, @@ -142,7 +142,7 @@ func TestEventf(t *testing.T) { return event, nil }, } - recorder := record.StartRecording(&testEvents, "eventTest") + recorder := record.StartRecording(&testEvents, api.EventSource{Component: "eventTest"}) logger := record.StartLogging(t.Logf) // Prove that it is useful logger2 := record.StartLogging(func(formatter string, args ...interface{}) { if e, a := item.expectLog, fmt.Sprintf(formatter, args...); e != a { @@ -223,7 +223,7 @@ func TestWriteEventError(t *testing.T) { return event, nil }, }, - "eventTest", + api.EventSource{Component: "eventTest"}, ).Stop() for caseName := range table { diff --git a/pkg/kubectl/describe_test.go b/pkg/kubectl/describe_test.go index 178083919d0..e965effd57c 100644 --- a/pkg/kubectl/describe_test.go +++ b/pkg/kubectl/describe_test.go @@ -69,17 +69,17 @@ func TestPodDescribeResultsSorted(t *testing.T) { EventsList: api.EventList{ Items: []api.Event{ { - Source: "kubelet", + Source: api.EventSource{Component: "kubelet"}, Message: "Item 1", Timestamp: util.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)), }, { - Source: "scheduler", + Source: api.EventSource{Component: "scheduler"}, Message: "Item 2", Timestamp: util.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)), }, { - Source: "kubelet", + Source: api.EventSource{Component: "kubelet"}, Message: "Item 3", Timestamp: util.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)), }, diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index ef5effbe003..c8972a054a3 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -463,17 +463,17 @@ func TestPrintEventsResultSorted(t *testing.T) { obj := api.EventList{ Items: []api.Event{ { - Source: "kubelet", + Source: api.EventSource{Component: "kubelet"}, Message: "Item 1", Timestamp: util.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)), }, { - Source: "scheduler", + Source: api.EventSource{Component: "scheduler"}, Message: "Item 2", Timestamp: util.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)), }, { - Source: "kubelet", + Source: api.EventSource{Component: "kubelet"}, Message: "Item 3", Timestamp: util.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)), }, diff --git a/pkg/kubectl/sorted_event_list_test.go b/pkg/kubectl/sorted_event_list_test.go index 62716183924..7307a8038ea 100644 --- a/pkg/kubectl/sorted_event_list_test.go +++ b/pkg/kubectl/sorted_event_list_test.go @@ -54,17 +54,17 @@ func TestSortableEvents(t *testing.T) { // Arrange list := SortableEvents([]api.Event{ { - Source: "kubelet", + Source: api.EventSource{Component: "kubelet"}, Message: "Item 1", Timestamp: util.NewTime(time.Date(2014, time.January, 15, 0, 0, 0, 0, time.UTC)), }, { - Source: "scheduler", + Source: api.EventSource{Component: "scheduler"}, Message: "Item 2", Timestamp: util.NewTime(time.Date(1987, time.June, 17, 0, 0, 0, 0, time.UTC)), }, { - Source: "kubelet", + Source: api.EventSource{Component: "kubelet"}, Message: "Item 3", Timestamp: util.NewTime(time.Date(2002, time.December, 25, 0, 0, 0, 0, time.UTC)), }, diff --git a/pkg/kubelet/util.go b/pkg/kubelet/util.go index 5a400df46d3..cc6aa5834ce 100644 --- a/pkg/kubelet/util.go +++ b/pkg/kubelet/util.go @@ -23,6 +23,7 @@ import ( "path" "strconv" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" @@ -132,7 +133,11 @@ func SetupEventSending(authPath string, apiServerList util.StringList) { // Send events to APIserver if there is a client. hostname := util.GetHostname("") glog.Infof("Sending events to APIserver.") - record.StartRecording(apiClient.Events(""), "kubelet:"+hostname) + record.StartRecording(apiClient.Events(""), + api.EventSource{ + Component: "kubelet", + Host: hostname, + }) } } } diff --git a/pkg/registry/event/rest.go b/pkg/registry/event/rest.go index 8ca30daa46f..511ee5e40ee 100644 --- a/pkg/registry/event/rest.go +++ b/pkg/registry/event/rest.go @@ -109,7 +109,7 @@ func (rs *REST) getAttrs(obj runtime.Object) (objLabels, objFields labels.Set, e "condition": event.Condition, "status": event.Condition, // TODO: remove me when we version fields "reason": event.Reason, - "source": event.Source, + "source": event.Source.Component, }, nil } diff --git a/pkg/registry/event/rest_test.go b/pkg/registry/event/rest_test.go index cb9557e3fff..aa73051b7ab 100644 --- a/pkg/registry/event/rest_test.go +++ b/pkg/registry/event/rest_test.go @@ -145,7 +145,7 @@ func TestRESTgetAttrs(t *testing.T) { }, Condition: "Tested", Reason: "ForTesting", - Source: "test", + Source: api.EventSource{Component: "test"}, } label, field, err := rest.getAttrs(eventA) if err != nil { diff --git a/plugin/cmd/kube-scheduler/scheduler.go b/plugin/cmd/kube-scheduler/scheduler.go index 35c250b448f..757e745e11e 100644 --- a/plugin/cmd/kube-scheduler/scheduler.go +++ b/plugin/cmd/kube-scheduler/scheduler.go @@ -22,6 +22,7 @@ import ( "net/http" "strconv" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" _ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" @@ -57,7 +58,7 @@ func main() { glog.Fatalf("Invalid API configuration: %v", err) } - record.StartRecording(kubeClient.Events(""), "scheduler") + record.StartRecording(kubeClient.Events(""), api.EventSource{Component: "scheduler"}) go http.ListenAndServe(net.JoinHostPort(address.String(), strconv.Itoa(*port)), nil)