fluent-plugin-kubernetes_metadata_filter_splunk 2.2.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 +56 -0
  3. data/.gitignore +20 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE.txt +201 -0
  6. data/README.md +209 -0
  7. data/Rakefile +37 -0
  8. data/fluent-plugin-kubernetes_metadata_filter.gemspec +36 -0
  9. data/lib/fluent/plugin/filter_kubernetes_metadata.rb +446 -0
  10. data/lib/fluent/plugin/kubernetes_metadata_cache_strategy.rb +98 -0
  11. data/lib/fluent/plugin/kubernetes_metadata_common.rb +113 -0
  12. data/lib/fluent/plugin/kubernetes_metadata_stats.rb +46 -0
  13. data/lib/fluent/plugin/kubernetes_metadata_watch_namespaces.rb +65 -0
  14. data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +68 -0
  15. data/test/cassettes/invalid_api_server_config.yml +53 -0
  16. data/test/cassettes/kubernetes_docker_metadata.yml +228 -0
  17. data/test/cassettes/kubernetes_docker_metadata_annotations.yml +239 -0
  18. data/test/cassettes/kubernetes_docker_metadata_dotted_labels.yml +231 -0
  19. data/test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml +248 -0
  20. data/test/cassettes/kubernetes_get_api_v1.yml +193 -0
  21. data/test/cassettes/kubernetes_get_api_v1_using_token.yml +195 -0
  22. data/test/cassettes/kubernetes_get_namespace_default.yml +69 -0
  23. data/test/cassettes/kubernetes_get_namespace_default_using_token.yml +71 -0
  24. data/test/cassettes/kubernetes_get_pod.yml +146 -0
  25. data/test/cassettes/kubernetes_get_pod_using_token.yml +148 -0
  26. data/test/cassettes/metadata_from_tag_and_journald_fields.yml +408 -0
  27. data/test/cassettes/metadata_from_tag_journald_and_kubernetes_fields.yml +540 -0
  28. data/test/cassettes/metadata_with_namespace_id.yml +276 -0
  29. data/test/cassettes/non_kubernetes_docker_metadata.yml +97 -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 +64 -0
  33. data/test/plugin/test.token +1 -0
  34. data/test/plugin/test_cache_stats.rb +36 -0
  35. data/test/plugin/test_cache_strategy.rb +196 -0
  36. data/test/plugin/test_filter_kubernetes_metadata.rb +970 -0
  37. data/test/plugin/test_watch_namespaces.rb +91 -0
  38. data/test/plugin/test_watch_pods.rb +145 -0
  39. data/test/plugin/watch_test.rb +57 -0
  40. metadata +295 -0
