kubernetes-operator 0.0.5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/kubernetes-operator.rb +138 -77
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3f00225b351939f42585587df92d9bd3e5425ded2a8c260f58171a39216bb77
|
4
|
+
data.tar.gz: 6eb6bf84877a2aabe98f6df1ebbe7a549822cf17cf1dfcc65d8813187d29202b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af548e2e4d2873aa1841cabf4c9c3021341f81a7e5fdb6f63b77fedd6a8dd5f917740dbf416346a31b722ee521084c0e1e8405cd9fee91c81f91a674004d27aa
|
7
|
+
data.tar.gz: 692bf36c849fc4b839376d1d9a03b80059e49441de9f4f9a81890950aab0d1d286d19a29b132df075ca4617c2a8566e557044b99c7a4fa0240b44799359ee524
|
data/lib/kubernetes-operator.rb
CHANGED
@@ -13,8 +13,111 @@ require 'log_formatter'
|
|
13
13
|
require 'log_formatter/log4r_json_formatter'
|
14
14
|
require 'json'
|
15
15
|
|
16
|
+
class EventHelper
|
17
|
+
|
18
|
+
# EventHelper initialize provides an helper class to add and delete events from ressources
|
19
|
+
# @see https://www.bluematador.com/blog/kubernetes-events-explained Documentation
|
20
|
+
# @param logger [Log4r::Logger] Logger for this class
|
21
|
+
def initialize(logger)
|
22
|
+
# logging
|
23
|
+
@logger = logger
|
24
|
+
|
25
|
+
# kubeconfig
|
26
|
+
# we need our own client because its an different api path
|
27
|
+
# (for local development it's nice to use .kube/config)
|
28
|
+
if File.exist?("#{Dir.home}/.kube/config")
|
29
|
+
config = Kubeclient::Config.read(ENV['KUBECONFIG'] || "#{ENV['HOME']}/.kube/config")
|
30
|
+
context = config.context
|
31
|
+
@k8sclient = Kubeclient::Client.new(
|
32
|
+
context.api_endpoint,
|
33
|
+
'v1',
|
34
|
+
ssl_options: context.ssl_options,
|
35
|
+
auth_options: context.auth_options
|
36
|
+
)
|
37
|
+
else
|
38
|
+
auth_options = {
|
39
|
+
bearer_token_file: '/var/run/secrets/kubernetes.io/serviceaccount/token'
|
40
|
+
}
|
41
|
+
ssl_options = {}
|
42
|
+
if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
|
43
|
+
ssl_options[:ca_file] = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
44
|
+
end
|
45
|
+
@k8sclient = Kubeclient::Client.new(
|
46
|
+
'https://kubernetes.default.svc',
|
47
|
+
'v1',
|
48
|
+
auth_options: auth_options,
|
49
|
+
ssl_options: ssl_options
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add an event
|
55
|
+
# @param obj [Hash] Kubernetes custom resource object as hash (required)
|
56
|
+
# @param message [string] Event message (required)
|
57
|
+
# @param reason [string] Event reason (default: "Upsert")
|
58
|
+
# @param type [string] Event type (default: "Normal")
|
59
|
+
# @param component [string] Event component (default: "KubernetesOperator")
|
60
|
+
def add(obj,message,reason = "Upsert",type = "Normal", component = "KubernetesOperator")
|
61
|
+
begin
|
62
|
+
event = Kubeclient::Resource.new
|
63
|
+
time = Time.new.utc
|
64
|
+
|
65
|
+
_tmpNS = obj[:metadata][:namespace]
|
66
|
+
|
67
|
+
event.firstTimestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
68
|
+
event.lastTimestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
69
|
+
event.involvedObject = {}
|
70
|
+
event.involvedObject.apiVersion = obj[:apiVersion]
|
71
|
+
event.involvedObject.kind = obj[:kind]
|
72
|
+
event.involvedObject.name = obj[:metadata][:name]
|
73
|
+
event.involvedObject.namespace = obj[:metadata][:namespace]
|
74
|
+
event.involvedObject.resourceVersion = obj[:metadata][:resourceVersion]
|
75
|
+
event.involvedObject.uid = obj[:metadata][:uid]
|
76
|
+
event.kind = "Event"
|
77
|
+
event.message = message
|
78
|
+
event.metadata = {}
|
79
|
+
event.metadata.name = "#{obj[:metadata][:name]}.#{time.to_i}"
|
80
|
+
event.metadata.namespace = obj[:metadata][:namespace] ||= "default"
|
81
|
+
event.reason = reason
|
82
|
+
event.source = {}
|
83
|
+
event.source.component = component
|
84
|
+
event.type = type
|
85
|
+
|
86
|
+
@k8sclient.create_event(event)
|
87
|
+
|
88
|
+
@logger.info("add event #{message}(#{type}) to #{obj[:metadata][:name]}(#{obj[:metadata][:uid]})")
|
89
|
+
rescue => exception
|
90
|
+
@logger.error(exception.inspect)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
# Delete all events from an cr
|
96
|
+
# @param obj [Hash] Kubernetes custom resource object as hash (required)
|
97
|
+
def deleteAll(obj)
|
98
|
+
begin
|
99
|
+
events = @k8sclient.get_events(namespace: obj[:metadata][:namespace],field_selector: "involvedObject.uid=#{obj[:metadata][:uid]}")
|
100
|
+
events.each do |event|
|
101
|
+
@logger.info("delete event #{event[:metadata][:name]}(#{event[:metadata][:namespace]}) from #{obj[:metadata][:name]}(#{obj[:metadata][:uid]})")
|
102
|
+
@k8sclient.delete_event(event[:metadata][:name],event[:metadata][:namespace])
|
103
|
+
end
|
104
|
+
rescue => exception
|
105
|
+
@logger.error(exception.inspect)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
16
110
|
class KubernetesOperator
|
17
111
|
|
112
|
+
# Operator Class to run the core operator functions for your crd
|
113
|
+
# @see https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning/ Documentation
|
114
|
+
# @param group [string] Group from crd
|
115
|
+
# @param version [string] Api Version from crd
|
116
|
+
# @param plural [string] Name (plural) from crd
|
117
|
+
# @param options [Hash] Additional options
|
118
|
+
# @option options [Hash] sleepTimer Time to wait for retry if the watch event stops
|
119
|
+
# @option options [Hash] namespace Watch only an namespace, default watch all namespaces
|
120
|
+
# @option options [Hash] persistence_location Location for the yaml store, default is /tmp/persistence
|
18
121
|
def initialize(crdGroup, crdVersion, crdPlural, options = {} )
|
19
122
|
# parameter
|
20
123
|
@crdGroup = crdGroup
|
@@ -67,34 +170,55 @@ class KubernetesOperator
|
|
67
170
|
ssl_options: ssl_options
|
68
171
|
)
|
69
172
|
end
|
173
|
+
|
174
|
+
# event helper
|
175
|
+
@eventHelper = EventHelper.new(@logger)
|
70
176
|
end
|
71
177
|
|
72
178
|
# Action Methods
|
179
|
+
|
180
|
+
# Set the method that was triggert then an add cr event occurred
|
181
|
+
# @param callback [methode] Ruby methode
|
73
182
|
def setAddMethod(callback)
|
74
183
|
@addMethod = callback
|
75
184
|
end
|
76
185
|
|
186
|
+
# Set the method that was triggert then an update cr event occurred
|
187
|
+
# @param callback [methode] Ruby methode
|
77
188
|
def setUpdateMethod(callback)
|
78
189
|
@updateMethod = callback
|
79
190
|
end
|
80
191
|
|
192
|
+
# Set the method that was triggert then an add or update cr event occurred
|
193
|
+
# This function overwrite setAddMethod and setUpdateMethod
|
194
|
+
# @param callback [methode] Ruby methode
|
81
195
|
def setUpsertMethod(callback)
|
82
196
|
@updateMethod = callback
|
83
197
|
@addMethod = callback
|
84
198
|
end
|
85
199
|
|
200
|
+
# Set the method that was triggert then an delete cr event occurred
|
201
|
+
# @param callback [methode] Ruby methode
|
86
202
|
def setDeleteMethod(callback)
|
87
203
|
@deleteMethod = callback
|
88
204
|
end
|
89
205
|
|
90
|
-
#
|
206
|
+
# Helper Methods
|
207
|
+
|
208
|
+
# get the logger from the operatore framework
|
209
|
+
# @return [Log4r::Logger] logger
|
91
210
|
def getLogger()
|
92
211
|
return @logger
|
93
212
|
end
|
94
213
|
|
95
|
-
#
|
96
|
-
|
214
|
+
# get the event helper from the operatore framework
|
215
|
+
# @return [EventHelper] event helper
|
216
|
+
def getEventHelper()
|
217
|
+
return @eventHelper
|
218
|
+
end
|
97
219
|
|
220
|
+
# start the operator to watch your cr
|
221
|
+
def run
|
98
222
|
@logger.info("start the operator")
|
99
223
|
# load methods
|
100
224
|
@addMethod = method(:defaultActionMethod) unless @addMethod
|
@@ -102,7 +226,6 @@ class KubernetesOperator
|
|
102
226
|
@deleteMethod = method(:defaultActionMethod) unless @deleteMethod
|
103
227
|
|
104
228
|
while true
|
105
|
-
|
106
229
|
begin
|
107
230
|
if @options[:namespace]
|
108
231
|
watcher = @k8sclient.watch_entities(@crdPlural,@options[:namespace])
|
@@ -117,9 +240,6 @@ class KubernetesOperator
|
|
117
240
|
when "ADDED"
|
118
241
|
# check if version is already processed
|
119
242
|
unless isCached
|
120
|
-
# add finalizer
|
121
|
-
@logger.info("add finalizer to #{notice[:object][:metadata][:name]} (#{notice[:object][:metadata][:uid]})")
|
122
|
-
patched = @k8sclient.patch_entity(@crdPlural,notice[:object][:metadata][:name], {metadata: {finalizers: ["#{@crdPlural}.#{@crdVersion}.#{@crdGroup}"]}},'merge-patch',@options[:namespace])
|
123
243
|
# trigger action
|
124
244
|
@logger.info("trigger add action for #{notice[:object][:metadata][:name]} (#{notice[:object][:metadata][:uid]})")
|
125
245
|
resp = @addMethod.call(notice[:object],@k8sclient)
|
@@ -127,6 +247,9 @@ class KubernetesOperator
|
|
127
247
|
if resp[:status]
|
128
248
|
@k8sclient.patch_entity(@crdPlural,notice[:object][:metadata][:name]+"/status", {status: resp[:status]},'merge-patch',@options[:namespace])
|
129
249
|
end
|
250
|
+
# add finalizer
|
251
|
+
@logger.info("add finalizer to #{notice[:object][:metadata][:name]} (#{notice[:object][:metadata][:uid]})")
|
252
|
+
patched = @k8sclient.patch_entity(@crdPlural,notice[:object][:metadata][:name], {metadata: {finalizers: ["#{@crdPlural}.#{@crdVersion}.#{@crdGroup}"]}},'merge-patch',@options[:namespace])
|
130
253
|
# save version
|
131
254
|
@store.transaction do
|
132
255
|
@store[patched[:metadata][:uid]] = patched[:metadata][:resourceVersion]
|
@@ -138,7 +261,7 @@ class KubernetesOperator
|
|
138
261
|
# cr was change or deleted (if finalizer is set, it an modified call, not an delete)
|
139
262
|
when "MODIFIED"
|
140
263
|
# check if version is already processed
|
141
|
-
if isCached
|
264
|
+
if isCached.to_i < notice[:object][:metadata][:resourceVersion].to_i
|
142
265
|
# check if it's an delete event
|
143
266
|
unless notice[:object][:metadata][:deletionTimestamp]
|
144
267
|
# trigger action
|
@@ -165,94 +288,32 @@ class KubernetesOperator
|
|
165
288
|
@logger.info("skip update action for #{notice[:object][:metadata][:name]} (#{notice[:object][:metadata][:uid]}), found version in cache")
|
166
289
|
end
|
167
290
|
when "DELETED"
|
168
|
-
|
291
|
+
# clear events, if delete was successfuly
|
292
|
+
@logger.info("#{notice[:object][:metadata][:name]} (#{notice[:object][:metadata][:uid]}) is done, clean up events")
|
293
|
+
@eventHelper.deleteAll(notice[:object])
|
169
294
|
else
|
295
|
+
# upsi, something wrong
|
170
296
|
@logger.info("strange things are going on here, I found the type "+notice[:type])
|
171
297
|
end
|
172
298
|
rescue => exception
|
173
299
|
@logger.error(exception.inspect)
|
174
300
|
end
|
175
301
|
end
|
302
|
+
# watcher is done, lost connection ...
|
176
303
|
watcher.finish
|
177
|
-
|
178
|
-
## Search for ressources
|
179
|
-
#_ressources = @k8sclient.get(@crdGroup+"/"+@crdVersion).resource(@crdPlural).list()
|
180
|
-
|
181
|
-
#_ressources.each do |_i|
|
182
|
-
# _uid = _i["metadata"]["uid"]
|
183
|
-
# _v = _i["metadata"]["resourceVersion"]
|
184
|
-
|
185
|
-
# if @options[:namespace] == nil || @options[:namespace].contains(_i["metadata"]["namespace"])
|
186
|
-
# _from_cache = @store.transaction{@store[_uid]}
|
187
|
-
|
188
|
-
# unless _from_cache
|
189
|
-
# # Add finalizer and refresh version number
|
190
|
-
# _i[:metadata][:finalizers] = ["#{@crdPlural}.#{@crdVersion}.#{@crdGroup}"]
|
191
|
-
# _i = @k8sclient.api(@crdGroup+"/"+@crdVersion).resource(@crdPlural).update_resource(_i)
|
192
|
-
|
193
|
-
# # call the action method
|
194
|
-
# _i["metadata"]["crd_status"] = "add"
|
195
|
-
# @logger.info("add custom resource #{_i["metadata"]["name"]}@#{_i["metadata"]["namespace"]}") if _i["metadata"]["namespace"]
|
196
|
-
# @logger.info("add custom resource #{_i["metadata"]["name"]}@cluster") unless _i["metadata"]["namespace"]
|
197
|
-
# @addMethod.call(_i,@k8sclient)
|
198
|
-
|
199
|
-
# # update status
|
200
|
-
# _i[:status] = {message: "Test"}
|
201
|
-
# _i = @k8sclient.api(@crdGroup+"/"+@crdVersion).resource(@crdPlural).update_resource(_i)
|
202
|
-
|
203
|
-
# # Cache last version of ressources
|
204
|
-
# @store.transaction do
|
205
|
-
# @store[_uid] = _i["metadata"]["resourceVersion"]
|
206
|
-
# @store.commit
|
207
|
-
# end
|
208
|
-
|
209
|
-
# else
|
210
|
-
# # only trigger action on change or delete event
|
211
|
-
# unless _from_cache == _v
|
212
|
-
# if _i["metadata"]["deletionTimestamp"]
|
213
|
-
# # remove finalizers
|
214
|
-
# _i[:metadata][:finalizers] = []
|
215
|
-
# @k8sclient.api(@crdGroup+"/"+@crdVersion).resource(@crdPlural).update_resource(_i)
|
216
|
-
|
217
|
-
# # call the action method
|
218
|
-
# _i["metadata"]["crd_status"] = "delete"
|
219
|
-
# @logger.info("delete custom resource #{_i["metadata"]["name"]}@#{_i["metadata"]["namespace"]}") if _i["metadata"]["namespace"]
|
220
|
-
# @logger.info("delete custom resource #{_i["metadata"]["name"]}@cluster") unless _i["metadata"]["namespace"]
|
221
|
-
# @deleteMethod.call(_i,@k8sclient)
|
222
|
-
# else
|
223
|
-
# # store new version in cache
|
224
|
-
# @store.transaction do
|
225
|
-
# @store[_uid] = _v
|
226
|
-
# @store.commit
|
227
|
-
# end
|
228
|
-
|
229
|
-
# # call the action method
|
230
|
-
# _i["metadata"]["crd_status"] = "update"
|
231
|
-
# @logger.info("update custom resource #{_i["metadata"]["name"]}@#{_i["metadata"]["namespace"]}") if _i["metadata"]["namespace"]
|
232
|
-
# @logger.info("update custom resource #{_i["metadata"]["name"]}@cluster") unless _i["metadata"]["namespace"]
|
233
|
-
# @updateMethod.call(_i,@k8sclient)
|
234
|
-
# end
|
235
|
-
# end
|
236
|
-
# end
|
237
|
-
# end
|
238
|
-
#end
|
239
|
-
|
240
304
|
rescue => exception
|
241
305
|
@logger.error(exception.inspect)
|
242
306
|
end
|
243
307
|
|
244
|
-
#
|
308
|
+
# done
|
245
309
|
sleep @options[:sleepTimer]
|
246
310
|
|
247
311
|
end
|
248
312
|
end
|
249
313
|
|
314
|
+
# default methode, only an esay print command
|
250
315
|
private
|
251
316
|
def defaultActionMethod(obj,k8sclient)
|
252
317
|
puts "{leve: \"info\", action: \"#{obj["metadata"]["crd_status"]}\", ressource: \"#{obj["metadata"]["namespace"]}/#{obj["metadata"]["name"]}\"}"
|
253
318
|
end
|
254
319
|
end
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubernetes-operator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Kuntzsch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kubeclient
|