From 283eaf3931322cee7f793052dcbbbdb87951fb21 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Wed, 24 Sep 2014 14:35:34 -0700 Subject: [PATCH] Add new Event type * replaces previous Event type, which is too limited. * Remove writing of old event type. * Fix serialiazation test to automatically test all types. --- pkg/api/register.go | 2 ++ pkg/api/serialization_test.go | 23 ++++-------- pkg/api/types.go | 68 ++++++++++++++++++++++++++++++----- pkg/api/v1beta1/register.go | 2 ++ pkg/api/v1beta1/types.go | 68 ++++++++++++++++++++++++++++++----- pkg/api/v1beta2/register.go | 2 ++ pkg/api/v1beta2/types.go | 68 ++++++++++++++++++++++++++++++----- pkg/kubelet/handlers.go | 8 ++--- pkg/kubelet/kubelet.go | 44 +++++------------------ pkg/kubelet/kubelet_test.go | 48 ------------------------- 10 files changed, 204 insertions(+), 129 deletions(-) diff --git a/pkg/api/register.go b/pkg/api/register.go index 6935cb1b538..e7172d13615 100644 --- a/pkg/api/register.go +++ b/pkg/api/register.go @@ -39,5 +39,7 @@ func init() { &Endpoints{}, &EndpointsList{}, &Binding{}, + &Event{}, + &EventList{}, ) } diff --git a/pkg/api/serialization_test.go b/pkg/api/serialization_test.go index a464c0d96c4..af83f466544 100644 --- a/pkg/api/serialization_test.go +++ b/pkg/api/serialization_test.go @@ -147,25 +147,14 @@ func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) { } func TestTypes(t *testing.T) { - table := []runtime.Object{ - &api.PodList{}, - &api.Pod{}, - &api.ServiceList{}, - &api.Service{}, - &api.ReplicationControllerList{}, - &api.ReplicationController{}, - &api.MinionList{}, - &api.Minion{}, - &api.Status{}, - &api.ServerOpList{}, - &api.ServerOp{}, - &api.ContainerManifestList{}, - &api.Endpoints{}, - &api.Binding{}, - } - for _, item := range table { + for kind := range api.Scheme.KnownTypes("") { // Try a few times, since runTest uses random values. for i := 0; i < *fuzzIters; i++ { + item, err := api.Scheme.New("", kind) + if err != nil { + t.Errorf("Couldn't make a %v? %v", kind, err) + continue + } runTest(t, v1beta1.Codec, item) runTest(t, v1beta2.Codec, item) runTest(t, api.Codec, item) diff --git a/pkg/api/types.go b/pkg/api/types.go index ec1419b6e7a..37475ba2a91 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -219,14 +219,6 @@ type Lifecycle struct { PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty"` } -// Event is the representation of an event logged to etcd backends. -type Event struct { - Event string `json:"event,omitempty"` - Manifest *ContainerManifest `json:"manifest,omitempty"` - Container *Container `json:"container,omitempty"` - Timestamp int64 `json:"timestamp"` -} - // The below types are used by kube_client and api_server. // JSONBase is shared by all objects sent to, or returned from the client. @@ -621,3 +613,63 @@ type ServerOpList struct { } func (*ServerOpList) IsAnAPIObject() {} + +// ObjectReference contains enough information to let you inspect or modify the referred object. +type ObjectReference struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + UID string `json:"uid,omitempty" yaml:"uid,omitempty"` + APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + + // Optional. If referring to a piece of an object instead of an entire object, this string + // should contain a valid field access statement. For example, + // if the object reference is to a container within a pod, this would take on a value like: + // "desiredState.manifest.containers[2]". Such statements are valid language constructs in + // both go and JavaScript. This is syntax is chosen only to have some well-defined way of + // referencing a part of an object. + // TODO: this design is not final and this field is subject to change in the future. + FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,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 { + JSONBase `yaml:",inline" json:",inline"` + + // Required. The object that this event is about. + InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty"` + + // Should be a short, machine understandable string that describes the current status + // of the referred object. This should not give the reason for being in this state. + // Examples: "running", "cantStart", "cantSchedule", "deleted". + // It's OK for components to make up statuses to report here, but the same string should + // always be used for the same status. + // TODO: define a way of making sure these are consistent and don't collide. + // TODO: provide exact specification for format. + Status string `json:"status,omitempty" yaml:"status,omitempty"` + + // Optional; this should be a short, machine understandable string that gives the reason + // for the transition into the object's current status. For example, if ObjectStatus is + // "cantStart", StatusReason might be "imageNotFound". + // TODO: provide exact specification for format. + Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + + // Optional. A human-readable description of the status of this operation. + // TODO: decide on maximum length. + Message string `json:"message,omitempty" yaml:"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" yaml:"source,omitempty"` +} + +func (*Event) IsAnAPIObject() {} + +// EventList is a list of events. +type EventList struct { + JSONBase `yaml:",inline" json:",inline"` + Items []Event `yaml:"items,omitempty" json:"items,omitempty"` +} + +func (*EventList) IsAnAPIObject() {} diff --git a/pkg/api/v1beta1/register.go b/pkg/api/v1beta1/register.go index 980aa7fc005..4d60afbbcdf 100644 --- a/pkg/api/v1beta1/register.go +++ b/pkg/api/v1beta1/register.go @@ -41,5 +41,7 @@ func init() { &Endpoints{}, &EndpointsList{}, &Binding{}, + &Event{}, + &EventList{}, ) } diff --git a/pkg/api/v1beta1/types.go b/pkg/api/v1beta1/types.go index b85fec96707..a63879f740b 100644 --- a/pkg/api/v1beta1/types.go +++ b/pkg/api/v1beta1/types.go @@ -230,14 +230,6 @@ type Lifecycle struct { PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty"` } -// Event is the representation of an event logged to etcd backends. -type Event struct { - Event string `json:"event,omitempty"` - Manifest *ContainerManifest `json:"manifest,omitempty"` - Container *Container `json:"container,omitempty"` - Timestamp int64 `json:"timestamp"` -} - // The below types are used by kube_client and api_server. // JSONBase is shared by all objects sent to, or returned from the client. @@ -623,3 +615,63 @@ type ServerOpList struct { } func (*ServerOpList) IsAnAPIObject() {} + +// ObjectReference contains enough information to let you inspect or modify the referred object. +type ObjectReference struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + UID string `json:"uid,omitempty" yaml:"uid,omitempty"` + APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + + // Optional. If referring to a piece of an object instead of an entire object, this string + // should contain a valid field access statement. For example, + // if the object reference is to a container within a pod, this would take on a value like: + // "desiredState.manifest.containers[2]". Such statements are valid language constructs in + // both go and JavaScript. This is syntax is chosen only to have some well-defined way of + // referencing a part of an object. + // TODO: this design is not final and this field is subject to change in the future. + FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,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 { + JSONBase `yaml:",inline" json:",inline"` + + // Required. The object that this event is about. + InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty"` + + // Should be a short, machine understandable string that describes the current status + // of the referred object. This should not give the reason for being in this state. + // Examples: "running", "cantStart", "cantSchedule", "deleted". + // It's OK for components to make up statuses to report here, but the same string should + // always be used for the same status. + // TODO: define a way of making sure these are consistent and don't collide. + // TODO: provide exact specification for format. + Status string `json:"status,omitempty" yaml:"status,omitempty"` + + // Optional; this should be a short, machine understandable string that gives the reason + // for the transition into the object's current status. For example, if ObjectStatus is + // "cantStart", StatusReason might be "imageNotFound". + // TODO: provide exact specification for format. + Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + + // Optional. A human-readable description of the status of this operation. + // TODO: decide on maximum length. + Message string `json:"message,omitempty" yaml:"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" yaml:"source,omitempty"` +} + +func (*Event) IsAnAPIObject() {} + +// EventList is a list of events. +type EventList struct { + JSONBase `yaml:",inline" json:",inline"` + Items []Event `yaml:"items,omitempty" json:"items,omitempty"` +} + +func (*EventList) IsAnAPIObject() {} diff --git a/pkg/api/v1beta2/register.go b/pkg/api/v1beta2/register.go index 79f545330c8..0e5de823b16 100644 --- a/pkg/api/v1beta2/register.go +++ b/pkg/api/v1beta2/register.go @@ -41,5 +41,7 @@ func init() { &Endpoints{}, &EndpointsList{}, &Binding{}, + &Event{}, + &EventList{}, ) } diff --git a/pkg/api/v1beta2/types.go b/pkg/api/v1beta2/types.go index 4816d5f590e..d1edc19d4eb 100644 --- a/pkg/api/v1beta2/types.go +++ b/pkg/api/v1beta2/types.go @@ -228,14 +228,6 @@ type Lifecycle struct { PreStop *Handler `yaml:"preStop,omitempty" json:"preStop,omitempty"` } -// Event is the representation of an event logged to etcd backends. -type Event struct { - Event string `json:"event,omitempty"` - Manifest *ContainerManifest `json:"manifest,omitempty"` - Container *Container `json:"container,omitempty"` - Timestamp int64 `json:"timestamp"` -} - // The below types are used by kube_client and api_server. // JSONBase is shared by all objects sent to, or returned from the client. @@ -633,3 +625,63 @@ type ServerOpList struct { } func (*ServerOpList) IsAnAPIObject() {} + +// ObjectReference contains enough information to let you inspect or modify the referred object. +type ObjectReference struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + UID string `json:"uid,omitempty" yaml:"uid,omitempty"` + APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"` + ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"` + + // Optional. If referring to a piece of an object instead of an entire object, this string + // should contain a valid field access statement. For example, + // if the object reference is to a container within a pod, this would take on a value like: + // "desiredState.manifest.containers[2]". Such statements are valid language constructs in + // both go and JavaScript. This is syntax is chosen only to have some well-defined way of + // referencing a part of an object. + // TODO: this design is not final and this field is subject to change in the future. + FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,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 { + JSONBase `yaml:",inline" json:",inline"` + + // Required. The object that this event is about. + InvolvedObject ObjectReference `json:"involvedObject,omitempty" yaml:"involvedObject,omitempty"` + + // Should be a short, machine understandable string that describes the current status + // of the referred object. This should not give the reason for being in this state. + // Examples: "running", "cantStart", "cantSchedule", "deleted". + // It's OK for components to make up statuses to report here, but the same string should + // always be used for the same status. + // TODO: define a way of making sure these are consistent and don't collide. + // TODO: provide exact specification for format. + Status string `json:"status,omitempty" yaml:"status,omitempty"` + + // Optional; this should be a short, machine understandable string that gives the reason + // for the transition into the object's current status. For example, if ObjectStatus is + // "cantStart", StatusReason might be "imageNotFound". + // TODO: provide exact specification for format. + Reason string `json:"reason,omitempty" yaml:"reason,omitempty"` + + // Optional. A human-readable description of the status of this operation. + // TODO: decide on maximum length. + Message string `json:"message,omitempty" yaml:"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" yaml:"source,omitempty"` +} + +func (*Event) IsAnAPIObject() {} + +// EventList is a list of events. +type EventList struct { + JSONBase `yaml:",inline" json:",inline"` + Items []Event `yaml:"items,omitempty" json:"items,omitempty"` +} + +func (*EventList) IsAnAPIObject() {} diff --git a/pkg/kubelet/handlers.go b/pkg/kubelet/handlers.go index 77934595721..f3583fc71be 100644 --- a/pkg/kubelet/handlers.go +++ b/pkg/kubelet/handlers.go @@ -18,10 +18,10 @@ package kubelet import ( "fmt" - "net" - "strconv" - "net/http" "io" + "net" + "net/http" + "strconv" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -101,7 +101,7 @@ func (h *httpActionHandler) Run(podFullName, uuid string, container *api.Contain // FlushWriter provides wrapper for responseWriter with HTTP streaming capabilities type FlushWriter struct { flusher http.Flusher - writer io.Writer + writer io.Writer } // Write is a FlushWriter implementation of the io.Writer that sends any buffered data to the client. diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 6f0f3cb4508..9b54d0f67a8 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -17,16 +17,15 @@ limitations under the License. package kubelet import ( - "encoding/json" "errors" "fmt" + "io" "net/http" "path" "strconv" "strings" "sync" "time" - "io" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" @@ -36,7 +35,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume" - "github.com/coreos/go-etcd/etcd" "github.com/fsouza/go-dockerclient" "github.com/golang/glog" "github.com/google/cadvisor/info" @@ -174,27 +172,9 @@ func (self *podWorkers) Run(podFullName string, action func()) { }() } -// LogEvent logs an event to the etcd backend. +// LogEvent reports an event. func (kl *Kubelet) LogEvent(event *api.Event) error { - if kl.etcdClient == nil { - return fmt.Errorf("no etcd client connection") - } - event.Timestamp = time.Now().Unix() - data, err := json.Marshal(event) - if err != nil { - return err - } - - var response *etcd.Response - response, err = kl.etcdClient.AddChild(fmt.Sprintf("/events/%s", event.Container.Name), string(data), 60*60*48 /* 2 days */) - // TODO(bburns) : examine response here. - if err != nil { - glog.Errorf("Error writing event: %s\n", err) - if response != nil { - glog.Infof("Response was: %v\n", *response) - } - } - return err + return nil } func makeEnvironmentVariables(container *api.Container) []string { @@ -370,18 +350,10 @@ func (kl *Kubelet) killContainerByID(ID, name string) error { if len(name) == 0 { return err } - podFullName, uuid, containerName, _ := dockertools.ParseDockerName(name) - kl.LogEvent(&api.Event{ - Event: "STOP", - Manifest: &api.ContainerManifest{ - //TODO: This should be reported using either the apiserver schema or the kubelet schema - ID: podFullName, - UUID: uuid, - }, - Container: &api.Container{ - Name: containerName, - }, - }) + + // TODO(lavalamp): restore event logging: + // podFullName, uuid, containerName, _ := dockertools.ParseDockerName(name) + // kl.LogEvent(&api.Event{}) return err } @@ -758,7 +730,7 @@ func (kl *Kubelet) GetKubeletContainerLogs(podFullName, containerName, tail stri if !found { return fmt.Errorf("container not found (%s)\n", containerName) } - return dockertools.GetKubeletDockerContainerLogs(kl.dockerClient, dockerContainer.ID, tail , follow, stdout, stderr) + return dockertools.GetKubeletDockerContainerLogs(kl.dockerClient, dockerContainer.ID, tail, follow, stdout, stderr) } // GetPodInfo returns information from Docker about the containers in a pod diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index d04faf73148..74c0b10cc11 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -17,7 +17,6 @@ limitations under the License. package kubelet import ( - "encoding/json" "fmt" "net/http" "reflect" @@ -547,53 +546,6 @@ func TestSyncPodUnhealthy(t *testing.T) { } } -func TestEventWriting(t *testing.T) { - kubelet, fakeEtcd, _ := newTestKubelet(t) - expectedEvent := api.Event{ - Event: "test", - Container: &api.Container{ - Name: "foo", - }, - } - err := kubelet.LogEvent(&expectedEvent) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if fakeEtcd.Ix != 1 { - t.Errorf("Unexpected number of children added: %d, expected 1", fakeEtcd.Ix) - } - response, err := fakeEtcd.Get("/events/foo/1", false, false) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - var event api.Event - err = json.Unmarshal([]byte(response.Node.Value), &event) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if event.Event != expectedEvent.Event || - event.Container.Name != expectedEvent.Container.Name { - t.Errorf("Event's don't match. Expected: %#v Saw: %#v", expectedEvent, event) - } -} - -func TestEventWritingError(t *testing.T) { - kubelet, fakeEtcd, _ := newTestKubelet(t) - fakeEtcd.Err = fmt.Errorf("test error") - err := kubelet.LogEvent(&api.Event{ - Event: "test", - Container: &api.Container{ - Name: "foo", - }, - }) - if err == nil { - t.Errorf("Unexpected non-error") - } -} - func TestMakeEnvVariables(t *testing.T) { container := api.Container{ Env: []api.EnvVar{