mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			164 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2014 Google Inc. All rights reserved.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package record
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
						|
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
 | 
						|
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
 | 
						|
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
						|
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
						|
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
 | 
						|
 | 
						|
	"github.com/golang/glog"
 | 
						|
)
 | 
						|
 | 
						|
// retryEventSleep is the time between record failures to retry.  Available for test alteration.
 | 
						|
var retryEventSleep = 1 * time.Second
 | 
						|
 | 
						|
// EventRecorder knows how to store events (client.Client implements it.)
 | 
						|
// EventRecorder must respect the namespace that will be embedded in 'event'.
 | 
						|
// It is assumed that EventRecorder will return the same sorts of errors as
 | 
						|
// pkg/client's REST client.
 | 
						|
type EventRecorder interface {
 | 
						|
	Create(event *api.Event) (*api.Event, error)
 | 
						|
}
 | 
						|
 | 
						|
// 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.
 | 
						|
// TODO: make me an object with parameterizable queue length and retry interval
 | 
						|
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 = source
 | 
						|
		try := 0
 | 
						|
		for {
 | 
						|
			try++
 | 
						|
			_, err := recorder.Create(event)
 | 
						|
			if err == nil {
 | 
						|
				break
 | 
						|
			}
 | 
						|
			// If we can't contact the server, then hold everything while we keep trying.
 | 
						|
			// Otherwise, something about the event is malformed and we should abandon it.
 | 
						|
			giveUp := false
 | 
						|
			switch err.(type) {
 | 
						|
			case *client.RequestConstructionError:
 | 
						|
				// We will construct the request the same next time, so don't keep trying.
 | 
						|
				giveUp = true
 | 
						|
			case *errors.StatusError:
 | 
						|
				// This indicates that the server understood and rejected our request.
 | 
						|
				giveUp = true
 | 
						|
			case *errors.UnexpectedObjectError:
 | 
						|
				// We don't expect this; it implies the server's response didn't match a
 | 
						|
				// known pattern. Go ahead and retry.
 | 
						|
			default:
 | 
						|
				// This case includes actual http transport errors. Go ahead and retry.
 | 
						|
			}
 | 
						|
			if giveUp {
 | 
						|
				glog.Errorf("Unable to write event '%#v': '%v' (will not retry!)", event, err)
 | 
						|
				break
 | 
						|
			}
 | 
						|
			if try >= 3 {
 | 
						|
				glog.Errorf("Unable to write event '%#v': '%v' (retry limit exceeded!)", event, err)
 | 
						|
				break
 | 
						|
			}
 | 
						|
			glog.Errorf("Unable to write event: '%v' (will retry in 1 second)", err)
 | 
						|
			time.Sleep(retryEventSleep)
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// StartLogging just logs local events, using the given logging function. The
 | 
						|
// return value can be ignored or used to stop logging, if desired.
 | 
						|
func StartLogging(logf func(format string, args ...interface{})) watch.Interface {
 | 
						|
	return GetEvents(func(e *api.Event) {
 | 
						|
		logf("Event(%#v): status: '%v', reason: '%v' %v", e.InvolvedObject, e.Condition, e.Reason, e.Message)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// GetEvents lets you see *local* events. Convenience function for testing. The
 | 
						|
// return value can be ignored or used to stop logging, if desired.
 | 
						|
func GetEvents(f func(*api.Event)) watch.Interface {
 | 
						|
	w := events.Watch()
 | 
						|
	go func() {
 | 
						|
		defer util.HandleCrash()
 | 
						|
		for {
 | 
						|
			watchEvent, open := <-w.ResultChan()
 | 
						|
			if !open {
 | 
						|
				return
 | 
						|
			}
 | 
						|
			event, ok := watchEvent.Object.(*api.Event)
 | 
						|
			if !ok {
 | 
						|
				// This is all local, so there's no reason this should
 | 
						|
				// ever happen.
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			f(event)
 | 
						|
		}
 | 
						|
	}()
 | 
						|
	return w
 | 
						|
}
 | 
						|
 | 
						|
const queueLen = 1000
 | 
						|
 | 
						|
var events = watch.NewBroadcaster(queueLen)
 | 
						|
 | 
						|
// Event constructs an event from the given information and puts it in the queue for sending.
 | 
						|
// 'object' is the object this event is about. Event will make a reference-- or you may also
 | 
						|
// pass a reference to the object directly.
 | 
						|
// 'condition' is the new condition of the object. 'reason' is the reason it now has this status.
 | 
						|
// Both 'condition' and 'reason' should be short and unique; they will be used to automate
 | 
						|
// handling of events, so imagine people writing switch statements to handle them. You want to
 | 
						|
// make that easy.
 | 
						|
// 'message' is intended to be human readable.
 | 
						|
//
 | 
						|
// The resulting event will be created in the same namespace as the reference object.
 | 
						|
func Event(object runtime.Object, condition, reason, message string) {
 | 
						|
	ref, err := api.GetReference(object)
 | 
						|
	if err != nil {
 | 
						|
		glog.Errorf("Could not construct reference to: '%#v' due to: '%v'. Will not report event: '%v' '%v' '%v'", object, err, condition, reason, message)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	t := util.Now()
 | 
						|
 | 
						|
	e := &api.Event{
 | 
						|
		ObjectMeta: api.ObjectMeta{
 | 
						|
			Name:      fmt.Sprintf("%v.%x", ref.Name, t.UnixNano()),
 | 
						|
			Namespace: ref.Namespace,
 | 
						|
		},
 | 
						|
		InvolvedObject: *ref,
 | 
						|
		Condition:      condition,
 | 
						|
		Reason:         reason,
 | 
						|
		Message:        message,
 | 
						|
		Timestamp:      t,
 | 
						|
	}
 | 
						|
 | 
						|
	events.Action(watch.Added, e)
 | 
						|
}
 | 
						|
 | 
						|
// Eventf is just like Event, but with Sprintf for the message field.
 | 
						|
func Eventf(object runtime.Object, status, reason, messageFmt string, args ...interface{}) {
 | 
						|
	Event(object, status, reason, fmt.Sprintf(messageFmt, args...))
 | 
						|
}
 |