fluent-plugin-wh-kubernetes_metadata_filter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +53 -0
  3. data/.gitignore +18 -0
  4. data/.rubocop.yml +57 -0
  5. data/Gemfile +9 -0
  6. data/LICENSE +201 -0
  7. data/README.md +179 -0
  8. data/Rakefile +41 -0
  9. data/fluent-plugin-wh-kubernetes_metadata_filter.gemspec +33 -0
  10. data/lib/fluent/plugin/filter_kubernetes_metadata.rb +381 -0
  11. data/lib/fluent/plugin/kubernetes_metadata_cache_strategy.rb +100 -0
  12. data/lib/fluent/plugin/kubernetes_metadata_common.rb +130 -0
  13. data/lib/fluent/plugin/kubernetes_metadata_stats.rb +62 -0
  14. data/lib/fluent/plugin/kubernetes_metadata_test_api_adapter.rb +68 -0
  15. data/lib/fluent/plugin/kubernetes_metadata_util.rb +33 -0
  16. data/lib/fluent/plugin/kubernetes_metadata_watch_namespaces.rb +187 -0
  17. data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +205 -0
  18. data/test/cassettes/invalid_api_server_config.yml +53 -0
  19. data/test/cassettes/kubernetes_docker_metadata_annotations.yml +205 -0
  20. data/test/cassettes/kubernetes_docker_metadata_dotted_slashed_labels.yml +197 -0
  21. data/test/cassettes/kubernetes_get_api_v1.yml +193 -0
  22. data/test/cassettes/kubernetes_get_api_v1_using_token.yml +195 -0
  23. data/test/cassettes/kubernetes_get_namespace_default.yml +72 -0
  24. data/test/cassettes/kubernetes_get_namespace_default_using_token.yml +71 -0
  25. data/test/cassettes/kubernetes_get_pod.yml +146 -0
  26. data/test/cassettes/kubernetes_get_pod_container_init.yml +145 -0
  27. data/test/cassettes/kubernetes_get_pod_using_token.yml +148 -0
  28. data/test/cassettes/metadata_from_tag_and_journald_fields.yml +153 -0
  29. data/test/cassettes/metadata_from_tag_journald_and_kubernetes_fields.yml +285 -0
  30. data/test/cassettes/valid_kubernetes_api_server.yml +55 -0
  31. data/test/cassettes/valid_kubernetes_api_server_using_token.yml +57 -0
  32. data/test/helper.rb +82 -0
  33. data/test/plugin/test.token +1 -0
  34. data/test/plugin/test_cache_stats.rb +33 -0
  35. data/test/plugin/test_cache_strategy.rb +194 -0
  36. data/test/plugin/test_filter_kubernetes_metadata.rb +810 -0
  37. data/test/plugin/test_watch_namespaces.rb +245 -0
  38. data/test/plugin/test_watch_pods.rb +344 -0
  39. data/test/plugin/watch_test.rb +76 -0
  40. metadata +276 -0
