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 }