github.com/timstclair/heapster@v0.20.0-alpha1/events/sources/kubernetes/kubernetes_source.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kubernetes
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    20  	"time"
    21  
    22  	"github.com/golang/glog"
    23  
    24  	kubeconfig "k8s.io/heapster/common/kubernetes"
    25  	"k8s.io/heapster/events/core"
    26  	kubeapi "k8s.io/kubernetes/pkg/api"
    27  	kubeapiunv "k8s.io/kubernetes/pkg/api/unversioned"
    28  	kubeclient "k8s.io/kubernetes/pkg/client/unversioned"
    29  	kubefields "k8s.io/kubernetes/pkg/fields"
    30  	kubelabels "k8s.io/kubernetes/pkg/labels"
    31  	kubewatch "k8s.io/kubernetes/pkg/watch"
    32  )
    33  
    34  const (
    35  	// Number of object pointers. Big enough so it won't be hit anytime soon with resonable GetNewEvents frequency.
    36  	LocalEventsBufferSize = 100000
    37  )
    38  
    39  // Implements core.EventSource interface.
    40  type KubernetesEventSource struct {
    41  	// Large local buffer, periodically read.
    42  	localEventsBuffer chan *kubeapi.Event
    43  
    44  	stopChannel  chan struct{}
    45  	errorChannel chan error
    46  
    47  	eventClient kubeclient.EventInterface
    48  }
    49  
    50  func (this *KubernetesEventSource) GetNewEvents() *core.EventBatch {
    51  	result := core.EventBatch{
    52  		Timestamp: time.Now(),
    53  		Events:    []*kubeapi.Event{},
    54  	}
    55  	// Get all data from the buffer.
    56  event_loop:
    57  	for {
    58  		select {
    59  		case event := <-this.localEventsBuffer:
    60  			result.Events = append(result.Events, event)
    61  		default:
    62  			break event_loop
    63  		}
    64  	}
    65  	return &result
    66  }
    67  
    68  func (this *KubernetesEventSource) watch() {
    69  	defer close(this.errorChannel)
    70  
    71  	// Outer loop, for reconnections.
    72  	for {
    73  		events, err := this.eventClient.List(kubelabels.Everything(), kubefields.Everything())
    74  		if err != nil {
    75  			glog.Fatalf("Failed to load events: %v", err)
    76  			this.errorChannel <- fmt.Errorf("Failed to load events")
    77  			return
    78  		}
    79  		// Do not write old events.
    80  
    81  		resourceVersion := events.ResourceVersion
    82  
    83  		watcher, err := this.eventClient.Watch(
    84  			kubelabels.Everything(),
    85  			kubefields.Everything(),
    86  			kubeapi.ListOptions{
    87  				LabelSelector:   kubelabels.Everything(),
    88  				FieldSelector:   kubefields.Everything(),
    89  				Watch:           true,
    90  				ResourceVersion: resourceVersion})
    91  		if err != nil {
    92  			glog.Fatalf("Failed to start watch for new events: %v", err)
    93  			this.errorChannel <- fmt.Errorf("Failed to start watch")
    94  			return
    95  		}
    96  
    97  		watchChannel := watcher.ResultChan()
    98  		// Inner loop, for update processing.
    99  		for {
   100  			select {
   101  			case watchUpdate, ok := <-watchChannel:
   102  				if !ok {
   103  					glog.Errorf("Event watch channel closed")
   104  					break
   105  				}
   106  
   107  				if watchUpdate.Type == kubewatch.Error {
   108  					if status, ok := watchUpdate.Object.(*kubeapiunv.Status); ok {
   109  						glog.Errorf("Error during watch: %#v", status)
   110  						break
   111  					}
   112  					glog.Errorf("Received unexpected error: %#v", watchUpdate.Object)
   113  					break
   114  				}
   115  
   116  				if event, ok := watchUpdate.Object.(*kubeapi.Event); ok {
   117  					switch watchUpdate.Type {
   118  					case kubewatch.Added, kubewatch.Modified:
   119  						select {
   120  						case this.localEventsBuffer <- event:
   121  							// Ok, buffer not full.
   122  						default:
   123  							// Buffer full, need to drop the event.
   124  							glog.Errorf("Event buffer full, dropping event")
   125  						}
   126  					case kubewatch.Deleted:
   127  						// Deleted events are silently ignored.
   128  					default:
   129  						glog.Warningf("Unknown watchUpdate.Type: %#v", watchUpdate.Type)
   130  					}
   131  				} else {
   132  					glog.Fatalf("Wrong object received: %v", watchUpdate)
   133  				}
   134  
   135  			case <-this.stopChannel:
   136  				glog.Infof("Event watching stopped")
   137  				return
   138  			}
   139  		}
   140  	}
   141  }
   142  
   143  func NewKubernetesSource(uri *url.URL) (*KubernetesEventSource, error) {
   144  	kubeConfig, err := kubeconfig.GetKubeClientConfig(uri)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	kubeClient, err := kubeclient.New(kubeConfig)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	eventClient := kubeClient.Events(kubeapi.NamespaceAll)
   153  	result := KubernetesEventSource{
   154  		localEventsBuffer: make(chan *kubeapi.Event, LocalEventsBufferSize),
   155  		stopChannel:       make(chan struct{}),
   156  		errorChannel:      make(chan error, 1),
   157  		eventClient:       eventClient,
   158  	}
   159  	go result.watch()
   160  	return &result, nil
   161  }