@@ -0,0 +1,810 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Fluentd Kubernetes Metadata Filter Plugin - Enrich Fluentd events with
5
+ # Kubernetes metadata
6
+ #
7
+ # Copyright 2015 Red Hat, Inc.
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ require_relative '../helper'
22
+
23
+ class KubernetesMetadataFilterTest < Test::Unit::TestCase
24
+ include Fluent
25
+
26
+ setup do
27
+ Fluent::Test.setup
28
+ @time = Fluent::Engine.now
29
+ end
30
+
31
+ VAR_LOG_CONTAINER_TAG = 'var.log.containers.fabric8-console-controller-98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log'
32
+ VAR_LOG_POD_TAG = 'var.log.pods.default_fabric8-console-controller-98rqc_c76927af-f563-11e4-b32d-54ee7527188d.fabric8-console-container.0.log'
33
+
34
+ def create_driver(conf = '')
35
+ Test::Driver::Filter.new(Plugin::KubernetesMetadataFilter).configure(conf)
36
+ end
37
+
38
+ sub_test_case 'configure' do
39
+ test 'check default' do
40
+ d = create_driver
41
+ assert_equal(1000, d.instance.cache_size)
42
+ end
43
+
44
+ sub_test_case 'stats_interval' do
45
+
46
+ test 'enables stats when greater than zero' do
47
+ d = create_driver('stats_interval 1')
48
+ assert_equal(1, d.instance.stats_interval)
49
+ d.instance.dump_stats
50
+ assert_false(d.instance.instance_variable_get("@curr_time").nil?)
51
+ end
52
+
53
+ test 'disables stats when <= zero' do
54
+ d = create_driver('stats_interval 0')
55
+ assert_equal(0, d.instance.stats_interval)
56
+ d.instance.dump_stats
57
+ assert_nil(d.instance.instance_variable_get("@curr_time"))
58
+ end
59
+
60
+ end
61
+
62
+ test 'check test_api_adapter' do
63
+ d = create_driver('test_api_adapter KubernetesMetadata::TestApiAdapter')
64
+ assert_equal('KubernetesMetadata::TestApiAdapter', d.instance.test_api_adapter)
65
+ end
66
+
67
+ test 'kubernetes url' do
68
+ VCR.use_cassette('valid_kubernetes_api_server') do
69
+ d = create_driver('
70
+ kubernetes_url https://localhost:8443
71
+ watch false
72
+ ')
73
+ assert_equal('https://localhost:8443', d.instance.kubernetes_url)
74
+ assert_equal(1000, d.instance.cache_size)
75
+ end
76
+ end
77
+
78
+ test 'cache size' do
79
+ VCR.use_cassette('valid_kubernetes_api_server') do
80
+ d = create_driver('
81
+ kubernetes_url https://localhost:8443
82
+ watch false
83
+ cache_size 1
84
+ ')
85
+ assert_equal('https://localhost:8443', d.instance.kubernetes_url)
86
+ assert_equal(1, d.instance.cache_size)
87
+ end
88
+ end
89
+
90
+ test 'invalid API server config' do
91
+ VCR.use_cassette('invalid_api_server_config') do
92
+ assert_raise Fluent::ConfigError do
93
+ create_driver('
94
+ kubernetes_url https://localhost:8443
95
+ bearer_token_file test/plugin/test.token
96
+ watch false
97
+ verify_ssl false
98
+ ')
99
+ end
100
+ end
101
+ end
102
+
103
+ test 'service account credentials' do
104
+ VCR.use_cassette('valid_kubernetes_api_server') do
105
+ ENV['KUBERNETES_SERVICE_HOST'] = 'localhost'
106
+ ENV['KUBERNETES_SERVICE_PORT'] = '8443'
107
+
108
+ Dir.mktmpdir do |dir|
109
+ # Fake token file and CA crt.
110
+ expected_cert_path = File.join(dir, Plugin::KubernetesMetadataFilter::K8_POD_CA_CERT)
111
+ expected_token_path = File.join(dir, Plugin::KubernetesMetadataFilter::K8_POD_TOKEN)
112
+
113
+ File.open(expected_cert_path, 'w')
114
+ File.open(expected_token_path, 'w')
115
+
116
+ d = create_driver("
117
+ watch false
118
+ secret_dir #{dir}
119
+ ")
120
+
121
+ assert_equal(d.instance.kubernetes_url, 'https://localhost:8443/api')
122
+ assert_equal(d.instance.ca_file, expected_cert_path)
123
+ assert_equal(d.instance.bearer_token_file, expected_token_path)
124
+ end
125
+ ensure
126
+ ENV['KUBERNETES_SERVICE_HOST'] = nil
127
+ ENV['KUBERNETES_SERVICE_PORT'] = nil
128
+ end
129
+ end
130
+
131
+ test 'service account credential files are tested for existence' do
132
+ VCR.use_cassette('valid_kubernetes_api_server') do
133
+ ENV['KUBERNETES_SERVICE_HOST'] = 'localhost'
134
+ ENV['KUBERNETES_SERVICE_PORT'] = '8443'
135
+
136
+ Dir.mktmpdir do |dir|
137
+ d = create_driver("
138
+ watch false
139
+ secret_dir #{dir}
140
+ ")
141
+ assert_equal(d.instance.kubernetes_url, 'https://localhost:8443/api')
142
+ assert_nil(d.instance.ca_file, nil)
143
+ assert_nil(d.instance.bearer_token_file)
144
+ end
145
+ ensure
146
+ ENV['KUBERNETES_SERVICE_HOST'] = nil
147
+ ENV['KUBERNETES_SERVICE_PORT'] = nil
148
+ end
149
+ end
150
+ end
151
+
152
+ sub_test_case 'filter' do
153
+ def emit(msg = {}, config = '
154
+ kubernetes_url https://localhost:8443
155
+ watch false
156
+ cache_size 1
157
+ ', d: nil)
158
+ d = create_driver(config) if d.nil?
159
+ d.run(default_tag: VAR_LOG_CONTAINER_TAG) do
160
+ d.feed(@time, msg)
161
+ end
162
+ d.filtered.map(&:last)
163
+ end
164
+
165
+ def emit_with_tag(tag, msg = {}, config = '
166
+ kubernetes_url https://localhost:8443
167
+ watch false
168
+ cache_size 1
169
+ ')
170
+ d = create_driver(config)
171
+ d.run(default_tag: tag) do
172
+ d.feed(@time, msg)
173
+ end
174
+ d.filtered.map(&:last)
175
+ end
176
+
177
+ sub_test_case 'parsing_pod_metadata when container_status is missing from the pod status' do
178
+ test 'using the tag_to_kubernetes_name_regexp for /var/log/containers ' do
179
+ VCR.use_cassettes(
180
+ [
181
+ { name: 'valid_kubernetes_api_server' },
182
+ { name: 'kubernetes_get_api_v1' },
183
+ { name: 'kubernetes_get_namespace_default' },
184
+ { name: 'kubernetes_get_pod_container_init' }
185
+ ]) do
186
+ filtered = emit({}, "
187
+ kubernetes_url https://localhost:8443
188
+ watch false
189
+ cache_size 1
190
+ ")
191
+ expected_kube_metadata = {
192
+ 'docker' => {
193
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
194
+ },
195
+ 'kubernetes' => {
196
+ 'container_image'=>'fabric8/hawtio-kubernetes:latest',
197
+ 'container_name'=>'fabric8-console-container',
198
+ 'host' => 'jimmi-redhat.localnet',
199
+ 'pod_name' => 'fabric8-console-controller-98rqc',
200
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
201
+ 'namespace_name' => 'default',
202
+ 'namespace_labels' => {
203
+ 'tenant' => 'test'
204
+ },
205
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
206
+ 'pod_ip' => '172.17.0.8',
207
+ 'master_url' => 'https://localhost:8443',
208
+ 'labels' => {
209
+ 'component' => 'fabric8Console'
210
+ }
211
+ }
212
+ }
213
+ assert_equal(expected_kube_metadata, filtered[0])
214
+ end
215
+ end
216
+ test 'using the tag_to_kubernetes_name_regexp for /var/log/pods' do
217
+ VCR.use_cassettes(
218
+ [
219
+ { name: 'valid_kubernetes_api_server' },
220
+ { name: 'kubernetes_get_api_v1' },
221
+ { name: 'kubernetes_get_namespace_default' },
222
+ { name: 'kubernetes_get_pod_container_init' }
223
+ ]) do
224
+ filtered = emit_with_tag(VAR_LOG_POD_TAG,{}, "
225
+ kubernetes_url https://localhost:8443
226
+ watch false
227
+ cache_size 1
228
+ ")
229
+ expected_kube_metadata = {
230
+ 'kubernetes' => {
231
+ 'container_image'=>'fabric8/hawtio-kubernetes:latest',
232
+ 'container_name'=>'fabric8-console-container',
233
+ 'host' => 'jimmi-redhat.localnet',
234
+ 'pod_name' => 'fabric8-console-controller-98rqc',
235
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
236
+ 'namespace_name' => 'default',
237
+ 'namespace_labels' => {
238
+ 'tenant' => 'test'
239
+ },
240
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
241
+ 'pod_ip' => '172.17.0.8',
242
+ 'master_url' => 'https://localhost:8443',
243
+ 'labels' => {
244
+ 'component' => 'fabric8Console'
245
+ }
246
+ }
247
+ }
248
+ assert_equal(expected_kube_metadata, filtered[0])
249
+ end
250
+ end
251
+ end
252
+
253
+ test 'inability to connect to the api server handles exception and doensnt block pipeline' do
254
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }]) do
255
+ driver = create_driver('
256
+ kubernetes_url https://localhost:8443
257
+ watch false
258
+ cache_size 1
259
+ ')
260
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc').to_raise(SocketError.new('error from pod fetch'))
261
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default').to_raise(SocketError.new('socket error from namespace fetch'))
262
+ filtered = emit({ 'time' => '2015-05-08T09:22:01Z' }, '', d: driver)
263
+ expected_kube_metadata = {
264
+ 'time' => '2015-05-08T09:22:01Z',
265
+ 'docker'=>{
266
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
267
+ },
268
+ 'kubernetes' => {
269
+ 'pod_name' => 'fabric8-console-controller-98rqc',
270
+ 'container_name' => 'fabric8-console-container',
271
+ 'namespace_id' => 'orphaned',
272
+ 'namespace_name' => '.orphaned',
273
+ 'orphaned_namespace' => 'default'
274
+ }
275
+ }
276
+ assert_equal(expected_kube_metadata, filtered[0])
277
+ end
278
+ end
279
+
280
+ test 'with docker & kubernetes metadata where id cache hit and metadata miss' do
281
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }]) do
282
+ driver = create_driver('
283
+ kubernetes_url https://localhost:8443
284
+ watch false
285
+ cache_size 1
286
+ ')
287
+ cache = driver.instance.instance_variable_get(:@id_cache)
288
+ cache['49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'] = {
289
+ pod_id: 'c76927af-f563-11e4-b32d-54ee7527188d',
290
+ namespace_id: '898268c8-4a36-11e5-9d81-42010af0194c'
291
+ }
292
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc').to_timeout
293
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default').to_timeout
294
+ filtered = emit({ 'time' => '2015-05-08T09:22:01Z' }, '', d: driver)
295
+ expected_kube_metadata = {
296
+ 'time' => '2015-05-08T09:22:01Z',
297
+ 'docker' => {
298
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
299
+ },
300
+ 'kubernetes' => {
301
+ 'pod_name' => 'fabric8-console-controller-98rqc',
302
+ 'container_name' => 'fabric8-console-container',
303
+ 'namespace_name' => 'default',
304
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
305
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d'
306
+ }
307
+ }
308
+
309
+ assert_equal(expected_kube_metadata, filtered[0])
310
+ end
311
+ end
312
+
313
+ test 'with docker & kubernetes metadata where id cache hit and metadata is reloaded' do
314
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' }, { name: 'kubernetes_get_namespace_default' }]) do
315
+ driver = create_driver('
316
+ kubernetes_url https://localhost:8443
317
+ watch false
318
+ cache_size 1
319
+ ')
320
+ cache = driver.instance.instance_variable_get(:@id_cache)
321
+ cache['49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'] = {
322
+ pod_id: 'c76927af-f563-11e4-b32d-54ee7527188d',
323
+ namespace_id: '898268c8-4a36-11e5-9d81-42010af0194c'
324
+ }
325
+ filtered = emit({ 'time' => '2015-05-08T09:22:01Z' }, '', d: driver)
326
+ expected_kube_metadata = {
327
+ 'time' => '2015-05-08T09:22:01Z',
328
+ 'docker' => {
329
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
330
+ },
331
+ 'kubernetes' => {
332
+ 'host' => 'jimmi-redhat.localnet',
333
+ 'pod_name' => 'fabric8-console-controller-98rqc',
334
+ 'container_name' => 'fabric8-console-container',
335
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
336
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
337
+ 'namespace_name' => 'default',
338
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
339
+ 'namespace_labels' => {
340
+ 'tenant' => 'test'
341
+ },
342
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
343
+ 'pod_ip' => '172.17.0.8',
344
+ 'master_url' => 'https://localhost:8443',
345
+ 'labels' => {
346
+ 'component' => 'fabric8Console'
347
+ }
348
+ }
349
+ }
350
+
351
+ assert_equal(expected_kube_metadata, filtered[0])
352
+ end
353
+ end
354
+
355
+ test 'with docker & kubernetes metadata' do
356
+
357
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' }, { name: 'kubernetes_get_namespace_default' }]) do
358
+ filtered = emit({ 'time' => '2015-05-08T09:22:01Z' })
359
+ expected_kube_metadata = {
360
+ 'time' => '2015-05-08T09:22:01Z',
361
+ 'docker' => {
362
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
363
+ },
364
+ 'kubernetes' => {
365
+ 'host' => 'jimmi-redhat.localnet',
366
+ 'pod_name' => 'fabric8-console-controller-98rqc',
367
+ 'container_name' => 'fabric8-console-container',
368
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
369
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
370
+ 'namespace_name' => 'default',
371
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
372
+ 'namespace_labels' => {
373
+ 'tenant' => 'test'
374
+ },
375
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
376
+ 'pod_ip' => '172.17.0.8',
377
+ 'master_url' => 'https://localhost:8443',
378
+ 'labels' => {
379
+ 'component' => 'fabric8Console'
380
+ }
381
+ }
382
+ }
383
+
384
+ assert_equal(expected_kube_metadata, filtered[0])
385
+ end
386
+ end
387
+
388
+ test 'kubernetes metadata is cloned so it further processing does not modify the cache' do
389
+
390
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' }, { name: 'kubernetes_get_namespace_default' }]) do
391
+
392
+ d = create_driver('
393
+ kubernetes_url https://localhost:8443
394
+ watch false
395
+ cache_size 1')
396
+ d.run(default_tag: VAR_LOG_POD_TAG) do
397
+ d.feed(@time, { 'time' => '2015-05-08T09:22:01Z' })
398
+ d.feed(@time, { 'time' => '2015-05-08T09:22:01Z' })
399
+ end
400
+ filtered = d.filtered.map(&:last)
401
+ assert_not_equal(filtered[0]['kubernetes']['labels'].object_id, filtered[1]['kubernetes']['labels'].object_id, "Exp. meta to be cloned")
402
+ end
403
+ end
404
+
405
+ test 'with docker & kubernetes metadata & namespace_id enabled' do
406
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' },
407
+ { name: 'kubernetes_get_namespace_default', options: { allow_playback_repeats: true } }]) do
408
+ filtered = emit({}, '
409
+ kubernetes_url https://localhost:8443
410
+ watch false
411
+ cache_size 1
412
+ ')
413
+ expected_kube_metadata = {
414
+ 'docker' => {
415
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
416
+ },
417
+ 'kubernetes' => {
418
+ 'host' => 'jimmi-redhat.localnet',
419
+ 'pod_name' => 'fabric8-console-controller-98rqc',
420
+ 'container_name' => 'fabric8-console-container',
421
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
422
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
423
+ 'namespace_name' => 'default',
424
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
425
+ 'namespace_labels' => {
426
+ 'tenant' => 'test'
427
+ },
428
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
429
+ 'pod_ip' => '172.17.0.8',
430
+ 'master_url' => 'https://localhost:8443',
431
+ 'labels' => {
432
+ 'component' => 'fabric8Console'
433
+ }
434
+ }
435
+ }
436
+ assert_equal(expected_kube_metadata, filtered[0])
437
+ end
438
+ end
439
+
440
+ test 'with docker & kubernetes metadata using bearer token' do
441
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server_using_token' }, { name: 'kubernetes_get_api_v1_using_token' },
442
+ { name: 'kubernetes_get_pod_using_token' }, { name: 'kubernetes_get_namespace_default_using_token' }]) do
443
+ filtered = emit({}, '
444
+ kubernetes_url https://localhost:8443
445
+ verify_ssl false
446
+ watch false
447
+ bearer_token_file test/plugin/test.token
448
+ ')
449
+ expected_kube_metadata = {
450
+ 'docker' => {
451
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
452
+ },
453
+ 'kubernetes' => {
454
+ 'host' => 'jimmi-redhat.localnet',
455
+ 'pod_name' => 'fabric8-console-controller-98rqc',
456
+ 'container_name' => 'fabric8-console-container',
457
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
458
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
459
+ 'namespace_name' => 'default',
460
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
461
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
462
+ 'pod_ip' => '172.17.0.8',
463
+ 'master_url' => 'https://localhost:8443',
464
+ 'labels' => {
465
+ 'component' => 'fabric8Console'
466
+ }
467
+ }
468
+ }
469
+ assert_equal(expected_kube_metadata, filtered[0])
470
+ end
471
+ end
472
+
473
+ test 'with docker & kubernetes metadata but no configured api server' do
474
+ filtered = emit({}, '')
475
+ expected_kube_metadata = {
476
+ 'docker'=>{
477
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
478
+ },
479
+ 'kubernetes' => {
480
+ 'pod_name' => 'fabric8-console-controller-98rqc',
481
+ 'container_name' => 'fabric8-console-container',
482
+ 'namespace_name' => 'default'
483
+ }
484
+ }
485
+ assert_equal(expected_kube_metadata, filtered[0])
486
+ end
487
+
488
+ test 'with docker & inaccessible kubernetes metadata' do
489
+ stub_request(:any, 'https://localhost:8443/api').to_return(
490
+ 'body' => {
491
+ 'versions' => ['v1beta3', 'v1']
492
+ }.to_json
493
+ )
494
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc').to_timeout
495
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default').to_timeout
496
+ filtered = emit
497
+ expected_kube_metadata = {
498
+ 'docker'=>{
499
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
500
+ },
501
+ 'kubernetes' => {
502
+ 'pod_name' => 'fabric8-console-controller-98rqc',
503
+ 'container_name' => 'fabric8-console-container',
504
+ 'namespace_name' => '.orphaned',
505
+ 'orphaned_namespace' => 'default',
506
+ 'namespace_id' => 'orphaned'
507
+ }
508
+ }
509
+ assert_equal(expected_kube_metadata, filtered[0])
510
+ end
511
+
512
+ test 'with dot in pod name' do
513
+ stub_request(:any, 'https://localhost:8443/api').to_return(
514
+ 'body' => {
515
+ 'versions' => ['v1beta3', 'v1']
516
+ }.to_json
517
+ )
518
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller.98rqc').to_timeout
519
+ filtered = emit_with_tag('var.log.containers.fabric8-console-controller.98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log', {}, '')
520
+ expected_kube_metadata = {
521
+ 'docker'=>{
522
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
523
+ },
524
+ 'kubernetes' => {
525
+ 'pod_name' => 'fabric8-console-controller.98rqc',
526
+ 'container_name' => 'fabric8-console-container',
527
+ 'namespace_name' => 'default'
528
+ }
529
+ }
530
+ assert_equal(expected_kube_metadata, filtered[0])
531
+ end
532
+
533
+ test 'with docker metadata, non-kubernetes' do
534
+ filtered = emit_with_tag('non-kubernetes', {}, '')
535
+ assert_false(filtered[0].key?(:kubernetes))
536
+ end
537
+
538
+ test 'ignores invalid json in log field' do
539
+ json_log = "{'foo':123}"
540
+ msg = {
541
+ 'log' => json_log
542
+ }
543
+ filtered = emit_with_tag('non-kubernetes', msg, '')
544
+ assert_equal(msg, filtered[0])
545
+ end
546
+
547
+ test 'with kubernetes annotations' do
548
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' },
549
+ { name: 'kubernetes_docker_metadata_annotations' },
550
+ { name: 'kubernetes_get_namespace_default' }]) do
551
+ filtered = emit({}, '
552
+ kubernetes_url https://localhost:8443
553
+ watch false
554
+ cache_size 1
555
+ annotation_match [ "^custom.+", "two"]
556
+ ')
557
+ expected_kube_metadata = {
558
+ 'docker' => {
559
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
560
+ },
561
+ 'kubernetes' => {
562
+ 'host' => 'jimmi-redhat.localnet',
563
+ 'pod_name' => 'fabric8-console-controller-98rqc',
564
+ 'container_name' => 'fabric8-console-container',
565
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
566
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
567
+ 'namespace_name' => 'default',
568
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
569
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
570
+ 'pod_ip' => '172.17.0.8',
571
+ 'master_url' => 'https://localhost:8443',
572
+ 'labels' => {
573
+ 'component' => 'fabric8Console'
574
+ },
575
+ 'annotations' => {
576
+ 'custom.field1' => 'hello_kitty',
577
+ 'field.two' => 'value'
578
+ }
579
+ }
580
+ }
581
+ assert_equal(expected_kube_metadata, filtered[0])
582
+ end
583
+ end
584
+
585
+ test 'with kubernetes namespace annotations' do
586
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' },
587
+ { name: 'kubernetes_docker_metadata_annotations' },
588
+ { name: 'kubernetes_get_namespace_default' }]) do
589
+ filtered = emit({}, '
590
+ kubernetes_url https://localhost:8443
591
+ watch false
592
+ cache_size 1
593
+ annotation_match [ "^custom.+", "two", "workspace*"]
594
+ ')
595
+ expected_kube_metadata = {
596
+ 'docker' => {
597
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
598
+ },
599
+ 'kubernetes' => {
600
+ 'host' => 'jimmi-redhat.localnet',
601
+ 'pod_name' => 'fabric8-console-controller-98rqc',
602
+ 'container_name' => 'fabric8-console-container',
603
+ 'namespace_name' => 'default',
604
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
605
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
606
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
607
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
608
+ 'pod_ip' => '172.17.0.8',
609
+ 'master_url' => 'https://localhost:8443',
610
+ 'labels' => {
611
+ 'component' => 'fabric8Console'
612
+ },
613
+ 'annotations' => {
614
+ 'custom.field1' => 'hello_kitty',
615
+ 'field.two' => 'value'
616
+ },
617
+ 'namespace_annotations' => {
618
+ 'workspaceId' => 'myWorkspaceName'
619
+ }
620
+ }
621
+ }
622
+ assert_equal(expected_kube_metadata, filtered[0])
623
+ end
624
+ end
625
+
626
+ test 'with kubernetes namespace annotations no match' do
627
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' },
628
+ { name: 'kubernetes_docker_metadata_annotations' },
629
+ { name: 'kubernetes_get_namespace_default' }]) do
630
+ filtered = emit({}, '
631
+ kubernetes_url https://localhost:8443
632
+ watch false
633
+ cache_size 1
634
+ annotation_match [ "noMatch*"]
635
+ ')
636
+ expected_kube_metadata = {
637
+ 'docker' => {
638
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
639
+ },
640
+ 'kubernetes' => {
641
+ 'host' => 'jimmi-redhat.localnet',
642
+ 'pod_name' => 'fabric8-console-controller-98rqc',
643
+ 'container_name' => 'fabric8-console-container',
644
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
645
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
646
+ 'namespace_name' => 'default',
647
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
648
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
649
+ 'pod_ip' => '172.17.0.8',
650
+ 'master_url' => 'https://localhost:8443',
651
+ 'labels' => {
652
+ 'component' => 'fabric8Console'
653
+ }
654
+ }
655
+ }
656
+ assert_equal(expected_kube_metadata, filtered[0])
657
+ end
658
+ end
659
+
660
+ test 'processes all events when reading from MessagePackEventStream' do
661
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' },
662
+ { name: 'kubernetes_get_api_v1' },
663
+ { name: 'kubernetes_get_pod' },
664
+ { name: 'kubernetes_get_namespace_default' }]) do
665
+ entries = [[@time, { 'time' => '2015-05-08T09:22:01Z' }], [@time, { 'time' => '2015-05-08T09:22:01Z' }]]
666
+ array_stream = Fluent::ArrayEventStream.new(entries)
667
+ msgpack_stream = Fluent::MessagePackEventStream.new(array_stream.to_msgpack_stream)
668
+
669
+ d = create_driver('
670
+ kubernetes_url https://localhost:8443
671
+ watch false
672
+ cache_size 1
673
+ stats_interval 0
674
+ ')
675
+ d.run do
676
+ d.feed(VAR_LOG_CONTAINER_TAG, msgpack_stream)
677
+ end
678
+ filtered = d.filtered.map(&:last)
679
+
680
+ expected_kube_metadata = {
681
+ 'time' => '2015-05-08T09:22:01Z',
682
+ 'docker' => {
683
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
684
+ },
685
+ 'kubernetes' => {
686
+ 'host' => 'jimmi-redhat.localnet',
687
+ 'pod_name' => 'fabric8-console-controller-98rqc',
688
+ 'container_name' => 'fabric8-console-container',
689
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
690
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
691
+ 'namespace_name' => 'default',
692
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
693
+ 'namespace_labels' => {
694
+ 'tenant' => 'test'
695
+ },
696
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
697
+ 'pod_ip' => '172.17.0.8',
698
+ 'master_url' => 'https://localhost:8443',
699
+ 'labels' => {
700
+ 'component' => 'fabric8Console'
701
+ }
702
+ }
703
+ }
704
+
705
+ assert_equal(expected_kube_metadata, filtered[0])
706
+ assert_equal(expected_kube_metadata, filtered[1])
707
+ end
708
+ end
709
+
710
+ test 'with docker & kubernetes metadata using skip config params' do
711
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' },
712
+ { name: 'kubernetes_get_namespace_default' }]) do
713
+ filtered = emit({}, '
714
+ kubernetes_url https://localhost:8443
715
+ watch false
716
+ cache_size 1
717
+ skip_labels true
718
+ skip_container_metadata true
719
+ skip_master_url true
720
+ skip_namespace_metadata true
721
+ ')
722
+ expected_kube_metadata = {
723
+ 'docker'=>{
724
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
725
+ },
726
+ 'kubernetes' => {
727
+ 'host' => 'jimmi-redhat.localnet',
728
+ 'pod_name' => 'fabric8-console-controller-98rqc',
729
+ 'container_name' => 'fabric8-console-container',
730
+ 'namespace_name' => 'default',
731
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
732
+ 'pod_ip' => '172.17.0.8'
733
+ }
734
+ }
735
+
736
+ assert_equal(expected_kube_metadata, filtered[0])
737
+ end
738
+ end
739
+
740
+ test 'with docker & kubernetes metadata using skip namespace labels config param' do
741
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' },
742
+ { name: 'kubernetes_get_namespace_default' }]) do
743
+ filtered = emit({}, '
744
+ kubernetes_url https://localhost:8443
745
+ watch false
746
+ cache_size 1
747
+ stats_interval 0
748
+ skip_namespace_labels true
749
+ skip_master_url true
750
+ ')
751
+ expected_kube_metadata = {
752
+ 'docker'=>{
753
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
754
+ },
755
+ 'kubernetes' => {
756
+ 'host' => 'jimmi-redhat.localnet',
757
+ 'pod_name' => 'fabric8-console-controller-98rqc',
758
+ 'container_name' => 'fabric8-console-container',
759
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
760
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
761
+ 'namespace_name' => 'default',
762
+ "namespace_id"=>"898268c8-4a36-11e5-9d81-42010af0194c",
763
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
764
+ 'pod_ip' => '172.17.0.8',
765
+ 'labels' => {
766
+ 'component' => 'fabric8Console'
767
+ }
768
+ }
769
+ }
770
+
771
+ assert_equal(expected_kube_metadata, filtered[0])
772
+ end
773
+ end
774
+ test 'with docker & kubernetes metadata using skip pod labels config param' do
775
+ VCR.use_cassettes([{ name: 'valid_kubernetes_api_server' }, { name: 'kubernetes_get_api_v1' }, { name: 'kubernetes_get_pod' },
776
+ { name: 'kubernetes_get_namespace_default' }]) do
777
+ filtered = emit({}, '
778
+ kubernetes_url https://localhost:8443
779
+ watch false
780
+ cache_size 1
781
+ stats_interval 0
782
+ skip_pod_labels true
783
+ skip_master_url true
784
+ ')
785
+ expected_kube_metadata = {
786
+ 'docker'=>{
787
+ 'container_id'=>'49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
788
+ },
789
+ 'kubernetes' => {
790
+ 'host' => 'jimmi-redhat.localnet',
791
+ 'pod_name' => 'fabric8-console-controller-98rqc',
792
+ 'container_name' => 'fabric8-console-container',
793
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
794
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
795
+ 'namespace_name' => 'default',
796
+ "namespace_id"=>"898268c8-4a36-11e5-9d81-42010af0194c",
797
+ 'namespace_labels' => {
798
+ 'tenant' => 'test'
799
+ },
800
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
801
+ 'pod_ip' => '172.17.0.8',
802
+ }
803
+ }
804
+
805
+ assert_equal(expected_kube_metadata, filtered[0])
806
+ end
807
+ end
808
+
809
+ end
810
+ end