Record event when image GC fails.

pull/6/head
Victor Marmol 2015-03-27 13:12:48 -07:00
parent 31324a0ba5
commit de35c8f2af
3 changed files with 37 additions and 21 deletions

View File

@ -22,6 +22,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@ -65,6 +67,12 @@ type realImageManager struct {
// cAdvisor instance. // cAdvisor instance.
cadvisor cadvisor.Interface cadvisor cadvisor.Interface
// Recorder for Kubernetes events.
recorder record.EventRecorder
// Reference to this node.
nodeRef *api.ObjectReference
} }
// Information about the images we track. // Information about the images we track.
@ -79,7 +87,7 @@ type imageRecord struct {
size int64 size int64
} }
func newImageManager(dockerClient dockertools.DockerInterface, cadvisorInterface cadvisor.Interface, policy ImageGCPolicy) (imageManager, error) { func newImageManager(dockerClient dockertools.DockerInterface, cadvisorInterface cadvisor.Interface, recorder record.EventRecorder, nodeRef *api.ObjectReference, policy ImageGCPolicy) (imageManager, error) {
// Validate policy. // Validate policy.
if policy.HighThresholdPercent < 0 || policy.HighThresholdPercent > 100 { if policy.HighThresholdPercent < 0 || policy.HighThresholdPercent > 100 {
return nil, fmt.Errorf("invalid HighThresholdPercent %d, must be in range [0-100]", policy.HighThresholdPercent) return nil, fmt.Errorf("invalid HighThresholdPercent %d, must be in range [0-100]", policy.HighThresholdPercent)
@ -92,6 +100,8 @@ func newImageManager(dockerClient dockertools.DockerInterface, cadvisorInterface
policy: policy, policy: policy,
imageRecords: make(map[string]*imageRecord), imageRecords: make(map[string]*imageRecord),
cadvisor: cadvisorInterface, cadvisor: cadvisorInterface,
recorder: recorder,
nodeRef: nodeRef,
} }
err := im.start() err := im.start()
@ -182,8 +192,9 @@ func (self *realImageManager) GarbageCollect() error {
// Check valid capacity. // Check valid capacity.
if capacity == 0 { if capacity == 0 {
// TODO(vmarmol): Surface event. err := fmt.Errorf("invalid capacity %d on device %q at mount point %q", capacity, fsInfo.Device, fsInfo.Mountpoint)
return fmt.Errorf("invalid capacity %d on device %q at mount point %q", capacity, fsInfo.Device, fsInfo.Mountpoint) self.recorder.Eventf(self.nodeRef, "invalidDiskCapacity", err.Error())
return err
} }
// If over the max threshold, free enough to place us at the lower threshold. // If over the max threshold, free enough to place us at the lower threshold.
@ -197,8 +208,9 @@ func (self *realImageManager) GarbageCollect() error {
} }
if freed < amountToFree { if freed < amountToFree {
// TODO(vmarmol): Surface event. err := fmt.Errorf("failed to garbage collect required amount of images. Wanted to free %d, but freed %d", amountToFree, freed)
return fmt.Errorf("failed to garbage collect required amount of images. Wanted to free %d, but freed %d", amountToFree, freed) self.recorder.Eventf(self.nodeRef, "freeDiskSpaceFailed", err.Error())
return err
} }
} }

View File

@ -21,6 +21,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@ -42,6 +43,7 @@ func newRealImageManager(policy ImageGCPolicy) (*realImageManager, *dockertools.
policy: policy, policy: policy,
imageRecords: make(map[string]*imageRecord), imageRecords: make(map[string]*imageRecord),
cadvisor: mockCadvisor, cadvisor: mockCadvisor,
recorder: &record.FakeRecorder{},
}, fakeDocker, mockCadvisor }, fakeDocker, mockCadvisor
} }

View File

