Merge pull request #1354 from lavalamp/eventing

Add Event to api types
pull/6/head
Clayton Coleman 2014-09-25 16:20:49 -04:00
commit a5ed10235e
9 changed files with 198 additions and 123 deletions

View File

@ -39,5 +39,7 @@ func init() {
&Endpoints{},
&EndpointsList{},
&Binding{},
&Event{},
&EventList{},
)
}

View File

@ -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)

View File

@ -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.
@ -620,3 +612,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() {}

View File

@ -41,5 +41,7 @@ func init() {
&Endpoints{},
&EndpointsList{},
&Binding{},
&Event{},
&EventList{},
)
}

View File

@ -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() {}

View File

@ -41,5 +41,7 @@ func init() {
&Endpoints{},
&EndpointsList{},
&Binding{},
&Event{},
&EventList{},
)
}

View File

@ -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() {}

View File

@ -17,7 +17,6 @@ limitations under the License.
package kubelet
import (
"encoding/json"
"errors"
"fmt"
"io"
@ -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
}

View File

@ -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{