@@ -0,0 +1,64 @@
1
+ #
2
+ # Fluentd Kubernetes Metadata Filter Plugin - Enrich Fluentd events with
3
+ # Kubernetes metadata
4
+ #
5
+ # Copyright 2015 Red Hat, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ require 'codeclimate-test-reporter'
20
+ SimpleCov.start do
21
+ formatter SimpleCov::Formatter::MultiFormatter.new [
22
+ SimpleCov::Formatter::HTMLFormatter,
23
+ CodeClimate::TestReporter::Formatter
24
+ ]
25
+ end
26
+
27
+ require 'rr'
28
+ require 'test/unit'
29
+ require 'test/unit/rr'
30
+ require 'fileutils'
31
+ require 'fluent/log'
32
+ require 'fluent/test'
33
+ require 'minitest/autorun'
34
+ require 'webmock/test_unit'
35
+ require 'vcr'
36
+
37
+ VCR.configure do |config|
38
+ config.cassette_library_dir = 'test/cassettes'
39
+ config.hook_into :webmock # or :fakeweb
40
+ config.ignore_hosts 'codeclimate.com'
41
+ end
42
+
43
+ unless defined?(Test::Unit::AssertionFailedError)
44
+ class Test::Unit::AssertionFailedError < StandardError
45
+ end
46
+ end
47
+
48
+ def unused_port
49
+ s = TCPServer.open(0)
50
+ port = s.addr[1]
51
+ s.close
52
+ port
53
+ end
54
+
55
+ def ipv6_enabled?
56
+ require 'socket'
57
+
58
+ begin
59
+ TCPServer.open('::1', 0)
60
+ true
61
+ rescue
62
+ false
63
+ end
64
+ end
@@ -0,0 +1 @@
1
+ 12345
@@ -0,0 +1,36 @@
1
+ #
2
+ # Fluentd Kubernetes Metadata Filter Plugin - Enrich Fluentd events with
3
+ # Kubernetes metadata
4
+ #
5
+ # Copyright 2015 Red Hat, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ require_relative '../helper'
20
+ require 'fluent/plugin/kubernetes_metadata_stats'
21
+ require 'webmock/test_unit'
22
+ WebMock.disable_net_connect!
23
+
24
+ class KubernetesMetadataCacheStatsTest < Test::Unit::TestCase
25
+
26
+ test 'watch stats' do
27
+ require 'lru_redux'
28
+ stats = KubernetesMetadata::Stats.new
29
+ stats.bump(:missed)
30
+ stats.bump(:deleted)
31
+ stats.bump(:deleted)
32
+
33
+ assert_equal("stats - deleted: 2, missed: 1", stats.to_s)
34
+ end
35
+
36
+ end
@@ -0,0 +1,196 @@
1
+ #
2
+ # Fluentd Kubernetes Metadata Filter Plugin - Enrich Fluentd events with
3
+ # Kubernetes metadata
4
+ #
5
+ # Copyright 2015 Red Hat, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ require_relative '../helper'
20
+ require_relative '../../lib/fluent/plugin/kubernetes_metadata_cache_strategy'
21
+ require_relative '../../lib/fluent/plugin/kubernetes_metadata_stats'
22
+ require 'lru_redux'
23
+ require 'webmock/test_unit'
24
+ WebMock.disable_net_connect!
25
+
26
+ class TestCacheStrategy
27
+ include KubernetesMetadata::CacheStrategy
28
+
29
+ def initialize
30
+ @stats = KubernetesMetadata::Stats.new
31
+ @cache = LruRedux::TTL::ThreadSafeCache.new(100,3600)
32
+ @id_cache = LruRedux::TTL::ThreadSafeCache.new(100,3600)
33
+ @namespace_cache = LruRedux::TTL::ThreadSafeCache.new(100,3600)
34
+ @orphaned_namespace_name = '.orphaned'
35
+ @orphaned_namespace_id = 'orphaned'
36
+ end
37
+
38
+ attr_accessor :stats, :cache, :id_cache, :namespace_cache, :allow_orphans
39
+
40
+ def fetch_pod_metadata(namespace_name, pod_name)
41
+ end
42
+
43
+ def fetch_namespace_metadata(namespace_name)
44
+ end
45
+
46
+ def log
47
+ logger = {}
48
+ def logger.trace?
49
+ true
50
+ end
51
+ def logger.trace(message)
52
+ end
53
+ logger
54
+ end
55
+
56
+ end
57
+
58
+ class KubernetesMetadataCacheStrategyTest < Test::Unit::TestCase
59
+
60
+ def setup
61
+ @strategy = TestCacheStrategy.new
62
+ @cache_key = 'some_long_container_id'
63
+ @namespace_name = 'some_namespace_name'
64
+ @namespace_uuid = 'some_namespace_uuid'
65
+ @pod_name = 'some_pod_name'
66
+ @pod_uuid = 'some_pod_uuid'
67
+ @time = Time.now
68
+ @pod_meta = {'pod_id'=> @pod_uuid, 'labels'=> {'meta'=>'pod'}}
69
+ @namespace_meta = {'namespace_id'=> @namespace_uuid, 'creation_timestamp'=>@time.to_s}
70
+ end
71
+
72
+ test 'when cached metadata is found' do
73
+ exp = @pod_meta.merge(@namespace_meta)
74
+ exp.delete('creation_timestamp')
75
+ @strategy.id_cache[@cache_key] = {
76
+ pod_id: @pod_uuid,
77
+ namespace_id: @namespace_uuid
78
+ }
79
+ @strategy.cache[@pod_uuid] = @pod_meta
80
+ @strategy.namespace_cache[@namespace_uuid] = @namespace_meta
81
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, {}))
82
+ end
83
+
84
+ test 'when previously processed record for pod but metadata is not cached and can not be fetched' do
85
+ exp = {
86
+ 'pod_id'=> @pod_uuid,
87
+ 'namespace_id'=> @namespace_uuid
88
+ }
89
+ @strategy.id_cache[@cache_key] = {
90
+ pod_id: @pod_uuid,
91
+ namespace_id: @namespace_uuid
92
+ }
93
+ @strategy.stub :fetch_pod_metadata, {} do
94
+ @strategy.stub :fetch_namespace_metadata, nil do
95
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, {}))
96
+ end
97
+ end
98
+ end
99
+
100
+ test 'when metadata is not cached and is fetched' do
101
+ exp = @pod_meta.merge(@namespace_meta)
102
+ exp.delete('creation_timestamp')
103
+ @strategy.stub :fetch_pod_metadata, @pod_meta do
104
+ @strategy.stub :fetch_namespace_metadata, @namespace_meta do
105
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, {}))
106
+ assert_true(@strategy.id_cache.key?(@cache_key))
107
+ end
108
+ end
109
+ end
110
+
111
+ test 'when metadata is not cached and pod is deleted and namespace metadata is fetched' do
112
+ # this is the case for a record from a deleted pod where no other
113
+ # records were read. using the container hash since that is all
114
+ # we ever will have and should allow us to process all the deleted
115
+ # pod records
116
+ exp = {
117
+ 'pod_id'=> @cache_key,
118
+ 'namespace_id'=> @namespace_uuid
119
+ }
120
+ @strategy.stub :fetch_pod_metadata, {} do
121
+ @strategy.stub :fetch_namespace_metadata, @namespace_meta do
122
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, {}))
123
+ assert_true(@strategy.id_cache.key?(@cache_key))
124
+ end
125
+ end
126
+ end
127
+
128
+ test 'when metadata is not cached and pod is deleted and namespace is for a different namespace with the same name' do
129
+ # this is the case for a record from a deleted pod from a deleted namespace
130
+ # where new namespace was created with the same name
131
+ exp = {
132
+ 'namespace_id'=> @namespace_uuid
133
+ }
134
+ @strategy.stub :fetch_pod_metadata, {} do
135
+ @strategy.stub :fetch_namespace_metadata, @namespace_meta do
136
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time - 1*86400, {}))
137
+ assert_true(@strategy.id_cache.key?(@cache_key))
138
+ end
139
+ end
140
+ end
141
+
142
+ test 'when metadata is not cached and no metadata can be fetched and not allowing orphans' do
143
+ # we should never see this since pod meta should not be retrievable
144
+ # unless the namespace exists
145
+ @strategy.stub :fetch_pod_metadata, @pod_meta do
146
+ @strategy.stub :fetch_namespace_metadata, {} do
147
+ assert_equal({}, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time - 1*86400, {}))
148
+ end
149
+ end
150
+ end
151
+
152
+ test 'when metadata is not cached and no metadata can be fetched and allowing orphans' do
153
+ # we should never see this since pod meta should not be retrievable
154
+ # unless the namespace exists
155
+ @strategy.allow_orphans = true
156
+ exp = {
157
+ 'orphaned_namespace' => 'namespace',
158
+ 'namespace_name' => '.orphaned',
159
+ 'namespace_id' => 'orphaned'
160
+ }
161
+ @strategy.stub :fetch_pod_metadata, @pod_meta do
162
+ @strategy.stub :fetch_namespace_metadata, {} do
163
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time - 1*86400, {}))
164
+ end
165
+ end
166
+ end
167
+
168
+ test 'when metadata is not cached and no metadata can be fetched and not allowing orphans for multiple records' do
169
+ # processing a batch of records with no meta. ideally we only hit the api server once
170
+ batch_miss_cache = {}
171
+ @strategy.stub :fetch_pod_metadata, {} do
172
+ @strategy.stub :fetch_namespace_metadata, {} do
173
+ assert_equal({}, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, batch_miss_cache))
174
+ end
175
+ end
176
+ assert_equal({}, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, batch_miss_cache))
177
+ end
178
+
179
+ test 'when metadata is not cached and no metadata can be fetched and allowing orphans for multiple records' do
180
+ # we should never see this since pod meta should not be retrievable
181
+ # unless the namespace exists
182
+ @strategy.allow_orphans = true
183
+ exp = {
184
+ 'orphaned_namespace' => 'namespace',
185
+ 'namespace_name' => '.orphaned',
186
+ 'namespace_id' => 'orphaned'
187
+ }
188
+ batch_miss_cache = {}
189
+ @strategy.stub :fetch_pod_metadata, {} do
190
+ @strategy.stub :fetch_namespace_metadata, {} do
191
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, batch_miss_cache))
192
+ end
193
+ end
194
+ assert_equal(exp, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, batch_miss_cache))
195
+ end
196
+ end
@@ -0,0 +1,970 @@
1
+ #
2
+ # Fluentd Kubernetes Metadata Filter Plugin - Enrich Fluentd events with
3
+ # Kubernetes metadata
4
+ #
5
+ # Copyright 2015 Red Hat, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ require_relative '../helper'
20
+ require 'fluent/test/driver/filter'
21
+ require 'fluent/plugin/filter_kubernetes_metadata'
22
+
23
+ require 'webmock/test_unit'
24
+ WebMock.disable_net_connect!
25
+
26
+ class KubernetesMetadataFilterTest < Test::Unit::TestCase
27
+ include Fluent
28
+
29
+ setup do
30
+ Fluent::Test.setup
31
+ @time = Fluent::Engine.now
32
+ end
33
+
34
+ DEFAULT_TAG = 'var.log.containers.fabric8-console-controller-98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log'
35
+
36
+ def create_driver(conf = '')
37
+ Test::Driver::Filter.new(Plugin::KubernetesMetadataFilter).configure(conf)
38
+ end
39
+
40
+ sub_test_case 'configure' do
41
+ test 'check default' do
42
+ d = create_driver
43
+ assert_equal(1000, d.instance.cache_size)
44
+ end
45
+
46
+ test 'kubernetes url' do
47
+ VCR.use_cassette('valid_kubernetes_api_server') do
48
+ d = create_driver('
49
+ kubernetes_url https://localhost:8443
50
+ watch false
51
+ ')
52
+ assert_equal('https://localhost:8443', d.instance.kubernetes_url)
53
+ assert_equal(1000, d.instance.cache_size)
54
+ end
55
+ end
56
+
57
+ test 'cache size' do
58
+ VCR.use_cassette('valid_kubernetes_api_server') do
59
+ d = create_driver('
60
+ kubernetes_url https://localhost:8443
61
+ watch false
62
+ cache_size 1
63
+ ')
64
+ assert_equal('https://localhost:8443', d.instance.kubernetes_url)
65
+ assert_equal(1, d.instance.cache_size)
66
+ end
67
+ end
68
+
69
+ test 'invalid API server config' do
70
+ VCR.use_cassette('invalid_api_server_config') do
71
+ assert_raise Fluent::ConfigError do
72
+ create_driver('
73
+ kubernetes_url https://localhost:8443
74
+ bearer_token_file test/plugin/test.token
75
+ watch false
76
+ verify_ssl false
77
+ ')
78
+ end
79
+ end
80
+ end
81
+
82
+ test 'service account credentials' do
83
+ VCR.use_cassette('valid_kubernetes_api_server') do
84
+ begin
85
+ ENV['KUBERNETES_SERVICE_HOST'] = 'localhost'
86
+ ENV['KUBERNETES_SERVICE_PORT'] = '8443'
87
+
88
+ Dir.mktmpdir { |dir|
89
+ # Fake token file and CA crt.
90
+ expected_cert_path = File.join(dir, Plugin::KubernetesMetadataFilter::K8_POD_CA_CERT)
91
+ expected_token_path = File.join(dir, Plugin::KubernetesMetadataFilter::K8_POD_TOKEN)
92
+
93
+ File.open(expected_cert_path, "w") {}
94
+ File.open(expected_token_path, "w") {}
95
+
96
+ d = create_driver("
97
+ watch false
98
+ secret_dir #{dir}
99
+ ")
100
+
101
+ assert_equal(d.instance.kubernetes_url, "https://localhost:8443/api")
102
+ assert_equal(d.instance.ca_file, expected_cert_path)
103
+ assert_equal(d.instance.bearer_token_file, expected_token_path)
104
+ }
105
+ ensure
106
+ ENV['KUBERNETES_SERVICE_HOST'] = nil
107
+ ENV['KUBERNETES_SERVICE_PORT'] = nil
108
+ end
109
+ end
110
+ end
111
+
112
+ test 'service account credential files are tested for existence' do
113
+ VCR.use_cassette('valid_kubernetes_api_server') do
114
+ begin
115
+ ENV['KUBERNETES_SERVICE_HOST'] = 'localhost'
116
+ ENV['KUBERNETES_SERVICE_PORT'] = '8443'
117
+
118
+ Dir.mktmpdir { |dir|
119
+ d = create_driver("
120
+ watch false
121
+ secret_dir #{dir}
122
+ ")
123
+ assert_equal(d.instance.kubernetes_url, "https://localhost:8443/api")
124
+ assert_false(d.instance.ca_file.present?)
125
+ assert_false(d.instance.bearer_token_file.present?)
126
+ }
127
+ ensure
128
+ ENV['KUBERNETES_SERVICE_HOST'] = nil
129
+ ENV['KUBERNETES_SERVICE_PORT'] = nil
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ sub_test_case 'filter_stream' do
136
+
137
+ def emit(msg={}, config='
138
+ kubernetes_url https://localhost:8443
139
+ watch false
140
+ cache_size 1
141
+ ', d: nil)
142
+ d = create_driver(config) if d.nil?
143
+ d.run(default_tag: DEFAULT_TAG) {
144
+ d.feed(@time, msg)
145
+ }
146
+ d.filtered.map{|e| e.last}
147
+ end
148
+
149
+ def emit_with_tag(tag, msg={}, config='
150
+ kubernetes_url https://localhost:8443
151
+ watch false
152
+ cache_size 1
153
+ ')
154
+ d = create_driver(config)
155
+ d.run(default_tag: tag) {
156
+ d.feed(@time, msg)
157
+ }
158
+ d.filtered.map{|e| e.last}
159
+ end
160
+
161
+ test 'nil event stream' do
162
+ #not certain how this is possible but adding test to properly
163
+ #guard against this condition we have seen - test for nil,
164
+ #empty, no empty method, not an event stream
165
+ plugin = create_driver.instance
166
+ plugin.filter_stream('tag', nil)
167
+ plugin.filter_stream('tag', Fluent::MultiEventStream.new)
168
+ end
169
+
170
+ test 'inability to connect to the api server handles exception and doensnt block pipeline' do
171
+ VCR.use_cassette('kubernetes_docker_metadata') do
172
+ driver = create_driver('
173
+ kubernetes_url https://localhost:8443
174
+ watch false
175
+ cache_size 1
176
+ ')
177
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc').to_raise(SocketError.new('error from pod fetch'))
178
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default').to_raise(SocketError.new('socket error from namespace fetch'))
179
+ filtered = emit({'time'=>'2015-05-08T09:22:01Z'}, '', :d => driver)
180
+ expected_kube_metadata = {
181
+ 'time'=>'2015-05-08T09:22:01Z',
182
+ 'docker' => {
183
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
184
+ },
185
+ 'kubernetes' => {
186
+ 'pod_name' => 'fabric8-console-controller-98rqc',
187
+ 'container_name' => 'fabric8-console-container',
188
+ "namespace_id"=>"orphaned",
189
+ 'namespace_name' => '.orphaned',
190
+ "orphaned_namespace"=>"default"
191
+ }
192
+ }
193
+ assert_equal(expected_kube_metadata, filtered[0])
194
+ end
195
+ end
196
+
197
+ test 'with docker & kubernetes metadata where id cache hit and metadata miss' do
198
+ VCR.use_cassette('kubernetes_docker_metadata') do
199
+ driver = create_driver('
200
+ kubernetes_url https://localhost:8443
201
+ watch false
202
+ cache_size 1
203
+ ')
204
+ cache = driver.instance.instance_variable_get(:@id_cache)
205
+ cache['49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'] = {
206
+ :pod_id =>'c76927af-f563-11e4-b32d-54ee7527188d',
207
+ :namespace_id =>'898268c8-4a36-11e5-9d81-42010af0194c'
208
+ }
209
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc').to_timeout
210
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default').to_timeout
211
+ filtered = emit({'time'=>'2015-05-08T09:22:01Z'}, '', d:driver)
212
+ expected_kube_metadata = {
213
+ 'time'=>'2015-05-08T09:22:01Z',
214
+ 'docker' => {
215
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
216
+ },
217
+ 'kubernetes' => {
218
+ 'pod_name' => 'fabric8-console-controller-98rqc',
219
+ 'container_name' => 'fabric8-console-container',
220
+ 'namespace_name' => 'default',
221
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
222
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
223
+ }
224
+ }
225
+
226
+ assert_equal(expected_kube_metadata, filtered[0])
227
+ end
228
+ end
229
+
230
+ test 'with docker & kubernetes metadata where id cache hit and metadata is reloaded' do
231
+ VCR.use_cassette('kubernetes_docker_metadata') do
232
+ driver = create_driver('
233
+ kubernetes_url https://localhost:8443
234
+ watch false
235
+ cache_size 1
236
+ ')
237
+ cache = driver.instance.instance_variable_get(:@id_cache)
238
+ cache['49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'] = {
239
+ :pod_id =>'c76927af-f563-11e4-b32d-54ee7527188d',
240
+ :namespace_id =>'898268c8-4a36-11e5-9d81-42010af0194c'
241
+ }
242
+ filtered = emit({'time'=>'2015-05-08T09:22:01Z'}, '', d:driver)
243
+ expected_kube_metadata = {
244
+ 'time'=>'2015-05-08T09:22:01Z',
245
+ 'docker' => {
246
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
247
+ },
248
+ 'kubernetes' => {
249
+ 'host' => 'jimmi-redhat.localnet',
250
+ 'pod_name' => 'fabric8-console-controller-98rqc',
251
+ 'container_name' => 'fabric8-console-container',
252
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
253
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
254
+ 'namespace_name' => 'default',
255
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
256
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
257
+ 'master_url' => 'https://localhost:8443',
258
+ 'labels' => {
259
+ 'component' => 'fabric8Console'
260
+ }
261
+ }
262
+ }
263
+
264
+ assert_equal(expected_kube_metadata, filtered[0])
265
+ end
266
+ end
267
+
268
+ test 'with docker & kubernetes metadata' do
269
+ VCR.use_cassette('kubernetes_docker_metadata') do
270
+ filtered = emit({'time'=>'2015-05-08T09:22:01Z'})
271
+ expected_kube_metadata = {
272
+ 'time'=>'2015-05-08T09:22:01Z',
273
+ 'docker' => {
274
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
275
+ },
276
+ 'kubernetes' => {
277
+ 'host' => 'jimmi-redhat.localnet',
278
+ 'pod_name' => 'fabric8-console-controller-98rqc',
279
+ 'container_name' => 'fabric8-console-container',
280
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
281
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
282
+ 'namespace_name' => 'default',
283
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
284
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
285
+ 'master_url' => 'https://localhost:8443',
286
+ 'labels' => {
287
+ 'component' => 'fabric8Console'
288
+ }
289
+ }
290
+ }
291
+
292
+ assert_equal(expected_kube_metadata, filtered[0])
293
+ end
294
+ end
295
+
296
+ test 'with docker & kubernetes metadata & namespace_id enabled' do
297
+ VCR.use_cassette('metadata_with_namespace_id') do
298
+ filtered = emit({}, '
299
+ kubernetes_url https://localhost:8443
300
+ watch false
301
+ cache_size 1
302
+ ')
303
+ expected_kube_metadata = {
304
+ 'docker' => {
305
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
306
+ },
307
+ 'kubernetes' => {
308
+ 'host' => 'jimmi-redhat.localnet',
309
+ 'pod_name' => 'fabric8-console-controller-98rqc',
310
+ 'container_name' => 'fabric8-console-container',
311
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
312
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
313
+ 'namespace_name' => 'default',
314
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
315
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
316
+ 'master_url' => 'https://localhost:8443',
317
+ 'labels' => {
318
+ 'component' => 'fabric8Console'
319
+ }
320
+ }
321
+ }
322
+ assert_equal(expected_kube_metadata, filtered[0])
323
+ end
324
+ end
325
+
326
+ test 'with docker & kubernetes metadata using bearer token' do
327
+ VCR.use_cassette('kubernetes_docker_metadata_using_bearer_token') do
328
+ filtered = emit({}, '
329
+ kubernetes_url https://localhost:8443
330
+ verify_ssl false
331
+ watch false
332
+ bearer_token_file test/plugin/test.token
333
+ ')
334
+ expected_kube_metadata = {
335
+ 'docker' => {
336
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
337
+ },
338
+ 'kubernetes' => {
339
+ 'host' => 'jimmi-redhat.localnet',
340
+ 'pod_name' => 'fabric8-console-controller-98rqc',
341
+ 'container_name' => 'fabric8-console-container',
342
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
343
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
344
+ 'namespace_name' => 'default',
345
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
346
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
347
+ 'master_url' => 'https://localhost:8443',
348
+ 'labels' => {
349
+ 'component' => 'fabric8Console'
350
+ }
351
+ }
352
+ }
353
+ assert_equal(expected_kube_metadata, filtered[0])
354
+ end
355
+ end
356
+
357
+ test 'with docker & kubernetes metadata but no configured api server' do
358
+ filtered = emit({}, '')
359
+ expected_kube_metadata = {
360
+ 'docker' => {
361
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
362
+ },
363
+ 'kubernetes' => {
364
+ 'pod_name' => 'fabric8-console-controller-98rqc',
365
+ 'container_name' => 'fabric8-console-container',
366
+ 'namespace_name' => 'default',
367
+ }
368
+ }
369
+ assert_equal(expected_kube_metadata, filtered[0])
370
+ end
371
+
372
+ test 'with docker & inaccessible kubernetes metadata' do
373
+ stub_request(:any, 'https://localhost:8443/api').to_return(
374
+ 'body' => {
375
+ 'versions' => ['v1beta3', 'v1']
376
+ }.to_json
377
+ )
378
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc').to_timeout
379
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default').to_timeout
380
+ filtered = emit()
381
+ expected_kube_metadata = {
382
+ 'docker' => {
383
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
384
+ },
385
+ 'kubernetes' => {
386
+ 'pod_name' => 'fabric8-console-controller-98rqc',
387
+ 'container_name' => 'fabric8-console-container',
388
+ 'namespace_name' => '.orphaned',
389
+ 'orphaned_namespace' => 'default',
390
+ 'namespace_id' => 'orphaned'
391
+ }
392
+ }
393
+ assert_equal(expected_kube_metadata, filtered[0])
394
+ end
395
+
396
+ test 'with dot in pod name' do
397
+ stub_request(:any, 'https://localhost:8443/api').to_return(
398
+ 'body' => {
399
+ 'versions' => ['v1beta3', 'v1']
400
+ }.to_json
401
+ )
402
+ stub_request(:any, 'https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller.98rqc').to_timeout
403
+ filtered = emit_with_tag('var.log.containers.fabric8-console-controller.98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log', {}, '')
404
+ expected_kube_metadata = {
405
+ 'docker' => {
406
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
407
+ },
408
+ 'kubernetes' => {
409
+ 'pod_name' => 'fabric8-console-controller.98rqc',
410
+ 'container_name' => 'fabric8-console-container',
411
+ 'namespace_name' => 'default'
412
+ }
413
+ }
414
+ assert_equal(expected_kube_metadata, filtered[0])
415
+ end
416
+
417
+ test 'with docker metadata, non-kubernetes' do
418
+ filtered = emit_with_tag('non-kubernetes', {}, '')
419
+ assert_false(filtered[0].has_key?(:kubernetes))
420
+ end
421
+
422
+ test 'ignores invalid json in log field' do
423
+ json_log = "{'foo':123}"
424
+ msg = {
425
+ 'log' => json_log
426
+ }
427
+ filtered = emit_with_tag('non-kubernetes', msg, '')
428
+ assert_equal(msg, filtered[0])
429
+ end
430
+
431
+ test 'with kubernetes dotted labels, de_dot enabled' do
432
+ VCR.use_cassette('kubernetes_docker_metadata_dotted_labels') do
433
+ filtered = emit({}, '
434
+ kubernetes_url https://localhost:8443
435
+ watch false
436
+ cache_size 1
437
+ ')
438
+ expected_kube_metadata = {
439
+ 'docker' => {
440
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
441
+ },
442
+ 'kubernetes' => {
443
+ 'host' => 'jimmi-redhat.localnet',
444
+ 'pod_name' => 'fabric8-console-controller-98rqc',
445
+ 'container_name' => 'fabric8-console-container',
446
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
447
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
448
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
449
+ 'namespace_labels' => {
450
+ 'kubernetes_io/namespacetest' => 'somevalue'
451
+ },
452
+ 'namespace_name' => 'default',
453
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
454
+ 'master_url' => 'https://localhost:8443',
455
+ 'labels' => {
456
+ 'kubernetes_io/test' => 'somevalue'
457
+ }
458
+ }
459
+ }
460
+ assert_equal(expected_kube_metadata, filtered[0])
461
+ end
462
+ end
463
+
464
+ test 'with kubernetes dotted labels, de_dot disabled' do
465
+ VCR.use_cassette('kubernetes_docker_metadata_dotted_labels') do
466
+ filtered = emit({}, '
467
+ kubernetes_url https://localhost:8443
468
+ watch false
469
+ cache_size 1
470
+ de_dot false
471
+ ')
472
+ expected_kube_metadata = {
473
+ 'docker' => {
474
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
475
+ },
476
+ 'kubernetes' => {
477
+ 'host' => 'jimmi-redhat.localnet',
478
+ 'pod_name' => 'fabric8-console-controller-98rqc',
479
+ 'container_name' => 'fabric8-console-container',
480
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
481
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
482
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
483
+ 'namespace_labels' => {
484
+ 'kubernetes.io/namespacetest' => 'somevalue'
485
+ },
486
+ 'namespace_name' => 'default',
487
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
488
+ 'master_url' => 'https://localhost:8443',
489
+ 'labels' => {
490
+ 'kubernetes.io/test' => 'somevalue'
491
+ }
492
+ }
493
+ }
494
+ assert_equal(expected_kube_metadata, filtered[0])
495
+ end
496
+ end
497
+
498
+ test 'invalid de_dot_separator config' do
499
+ assert_raise Fluent::ConfigError do
500
+ create_driver('
501
+ de_dot_separator contains.
502
+ ')
503
+ end
504
+ end
505
+
506
+ test 'with records from journald and docker & kubernetes metadata' do
507
+ # with use_journal true should ignore tags and use CONTAINER_NAME and CONTAINER_ID_FULL
508
+ tag = 'var.log.containers.junk1_junk2_junk3-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
509
+ msg = {
510
+ 'CONTAINER_NAME' => 'k8s_fabric8-console-container.db89db89_fabric8-console-controller-98rqc_default_c76927af-f563-11e4-b32d-54ee7527188d_89db89db',
511
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
512
+ 'randomfield' => 'randomvalue'
513
+ }
514
+ VCR.use_cassette('kubernetes_docker_metadata') do
515
+ filtered = emit_with_tag(tag, msg, '
516
+ kubernetes_url https://localhost:8443
517
+ watch false
518
+ cache_size 1
519
+ use_journal true
520
+ ')
521
+ expected_kube_metadata = {
522
+ 'docker' => {
523
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
524
+ },
525
+ 'kubernetes' => {
526
+ 'host' => 'jimmi-redhat.localnet',
527
+ 'pod_name' => 'fabric8-console-controller-98rqc',
528
+ 'container_name' => 'fabric8-console-container',
529
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
530
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
531
+ 'namespace_name' => 'default',
532
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
533
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
534
+ 'master_url' => 'https://localhost:8443',
535
+ 'labels' => {
536
+ 'component' => 'fabric8Console'
537
+ }
538
+ }
539
+ }.merge(msg)
540
+ assert_equal(expected_kube_metadata, filtered[0])
541
+ end
542
+ end
543
+
544
+ test 'with records from journald and docker & kubernetes metadata & namespace_id enabled' do
545
+ # with use_journal true should ignore tags and use CONTAINER_NAME and CONTAINER_ID_FULL
546
+ tag = 'var.log.containers.junk1_junk2_junk3-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
547
+ msg = {
548
+ 'CONTAINER_NAME' => 'k8s_fabric8-console-container.db89db89_fabric8-console-controller-98rqc_default_c76927af-f563-11e4-b32d-54ee7527188d_89db89db',
549
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
550
+ 'randomfield' => 'randomvalue'
551
+ }
552
+ VCR.use_cassette('metadata_with_namespace_id') do
553
+ filtered = emit_with_tag(tag, msg, '
554
+ kubernetes_url https://localhost:8443
555
+ watch false
556
+ cache_size 1
557
+ use_journal true
558
+ ')
559
+ expected_kube_metadata = {
560
+ 'docker' => {
561
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
562
+ },
563
+ 'kubernetes' => {
564
+ 'host' => 'jimmi-redhat.localnet',
565
+ 'pod_name' => 'fabric8-console-controller-98rqc',
566
+ 'container_name' => 'fabric8-console-container',
567
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
568
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
569
+ 'namespace_name' => 'default',
570
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
571
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
572
+ 'master_url' => 'https://localhost:8443',
573
+ 'labels' => {
574
+ 'component' => 'fabric8Console'
575
+ }
576
+ }
577
+ }.merge(msg)
578
+ assert_equal(expected_kube_metadata, filtered[0])
579
+ end
580
+ end
581
+
582
+ test 'with records from journald and docker & kubernetes metadata with use_journal unset' do
583
+ # with use_journal unset, should still use the journal fields instead of tag fields
584
+ tag = 'var.log.containers.fabric8-console-controller-98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log'
585
+ msg = {
586
+ 'CONTAINER_NAME' => 'k8s_journald-container-name.db89db89_journald-pod-name_journald-namespace-name_c76927af-f563-11e4-b32d-54ee7527188d_89db89db',
587
+ 'CONTAINER_ID_FULL' => '838350c64bacba968d39a30a50789b2795291fceca6ccbff55298671d46b0e3b',
588
+ 'kubernetes' => {
589
+ 'namespace_name' => 'k8s-namespace-name',
590
+ 'pod_name' => 'k8s-pod-name',
591
+ 'container_name' => 'k8s-container-name'
592
+ },
593
+ 'docker' => {'container_id' => 'e463bc0d3ae38f5c89d92dca49b30e049e899799920b79d4d5f705acbe82ba95'},
594
+ 'randomfield' => 'randomvalue'
595
+ }
596
+ VCR.use_cassette('metadata_from_tag_journald_and_kubernetes_fields') do
597
+ es = emit_with_tag(tag, msg, '
598
+ kubernetes_url https://localhost:8443
599
+ watch false
600
+ cache_size 1
601
+ ')
602
+ expected_kube_metadata = {
603
+ 'docker' => {
604
+ 'container_id' => 'e463bc0d3ae38f5c89d92dca49b30e049e899799920b79d4d5f705acbe82ba95'
605
+ },
606
+ 'kubernetes' => {
607
+ 'host' => 'jimmi-redhat.localnet',
608
+ 'pod_name' => 'k8s-pod-name',
609
+ 'container_name' => 'k8s-container-name',
610
+ 'container_image' => 'k8s-container-image:latest',
611
+ 'container_image_id' => 'docker://d78c5217c41e9af08d37d9ae2cb070afa1fe3da6bc77bfb18879a8b4bfdf8a34',
612
+ 'namespace_name' => 'k8s-namespace-name',
613
+ 'namespace_id' => '8e0dc8fc-59f2-49f7-a3e2-ed0913e19d9f',
614
+ 'pod_id' => 'ebabf749-5fcd-4750-a3f0-aedd89476da8',
615
+ 'master_url' => 'https://localhost:8443',
616
+ 'labels' => {
617
+ 'component' => 'k8s-test'
618
+ }
619
+ }
620
+ }.merge(msg) {|key,oldval,newval| ((key == 'kubernetes') || (key == 'docker')) ? oldval : newval}
621
+ assert_equal(expected_kube_metadata, es[0])
622
+ end
623
+ end
624
+
625
+ test 'with records from journald and docker & kubernetes metadata with lookup_from_k8s_field false' do
626
+ # with use_journal unset, should still use the journal fields instead of tag fields
627
+ tag = 'var.log.containers.fabric8-console-controller-98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log'
628
+ msg = {
629
+ 'CONTAINER_NAME' => 'k8s_journald-container-name.db89db89_journald-pod-name_journald-namespace-name_c76927af-f563-11e4-b32d-54ee7527188d_89db89db',
630
+ 'CONTAINER_ID_FULL' => '838350c64bacba968d39a30a50789b2795291fceca6ccbff55298671d46b0e3b',
631
+ 'kubernetes' => {
632
+ 'namespace_name' => 'k8s-namespace-name',
633
+ 'pod_name' => 'k8s-pod-name',
634
+ 'container_name' => 'k8s-container-name'
635
+ },
636
+ 'docker' => {'container_id' => 'e463bc0d3ae38f5c89d92dca49b30e049e899799920b79d4d5f705acbe82ba95'},
637
+ 'randomfield' => 'randomvalue'
638
+ }
639
+ VCR.use_cassette('metadata_from_tag_and_journald_fields') do
640
+ es = emit_with_tag(tag, msg, '
641
+ kubernetes_url https://localhost:8443
642
+ watch false
643
+ cache_size 1
644
+ lookup_from_k8s_field false
645
+ ')
646
+ expected_kube_metadata = {
647
+ 'docker' => {
648
+ 'container_id' => '838350c64bacba968d39a30a50789b2795291fceca6ccbff55298671d46b0e3b'
649
+ },
650
+ 'kubernetes' => {
651
+ 'host' => 'jimmi-redhat.localnet',
652
+ 'pod_name' => 'journald-pod-name',
653
+ 'container_name' => 'journald-container-name',
654
+ 'container_image' => 'journald-container-image:latest',
655
+ 'container_image_id' => 'docker://dda4c95705fb7050b701b10a7fe928ca5bc971a1dcb521ae3c339194cbf36b47',
656
+ 'namespace_name' => 'journald-namespace-name',
657
+ 'namespace_id' => '8282888f-733f-4f23-a3d3-1fdfa3bdacf2',
658
+ 'pod_id' => '5e1c1e27-b637-4e81-80b6-6d8a8c404d3b',
659
+ 'master_url' => 'https://localhost:8443',
660
+ 'labels' => {
661
+ 'component' => 'journald-test'
662
+ }
663
+ }
664
+ }.merge(msg) {|key,oldval,newval| ((key == 'kubernetes') || (key == 'docker')) ? oldval : newval}
665
+ assert_equal(expected_kube_metadata, es[0])
666
+ end
667
+ end
668
+
669
+ test 'uses metadata from tag if use_journal false and lookup_from_k8s_field false' do
670
+ # with use_journal unset, should still use the journal fields instead of tag fields
671
+ tag = 'var.log.containers.fabric8-console-controller-98rqc_default_fabric8-console-container-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459.log'
672
+ msg = {
673
+ 'CONTAINER_NAME' => 'k8s_journald-container-name.db89db89_journald-pod-name_journald-namespace-name_c76927af-f563-11e4-b32d-54ee7527188d_89db89db',
674
+ 'CONTAINER_ID_FULL' => '838350c64bacba968d39a30a50789b2795291fceca6ccbff55298671d46b0e3b',
675
+ 'kubernetes' => {
676
+ 'namespace_name' => 'k8s-namespace-name',
677
+ 'pod_name' => 'k8s-pod-name',
678
+ 'container_name' => 'k8s-container-name'
679
+ },
680
+ 'docker' => {'container_id' => 'e463bc0d3ae38f5c89d92dca49b30e049e899799920b79d4d5f705acbe82ba95'},
681
+ 'randomfield' => 'randomvalue'
682
+ }
683
+ VCR.use_cassette('metadata_from_tag_and_journald_fields') do
684
+ es = emit_with_tag(tag, msg, '
685
+ kubernetes_url https://localhost:8443
686
+ watch false
687
+ cache_size 1
688
+ lookup_from_k8s_field false
689
+ use_journal false
690
+ ')
691
+ expected_kube_metadata = {
692
+ 'docker' => {
693
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
694
+ },
695
+ 'kubernetes' => {
696
+ 'host' => 'jimmi-redhat.localnet',
697
+ 'pod_name' => 'fabric8-console-controller-98rqc',
698
+ 'container_name' => 'fabric8-console-container',
699
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
700
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
701
+ 'namespace_name' => 'default',
702
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
703
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
704
+ 'master_url' => 'https://localhost:8443',
705
+ 'labels' => {
706
+ 'component' => 'fabric8Console'
707
+ }
708
+ }
709
+ }.merge(msg) {|key,oldval,newval| ((key == 'kubernetes') || (key == 'docker')) ? oldval : newval}
710
+ assert_equal(expected_kube_metadata, es[0])
711
+ end
712
+ end
713
+
714
+ test 'with kubernetes annotations' do
715
+ VCR.use_cassette('kubernetes_docker_metadata_annotations') do
716
+ filtered = emit({},'
717
+ kubernetes_url https://localhost:8443
718
+ watch false
719
+ cache_size 1
720
+ annotation_match [ "^custom.+", "two"]
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
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
731
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
732
+ 'namespace_name' => 'default',
733
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
734
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
735
+ 'master_url' => 'https://localhost:8443',
736
+ 'labels' => {
737
+ 'component' => 'fabric8Console'
738
+ },
739
+ 'annotations' => {
740
+ 'custom_field1' => 'hello_kitty',
741
+ 'field_two' => 'value'
742
+ }
743
+ }
744
+ }
745
+ assert_equal(expected_kube_metadata, filtered[0])
746
+ end
747
+ end
748
+
749
+ test 'with records from journald and docker & kubernetes metadata, alternate form' do
750
+ # with use_journal true should ignore tags and use CONTAINER_NAME and CONTAINER_ID_FULL
751
+ tag = 'var.log.containers.junk1_junk2_junk3-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
752
+ msg = {
753
+ 'CONTAINER_NAME' => 'alt_fabric8-console-container_fabric8-console-controller-98rqc_default_c76927af-f563-11e4-b32d-54ee7527188d_0',
754
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
755
+ 'randomfield' => 'randomvalue'
756
+ }
757
+ VCR.use_cassette('kubernetes_docker_metadata') do
758
+ filtered = emit_with_tag(tag, msg, '
759
+ kubernetes_url https://localhost:8443
760
+ watch false
761
+ cache_size 1
762
+ use_journal true
763
+ ')
764
+ expected_kube_metadata = {
765
+ 'docker' => {
766
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
767
+ },
768
+ 'kubernetes' => {
769
+ 'host' => 'jimmi-redhat.localnet',
770
+ 'pod_name' => 'fabric8-console-controller-98rqc',
771
+ 'container_name' => 'fabric8-console-container',
772
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
773
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
774
+ 'namespace_name' => 'default',
775
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
776
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
777
+ 'master_url' => 'https://localhost:8443',
778
+ 'labels' => {
779
+ 'component' => 'fabric8Console'
780
+ }
781
+ }
782
+ }.merge(msg)
783
+ assert_equal(expected_kube_metadata, filtered[0])
784
+ end
785
+ end
786
+
787
+ test 'with kubernetes namespace annotations' do
788
+ VCR.use_cassette('kubernetes_docker_metadata_annotations') do
789
+ filtered = emit({},'
790
+ kubernetes_url https://localhost:8443
791
+ watch false
792
+ cache_size 1
793
+ annotation_match [ "^custom.+", "two", "workspace*"]
794
+ ')
795
+ expected_kube_metadata = {
796
+ 'docker' => {
797
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
798
+ },
799
+ 'kubernetes' => {
800
+ 'host' => 'jimmi-redhat.localnet',
801
+ 'pod_name' => 'fabric8-console-controller-98rqc',
802
+ 'container_name' => 'fabric8-console-container',
803
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
804
+ 'namespace_name' => 'default',
805
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
806
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
807
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
808
+ 'master_url' => 'https://localhost:8443',
809
+ 'labels' => {
810
+ 'component' => 'fabric8Console'
811
+ },
812
+ 'annotations' => {
813
+ 'custom_field1' => 'hello_kitty',
814
+ 'field_two' => 'value'
815
+ },
816
+ 'namespace_annotations' => {
817
+ 'workspaceId' => 'myWorkspaceName'
818
+ }
819
+ }
820
+ }
821
+ assert_equal(expected_kube_metadata, filtered[0])
822
+ end
823
+ end
824
+
825
+ test 'with kubernetes namespace annotations no match' do
826
+ VCR.use_cassette('kubernetes_docker_metadata_annotations') do
827
+ filtered = emit({},'
828
+ kubernetes_url https://localhost:8443
829
+ watch false
830
+ cache_size 1
831
+ annotation_match [ "noMatch*"]
832
+ ')
833
+ expected_kube_metadata = {
834
+ 'docker' => {
835
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
836
+ },
837
+ 'kubernetes' => {
838
+ 'host' => 'jimmi-redhat.localnet',
839
+ 'pod_name' => 'fabric8-console-controller-98rqc',
840
+ 'container_name' => 'fabric8-console-container',
841
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
842
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
843
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
844
+ 'namespace_name' => 'default',
845
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
846
+ 'master_url' => 'https://localhost:8443',
847
+ 'labels' => {
848
+ 'component' => 'fabric8Console'
849
+ }
850
+ }
851
+ }
852
+ assert_equal(expected_kube_metadata, filtered[0])
853
+ end
854
+ end
855
+ test 'with CONTAINER_NAME that does not match' do
856
+ tag = 'var.log.containers.junk4_junk5_junk6-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
857
+ msg = {
858
+ 'CONTAINER_NAME' => 'does_not_match',
859
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
860
+ 'randomfield' => 'randomvalue'
861
+ }
862
+ VCR.use_cassette('kubernetes_docker_metadata_annotations') do
863
+ filtered = emit_with_tag(tag, msg, '
864
+ kubernetes_url https://localhost:8443
865
+ watch false
866
+ cache_size 1
867
+ use_journal true
868
+ ')
869
+ expected_kube_metadata = {
870
+ 'CONTAINER_NAME' => 'does_not_match',
871
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
872
+ 'randomfield' => 'randomvalue'
873
+ }
874
+ assert_equal(expected_kube_metadata, filtered[0])
875
+ end
876
+ end
877
+ test 'with CONTAINER_NAME starts with k8s_ that does not match' do
878
+ tag = 'var.log.containers.junk4_junk5_junk6-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
879
+ msg = {
880
+ 'CONTAINER_NAME' => 'k8s_doesnotmatch',
881
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
882
+ 'randomfield' => 'randomvalue'
883
+ }
884
+ VCR.use_cassette('kubernetes_docker_metadata_annotations') do
885
+ filtered = emit_with_tag(tag, msg, '
886
+ kubernetes_url https://localhost:8443
887
+ watch false
888
+ cache_size 1
889
+ use_journal true
890
+ ')
891
+ expected_kube_metadata = {
892
+ 'CONTAINER_NAME' => 'k8s_doesnotmatch',
893
+ 'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
894
+ 'randomfield' => 'randomvalue'
895
+ }
896
+ assert_equal(expected_kube_metadata, filtered[0])
897
+ end
898
+ end
899
+
900
+ test 'processes all events when reading from MessagePackEventStream' do
901
+ VCR.use_cassette('kubernetes_docker_metadata') do
902
+ entries = [[@time, {'time'=>'2015-05-08T09:22:01Z'}], [@time, {'time'=>'2015-05-08T09:22:01Z'}]]
903
+ array_stream = Fluent::ArrayEventStream.new(entries)
904
+ msgpack_stream = Fluent::MessagePackEventStream.new(array_stream.to_msgpack_stream)
905
+
906
+ d = create_driver('
907
+ kubernetes_url https://localhost:8443
908
+ watch false
909
+ cache_size 1
910
+ ')
911
+ d.run {
912
+ d.feed(DEFAULT_TAG, msgpack_stream)
913
+ }
914
+ filtered = d.filtered.map{|e| e.last}
915
+
916
+ expected_kube_metadata = {
917
+ 'time'=>'2015-05-08T09:22:01Z',
918
+ 'docker' => {
919
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
920
+ },
921
+ 'kubernetes' => {
922
+ 'host' => 'jimmi-redhat.localnet',
923
+ 'pod_name' => 'fabric8-console-controller-98rqc',
924
+ 'container_name' => 'fabric8-console-container',
925
+ 'container_image' => 'fabric8/hawtio-kubernetes:latest',
926
+ 'container_image_id' => 'docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303',
927
+ 'namespace_name' => 'default',
928
+ 'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
929
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
930
+ 'master_url' => 'https://localhost:8443',
931
+ 'labels' => {
932
+ 'component' => 'fabric8Console'
933
+ }
934
+ }
935
+ }
936
+
937
+ assert_equal(expected_kube_metadata, filtered[0])
938
+ assert_equal(expected_kube_metadata, filtered[1])
939
+ end
940
+ end
941
+
942
+ test 'with docker & kubernetes metadata using skip config params' do
943
+ VCR.use_cassette('kubernetes_docker_metadata') do
944
+ filtered = emit({},'
945
+ kubernetes_url https://localhost:8443
946
+ watch false
947
+ cache_size 1
948
+ skip_labels true
949
+ skip_container_metadata true
950
+ skip_master_url true
951
+ skip_namespace_metadata true
952
+ ')
953
+ expected_kube_metadata = {
954
+ 'docker' => {
955
+ 'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
956
+ },
957
+ 'kubernetes' => {
958
+ 'host' => 'jimmi-redhat.localnet',
959
+ 'pod_name' => 'fabric8-console-controller-98rqc',
960
+ 'container_name' => 'fabric8-console-container',
961
+ 'namespace_name' => 'default',
962
+ 'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d'
963
+ }
964
+ }
965
+
966
+ assert_equal(expected_kube_metadata, filtered[0])
967
+ end
968
+ end
969
+ end
970
+ end