@ -195,11 +195,21 @@ func NewMainKubelet(
} }
nodeLister := &cache.StoreToNodeLister{nodeStore} nodeLister := &cache.StoreToNodeLister{nodeStore}
// TODO: get the real minion object of ourself,
// and use the real minion name and UID.
// TODO: what is namespace for node?
nodeRef := &api.ObjectReference{
Kind: "Node",
Name: hostname,
UID: types.UID(hostname),
Namespace: "",
}
containerGC, err := newContainerGC(dockerClient, containerGCPolicy) containerGC, err := newContainerGC(dockerClient, containerGCPolicy)
if err != nil { if err != nil {
return nil, err return nil, err
} }
imageManager, err := newImageManager(dockerClient, cadvisorInterface, imageGCPolicy) imageManager, err := newImageManager(dockerClient, cadvisorInterface, recorder, nodeRef, imageGCPolicy)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to initialize image manager: %v", err) return nil, fmt.Errorf("failed to initialize image manager: %v", err)
} }
@ -232,6 +242,7 @@ func NewMainKubelet(
imageManager: imageManager, imageManager: imageManager,
statusManager: statusManager, statusManager: statusManager,
cloud: cloud, cloud: cloud,
nodeRef: nodeRef,
} }
klet.podManager = newBasicPodManager(klet.kubeClient) klet.podManager = newBasicPodManager(klet.kubeClient)
@ -350,6 +361,9 @@ type Kubelet struct {
//Cloud provider interface //Cloud provider interface
cloud cloudprovider.Interface cloud cloudprovider.Interface
// Reference to this node.
nodeRef *api.ObjectReference
} }
// getRootDir returns the full path to the directory under which kubelet can // getRootDir returns the full path to the directory under which kubelet can
@ -1737,7 +1751,7 @@ func (kl *Kubelet) updateNodeStatus() error {
func (kl *Kubelet) recordNodeOnlineEvent() { func (kl *Kubelet) recordNodeOnlineEvent() {
// TODO: This requires a transaction, either both node status is updated // TODO: This requires a transaction, either both node status is updated
// and event is recorded or neither should happen, see issue #6055. // and event is recorded or neither should happen, see issue #6055.
kl.recorder.Eventf(kl.getNodeReference(), "online", "Node %s is now online", kl.hostname) kl.recorder.Eventf(kl.nodeRef, "online", "Node %s is now online", kl.hostname)
} }
// tryUpdateNodeStatus tries to update node status to master. // tryUpdateNodeStatus tries to update node status to master.
@ -1763,7 +1777,7 @@ func (kl *Kubelet) tryUpdateNodeStatus() error {
node.Status.NodeInfo.BootID != info.BootID { node.Status.NodeInfo.BootID != info.BootID {
// TODO: This requires a transaction, either both node status is updated // TODO: This requires a transaction, either both node status is updated
// and event is recorded or neither should happen, see issue #6055. // and event is recorded or neither should happen, see issue #6055.
kl.recorder.Eventf(kl.getNodeReference(), "rebooted", kl.recorder.Eventf(kl.nodeRef, "rebooted",
"Node %s has been rebooted, boot id: %s", kl.hostname, info.BootID) "Node %s has been rebooted, boot id: %s", kl.hostname, info.BootID)
} }
node.Status.NodeInfo.BootID = info.BootID node.Status.NodeInfo.BootID = info.BootID
@ -2013,22 +2027,10 @@ func (kl *Kubelet) PortForward(podFullName string, uid types.UID, port uint16, s
return kl.runner.PortForward(podInfraContainer.ID, port, stream) return kl.runner.PortForward(podInfraContainer.ID, port, stream)
} }
func (kl *Kubelet) getNodeReference() *api.ObjectReference {
// and use the real minion name and UID.
// TODO: what is namespace for node?
return &api.ObjectReference{
Kind: "Node",
Name: kl.hostname,
UID: types.UID(kl.hostname),
Namespace: "",
}
}
// BirthCry sends an event that the kubelet has started up. // BirthCry sends an event that the kubelet has started up.
func (kl *Kubelet) BirthCry() { func (kl *Kubelet) BirthCry() {
// Make an event that kubelet restarted. // Make an event that kubelet restarted.
// TODO: get the real minion object of ourself, kl.recorder.Eventf(kl.nodeRef, "starting", "Starting kubelet.")
kl.recorder.Eventf(kl.getNodeReference(), "starting", "Starting kubelet.")
} }
func (kl *Kubelet) StreamingConnectionIdleTimeout() time.Duration { func (kl *Kubelet) StreamingConnectionIdleTimeout() time.Duration {