github.com/caesarxuchao/heapster@v1.1.0/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  	"net/url"
    19  	"time"
    20  
    21  	"github.com/golang/glog"
    22  	"github.com/prometheus/client_golang/prometheus"
    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  var (
    40  	// Last time of event since unix epoch in seconds
    41  	lastEventTimestamp = prometheus.NewGauge(
    42  		prometheus.GaugeOpts{
    43  			Namespace: "eventer",
    44  			Subsystem: "scraper",
    45  			Name:      "last_time_seconds",
    46  			Help:      "Last time of event since unix epoch in seconds.",
    47  		})
    48  	totalEventsNum = prometheus.NewCounter(
    49  		prometheus.CounterOpts{
    50  			Namespace: "eventer",
    51  			Subsystem: "scraper",
    52  			Name:      "events_total_number",
    53  			Help:      "The total number of events.",
    54  		})
    55  	scrapEventsDuration = prometheus.NewSummary(
    56  		prometheus.SummaryOpts{
    57  			Namespace: "eventer",
    58  			Subsystem: "scraper",
    59  			Name:      "duration_microseconds",
    60  			Help:      "Time spent scraping events in microseconds.",
    61  		})
    62  )
    63  
    64  func init() {
    65  	prometheus.MustRegister(lastEventTimestamp)
    66  	prometheus.MustRegister(totalEventsNum)
    67  	prometheus.MustRegister(scrapEventsDuration)
    68  }
    69  
    70  // Implements core.EventSource interface.
    71  type KubernetesEventSource struct {
    72  	// Large local buffer, periodically read.
    73  	localEventsBuffer chan *kubeapi.Event
    74  
    75  	stopChannel chan struct{}
    76  
    77  	eventClient kubeclient.EventInterface
    78  }
    79  
    80  func (this *KubernetesEventSource) GetNewEvents() *core.EventBatch {
    81  	startTime := time.Now()
    82  	defer lastEventTimestamp.Set(float64(time.Now().Unix()))
    83  	defer scrapEventsDuration.Observe(float64(time.Since(startTime)) / float64(time.Microsecond))
    84  	result := core.EventBatch{
    85  		Timestamp: time.Now(),
    86  		Events:    []*kubeapi.Event{},
    87  	}
    88  	// Get all data from the buffer.
    89  event_loop:
    90  	for {
    91  		select {
    92  		case event := <-this.localEventsBuffer:
    93  			result.Events = append(result.Events, event)
    94  		default:
    95  			break event_loop
    96  		}
    97  	}
    98  
    99  	totalEventsNum.Add(float64(len(result.Events)))
   100  	return &result
   101  }
   102  
   103  func (this *KubernetesEventSource) watch() {
   104  	// Outer loop, for reconnections.
   105  	for {
   106  		events, err := this.eventClient.List(kubeapi.ListOptions{
   107  			LabelSelector: kubelabels.Everything(),
   108  			FieldSelector: kubefields.Everything(),
   109  		})
   110  		if err != nil {
   111  			glog.Errorf("Failed to load events: %v", err)
   112  			time.Sleep(time.Second)
   113  			continue
   114  		}
   115  		// Do not write old events.
   116  
   117  		resourceVersion := events.ResourceVersion
   118  
   119  		watcher, err := this.eventClient.Watch(
   120  			kubeapi.ListOptions{
   121  				LabelSelector:   kubelabels.Everything(),
   122  				FieldSelector:   kubefields.Everything(),
   123  				Watch:           true,
   124  				ResourceVersion: resourceVersion})
   125  		if err != nil {
   126  			glog.Errorf("Failed to start watch for new events: %v", err)
   127  			time.Sleep(time.Second)
   128  			continue
   129  		}
   130  
   131  		watchChannel := watcher.ResultChan()
   132  		// Inner loop, for update processing.
   133  	inner_loop:
   134  		for {
   135  			select {
   136  			case watchUpdate, ok := <-watchChannel:
   137  				if !ok {
   138  					glog.Errorf("Event watch channel closed")
   139  					break inner_loop
   140  				}
   141  
   142  				if watchUpdate.Type == kubewatch.Error {
   143  					if status, ok := watchUpdate.Object.(*kubeapiunv.Status); ok {
   144  						glog.Errorf("Error during watch: %#v", status)
   145  						break inner_loop
   146  					}
   147  					glog.Errorf("Received unexpected error: %#v", watchUpdate.Object)
   148  					break inner_loop
   149  				}
   150  
   151  				if event, ok := watchUpdate.Object.(*kubeapi.Event); ok {
   152  					switch watchUpdate.Type {
   153  					case kubewatch.Added, kubewatch.Modified:
   154  						select {
   155  						case this.localEventsBuffer <- event:
   156  							// Ok, buffer not full.
   157  						default:
   158  							// Buffer full, need to drop the event.
   159  							glog.Errorf("Event buffer full, dropping event")
   160  						}
   161  					case kubewatch.Deleted:
   162  						// Deleted events are silently ignored.
   163  					default:
   164  						glog.Warningf("Unknown watchUpdate.Type: %#v", watchUpdate.Type)
   165  					}
   166  				} else {
   167  					glog.Errorf("Wrong object received: %v", watchUpdate)
   168  				}
   169  
   170  			case <-this.stopChannel:
   171  				glog.Infof("Event watching stopped")
   172  				return
   173  			}
   174  		}
   175  	}
   176  }
   177  
   178  func NewKubernetesSource(uri *url.URL) (*KubernetesEventSource, error) {
   179  	kubeConfig, err := kubeconfig.GetKubeClientConfig(uri)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  	kubeClient, err := kubeclient.New(kubeConfig)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	eventClient := kubeClient.Events(kubeapi.NamespaceAll)
   188  	result := KubernetesEventSource{
   189  		localEventsBuffer: make(chan *kubeapi.Event, LocalEventsBufferSize),
   190  		stopChannel:       make(chan struct{}),
   191  		eventClient:       eventClient,
   192  	}
   193  	go result.watch()
   194  	return &result, nil
   195  }