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 }