fluent-plugin-kubernetes_metadata_filter 0.26.3 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -3
- data/fluent-plugin-kubernetes_metadata_filter.gemspec +1 -1
- data/lib/fluent/plugin/filter_kubernetes_metadata.rb +108 -92
- data/test/cassettes/kubernetes_docker_metadata.yml +48 -0
- data/test/cassettes/kubernetes_docker_metadata_annotations.yml +51 -0
- data/test/cassettes/kubernetes_docker_metadata_dotted_labels.yml +51 -0
- data/test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml +48 -0
- data/test/cassettes/metadata_with_namespace_id.yml +48 -0
- data/test/plugin/test_filter_kubernetes_metadata.rb +135 -11
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 168dd4ff037a7da0fc60de77b43784416cf0bf40
|
4
|
+
data.tar.gz: 6ecb0b18c7fc0a5883ec4584dd1e7261ae94393e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 234788bfb4c824714fc56cb165ac74480a78932bbe82f4b4bb5a02e0b491d7cedc7b6e54b23a6fef24be784184684630f5464ae87a20477f58a306a56cce72a0
|
7
|
+
data.tar.gz: d25a5dc8846f85c66b8ed99aadbc080d94a770e4cc887dbcf57c326721693cfbc88ed90db87a7a42a4c82182a2eb4974f39077b54f917fa117254d4f0cd2eaef
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
Configuration options for fluent.conf are:
|
13
13
|
|
14
|
-
* `kubernetes_url` - URL to the API server. Set this to retrieve further kubernetes metadata for logs from kubernetes API server
|
14
|
+
* `kubernetes_url` - URL to the API server. Set this to retrieve further kubernetes metadata for logs from kubernetes API server. If not specified, environment variables `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` will be used if both are present which is typically true when running fluentd in a pod.
|
15
15
|
* `apiVersion` - API version to use (default: `v1`)
|
16
16
|
* `ca_file` - path to CA file for Kubernetes server certificate validation
|
17
17
|
* `verify_ssl` - validate SSL certificates (default: `true`)
|
@@ -28,7 +28,8 @@ This must used named capture groups for `container_name`, `pod_name` & `namespac
|
|
28
28
|
* `de_dot` - replace dots in labels with configured `de_dot_separator`, required for ElasticSearch 2.x compatibility (default: `true`)
|
29
29
|
* `de_dot_separator` - separator to use if `de_dot` is enabled (default: `_`)
|
30
30
|
* `use_journal` - If false (default), messages are expected to be formatted and tagged as if read by the fluentd in\_tail plugin with wildcard filename. If true, messages are expected to be formatted as if read from the systemd journal. The `MESSAGE` field has the full message. The `CONTAINER_NAME` field has the encoded k8s metadata (see below). The `CONTAINER_ID_FULL` field has the full container uuid. This requires docker to use the `--log-driver=journald` log driver.
|
31
|
-
* `container_name_to_kubernetes_regexp` - The regular expression used to extract the k8s metadata encoded in the journal `CONTAINER_NAME` field (default: `'^
|
31
|
+
* `container_name_to_kubernetes_regexp` - The regular expression used to extract the k8s metadata encoded in the journal `CONTAINER_NAME` field (default: `'^(?<name_prefix>[^_]+)_(?<container_name>[^\._]+)(\.(?<container_hash>[^_]+))?_(?<pod_name>[^_]+)_(?<namespace>[^_]+)_[^_]+_[^_]+$'`
|
32
|
+
* This corresponds to the definition [in the source](https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockertools/docker.go#L317)
|
32
33
|
* `annotation_match` - Array of regular expressions matching annotation field names. Matched annotations are added to a log record.
|
33
34
|
|
34
35
|
Reading from the JSON formatted log files with `in_tail` and wildcard filenames:
|
@@ -43,7 +44,7 @@ Reading from the JSON formatted log files with `in_tail` and wildcard filenames:
|
|
43
44
|
read_from_head true
|
44
45
|
</source>
|
45
46
|
|
46
|
-
<filter kubernetes.var.log.containers
|
47
|
+
<filter kubernetes.var.log.containers.**.log>
|
47
48
|
type kubernetes_metadata
|
48
49
|
</filter>
|
49
50
|
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "fluent-plugin-kubernetes_metadata_filter"
|
7
|
-
gem.version = "0.
|
7
|
+
gem.version = "0.27.0"
|
8
8
|
gem.authors = ["Jimmi Dyson"]
|
9
9
|
gem.email = ["jimmidyson@gmail.com"]
|
10
10
|
gem.description = %q{Filter plugin to add Kubernetes metadata}
|
@@ -39,6 +39,7 @@ module Fluent
|
|
39
39
|
config_param :merge_json_log, :bool, default: true
|
40
40
|
config_param :preserve_json_log, :bool, default: true
|
41
41
|
config_param :include_namespace_id, :bool, default: false
|
42
|
+
config_param :include_namespace_metadata, :bool, default: false
|
42
43
|
config_param :secret_dir, :string, default: '/var/run/secrets/kubernetes.io/serviceaccount'
|
43
44
|
config_param :de_dot, :bool, default: true
|
44
45
|
config_param :de_dot_separator, :string, default: '_'
|
@@ -50,9 +51,10 @@ module Fluent
|
|
50
51
|
# Field 2 is the container_hash, field 5 is the pod_id, and field 6 is the pod_randhex
|
51
52
|
# I would have included them as named groups, but you can't have named groups that are
|
52
53
|
# non-capturing :P
|
54
|
+
# parse format is defined here: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockertools/docker.go#L317
|
53
55
|
config_param :container_name_to_kubernetes_regexp,
|
54
56
|
:string,
|
55
|
-
:default => '^
|
57
|
+
:default => '^(?<name_prefix>[^_]+)_(?<container_name>[^\._]+)(\.(?<container_hash>[^_]+))?_(?<pod_name>[^_]+)_(?<namespace>[^_]+)_[^_]+_[^_]+$'
|
56
58
|
|
57
59
|
config_param :annotation_match, :array, default: []
|
58
60
|
|
@@ -71,25 +73,45 @@ module Fluent
|
|
71
73
|
newhsh
|
72
74
|
end
|
73
75
|
|
74
|
-
def
|
76
|
+
def parse_pod_metadata(pod_object)
|
77
|
+
labels = syms_to_strs(pod_object['metadata']['labels'].to_h)
|
78
|
+
annotations = match_annotations(syms_to_strs(pod_object['metadata']['annotations'].to_h))
|
79
|
+
if @de_dot
|
80
|
+
self.de_dot!(labels)
|
81
|
+
self.de_dot!(annotations)
|
82
|
+
end
|
83
|
+
kubernetes_metadata = {
|
84
|
+
'namespace_name' => pod_object['metadata']['namespace'],
|
85
|
+
'pod_id' => pod_object['metadata']['uid'],
|
86
|
+
'pod_name' => pod_object['metadata']['name'],
|
87
|
+
'labels' => labels,
|
88
|
+
'host' => pod_object['spec']['nodeName'],
|
89
|
+
'master_url' => @kubernetes_url
|
90
|
+
}
|
91
|
+
kubernetes_metadata['annotations'] = annotations unless annotations.empty?
|
92
|
+
return kubernetes_metadata
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_namespace_metadata(namespace_object)
|
96
|
+
labels = syms_to_strs(namespace_object['metadata']['labels'].to_h)
|
97
|
+
annotations = match_annotations(syms_to_strs(namespace_object['metadata']['annotations'].to_h))
|
98
|
+
if @de_dot
|
99
|
+
self.de_dot!(labels)
|
100
|
+
self.de_dot!(annotations)
|
101
|
+
end
|
102
|
+
kubernetes_metadata = {
|
103
|
+
'namespace_id' => namespace_object['metadata']['uid']
|
104
|
+
}
|
105
|
+
kubernetes_metadata['namespace_labels'] = labels unless labels.empty?
|
106
|
+
kubernetes_metadata['namespace_annotations'] = annotations unless annotations.empty?
|
107
|
+
return kubernetes_metadata
|
108
|
+
end
|
109
|
+
|
110
|
+
def get_pod_metadata(namespace_name, pod_name)
|
75
111
|
begin
|
76
112
|
metadata = @client.get_pod(pod_name, namespace_name)
|
77
113
|
return if !metadata
|
78
|
-
|
79
|
-
annotations = match_annotations(syms_to_strs(metadata['metadata']['annotations'].to_h))
|
80
|
-
if @de_dot
|
81
|
-
self.de_dot!(labels)
|
82
|
-
self.de_dot!(annotations)
|
83
|
-
end
|
84
|
-
kubernetes_metadata = {
|
85
|
-
'namespace_name' => namespace_name,
|
86
|
-
'pod_id' => metadata['metadata']['uid'],
|
87
|
-
'pod_name' => pod_name,
|
88
|
-
'labels' => labels,
|
89
|
-
'host' => metadata['spec']['nodeName']
|
90
|
-
}
|
91
|
-
kubernetes_metadata['annotations'] = annotations unless annotations.empty?
|
92
|
-
return kubernetes_metadata
|
114
|
+
return parse_pod_metadata(metadata)
|
93
115
|
rescue KubeException
|
94
116
|
nil
|
95
117
|
end
|
@@ -110,11 +132,16 @@ module Fluent
|
|
110
132
|
raise Fluent::ConfigError, "Invalid de_dot_separator: cannot be or contain '.'"
|
111
133
|
end
|
112
134
|
|
135
|
+
if @include_namespace_id
|
136
|
+
# For compatibility, use include_namespace_metadata instead
|
137
|
+
@include_namespace_metadata = true
|
138
|
+
end
|
139
|
+
|
113
140
|
if @cache_ttl < 0
|
114
141
|
@cache_ttl = :none
|
115
142
|
end
|
116
143
|
@cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
|
117
|
-
if @
|
144
|
+
if @include_namespace_metadata
|
118
145
|
@namespace_cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
|
119
146
|
end
|
120
147
|
@tag_to_kubernetes_name_regexp_compiled = Regexp.compile(@tag_to_kubernetes_name_regexp)
|
@@ -172,7 +199,7 @@ module Fluent
|
|
172
199
|
if @watch
|
173
200
|
thread = Thread.new(self) { |this| this.start_watch }
|
174
201
|
thread.abort_on_exception = true
|
175
|
-
if @
|
202
|
+
if @include_namespace_metadata
|
176
203
|
namespace_thread = Thread.new(self) { |this| this.start_namespace_watch }
|
177
204
|
namespace_thread.abort_on_exception = true
|
178
205
|
end
|
@@ -197,6 +224,42 @@ module Fluent
|
|
197
224
|
|
198
225
|
end
|
199
226
|
|
227
|
+
def get_metadata_for_record(namespace_name, pod_name, container_name)
|
228
|
+
metadata = {
|
229
|
+
'container_name' => container_name,
|
230
|
+
'namespace_name' => namespace_name,
|
231
|
+
'pod_name' => pod_name,
|
232
|
+
}
|
233
|
+
if @kubernetes_url.present?
|
234
|
+
cache_key = "#{namespace_name}_#{pod_name}"
|
235
|
+
|
236
|
+
this = self
|
237
|
+
pod_metadata = @cache.getset(cache_key) {
|
238
|
+
md = this.get_pod_metadata(
|
239
|
+
namespace_name,
|
240
|
+
pod_name,
|
241
|
+
)
|
242
|
+
md
|
243
|
+
}
|
244
|
+
metadata.merge!(pod_metadata) if pod_metadata
|
245
|
+
|
246
|
+
if @include_namespace_metadata
|
247
|
+
namespace_metadata = @namespace_cache.getset(namespace_name) {
|
248
|
+
begin
|
249
|
+
namespace = @client.get_namespace(namespace_name)
|
250
|
+
if namespace
|
251
|
+
parse_namespace_metadata(namespace)
|
252
|
+
end
|
253
|
+
rescue KubeException
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
}
|
257
|
+
metadata.merge!(namespace_metadata) if namespace_metadata
|
258
|
+
end
|
259
|
+
end
|
260
|
+
metadata
|
261
|
+
end
|
262
|
+
|
200
263
|
def filter_stream(tag, es)
|
201
264
|
es
|
202
265
|
end
|
@@ -211,38 +274,12 @@ module Fluent
|
|
211
274
|
'docker' => {
|
212
275
|
'container_id' => match_data['docker_id']
|
213
276
|
},
|
214
|
-
'kubernetes' =>
|
215
|
-
|
216
|
-
|
217
|
-
|
277
|
+
'kubernetes' => get_metadata_for_record(
|
278
|
+
match_data['namespace'],
|
279
|
+
match_data['pod_name'],
|
280
|
+
match_data['container_name'],
|
281
|
+
),
|
218
282
|
}
|
219
|
-
|
220
|
-
if @kubernetes_url.present?
|
221
|
-
cache_key = "#{metadata['kubernetes']['namespace_name']}_#{metadata['kubernetes']['pod_name']}"
|
222
|
-
|
223
|
-
this = self
|
224
|
-
kubernetes_metadata = @cache.getset(cache_key) {
|
225
|
-
if metadata
|
226
|
-
md = this.get_metadata(
|
227
|
-
metadata['kubernetes']['namespace_name'],
|
228
|
-
metadata['kubernetes']['pod_name']
|
229
|
-
)
|
230
|
-
md
|
231
|
-
end
|
232
|
-
}
|
233
|
-
metadata['kubernetes'].merge!(kubernetes_metadata) if kubernetes_metadata
|
234
|
-
|
235
|
-
if @include_namespace_id
|
236
|
-
namespace_name = metadata['kubernetes']['namespace_name']
|
237
|
-
namespace_id = @namespace_cache.getset(namespace_name) {
|
238
|
-
namespace = @client.get_namespace(namespace_name)
|
239
|
-
namespace['metadata']['uid'] if namespace
|
240
|
-
}
|
241
|
-
metadata['kubernetes']['namespace_id'] = namespace_id if namespace_id
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
metadata['kubernetes']['container_name'] = match_data['container_name']
|
246
283
|
end
|
247
284
|
|
248
285
|
es.each { |time, record|
|
@@ -269,36 +306,13 @@ module Fluent
|
|
269
306
|
'docker' => {
|
270
307
|
'container_id' => record['CONTAINER_ID_FULL']
|
271
308
|
},
|
272
|
-
'kubernetes' =>
|
273
|
-
|
274
|
-
|
275
|
-
|
309
|
+
'kubernetes' => get_metadata_for_record(
|
310
|
+
match_data['namespace'],
|
311
|
+
match_data['pod_name'],
|
312
|
+
match_data['container_name'],
|
313
|
+
)
|
276
314
|
}
|
277
|
-
|
278
|
-
cache_key = "#{metadata['kubernetes']['namespace_name']}_#{metadata['kubernetes']['pod_name']}"
|
279
|
-
|
280
|
-
this = self
|
281
|
-
kubernetes_metadata = @cache.getset(cache_key) {
|
282
|
-
if metadata
|
283
|
-
md = this.get_metadata(
|
284
|
-
metadata['kubernetes']['namespace_name'],
|
285
|
-
metadata['kubernetes']['pod_name']
|
286
|
-
)
|
287
|
-
md
|
288
|
-
end
|
289
|
-
}
|
290
|
-
metadata['kubernetes'].merge!(kubernetes_metadata) if kubernetes_metadata
|
291
|
-
|
292
|
-
if @include_namespace_id
|
293
|
-
namespace_name = metadata['kubernetes']['namespace_name']
|
294
|
-
namespace_id = @namespace_cache.getset(namespace_name) {
|
295
|
-
namespace = @client.get_namespace(namespace_name)
|
296
|
-
namespace['metadata']['uid'] if namespace
|
297
|
-
}
|
298
|
-
metadata['kubernetes']['namespace_id'] = namespace_id if namespace_id
|
299
|
-
end
|
300
|
-
end
|
301
|
-
metadata['kubernetes']['container_name'] = match_data['container_name']
|
315
|
+
|
302
316
|
metadata
|
303
317
|
end
|
304
318
|
unless metadata
|
@@ -361,7 +375,12 @@ module Fluent
|
|
361
375
|
resource_version = @client.get_pods.resourceVersion
|
362
376
|
watcher = @client.watch_pods(resource_version)
|
363
377
|
rescue Exception => e
|
364
|
-
|
378
|
+
message = "Exception encountered fetching metadata from Kubernetes API endpoint: #{e.message}"
|
379
|
+
if e.respond_to?(:response)
|
380
|
+
message += " (#{e.response})"
|
381
|
+
end
|
382
|
+
|
383
|
+
raise Fluent::ConfigError, message
|
365
384
|
end
|
366
385
|
|
367
386
|
watcher.each do |notice|
|
@@ -370,16 +389,7 @@ module Fluent
|
|
370
389
|
cache_key = "#{notice.object['metadata']['namespace']}_#{notice.object['metadata']['name']}"
|
371
390
|
cached = @cache[cache_key]
|
372
391
|
if cached
|
373
|
-
|
374
|
-
labels = syms_to_strs(notice.object.metadata.labels.to_h)
|
375
|
-
annotations = match_annotations(syms_to_strs(notice.object.metadata.annotations.to_h))
|
376
|
-
if @de_dot
|
377
|
-
self.de_dot!(labels)
|
378
|
-
self.de_dot!(annotations)
|
379
|
-
end
|
380
|
-
cached['labels'] = labels
|
381
|
-
cached['annotations'] = annotations
|
382
|
-
@cache[cache_key] = cached
|
392
|
+
@cache[cache_key] = parse_pod_metadata(notice.object)
|
383
393
|
end
|
384
394
|
when 'DELETED'
|
385
395
|
cache_key = "#{notice.object['metadata']['namespace']}_#{notice.object['metadata']['name']}"
|
@@ -397,11 +407,17 @@ module Fluent
|
|
397
407
|
watcher.each do |notice|
|
398
408
|
puts notice
|
399
409
|
case notice.type
|
410
|
+
when 'MODIFIED'
|
411
|
+
cache_key = notice.object['metadata']['name']
|
412
|
+
cached = @namespace_cache[cache_key]
|
413
|
+
if cached
|
414
|
+
@namespace_cache[cache_key] = parse_namespace_metadata(notice.object)
|
415
|
+
end
|
400
416
|
when 'DELETED'
|
401
417
|
@namespace_cache.delete(notice.object['metadata']['name'])
|
402
418
|
else
|
403
|
-
#
|
404
|
-
#
|
419
|
+
# Don't pay attention to creations, since the created namespace may not
|
420
|
+
# be used by any pod on this node.
|
405
421
|
end
|
406
422
|
end
|
407
423
|
end
|
@@ -177,4 +177,52 @@ http_interactions:
|
|
177
177
|
}
|
178
178
|
http_version:
|
179
179
|
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
180
|
+
- request:
|
181
|
+
method: get
|
182
|
+
uri: https://localhost:8443/api/v1/namespaces/default
|
183
|
+
body:
|
184
|
+
encoding: US-ASCII
|
185
|
+
string: ''
|
186
|
+
headers:
|
187
|
+
Accept:
|
188
|
+
- "*/*; q=0.5, application/xml"
|
189
|
+
Accept-Encoding:
|
190
|
+
- gzip, deflate
|
191
|
+
User-Agent:
|
192
|
+
- Ruby
|
193
|
+
response:
|
194
|
+
status:
|
195
|
+
code: 200
|
196
|
+
message: OK
|
197
|
+
headers:
|
198
|
+
Content-Type:
|
199
|
+
- application/json
|
200
|
+
Date:
|
201
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
202
|
+
Transfer-Encoding:
|
203
|
+
- chunked
|
204
|
+
body:
|
205
|
+
encoding: UTF-8
|
206
|
+
string: |-
|
207
|
+
{
|
208
|
+
"kind": "Namespace",
|
209
|
+
"apiVersion": "v1",
|
210
|
+
"metadata": {
|
211
|
+
"name": "default",
|
212
|
+
"selfLink": "/api/v1/namespaces/default",
|
213
|
+
"uid": "898268c8-4a36-11e5-9d81-42010af0194c",
|
214
|
+
"resourceVersion": "6",
|
215
|
+
"creationTimestamp": "2015-05-08T09:22:01Z"
|
216
|
+
},
|
217
|
+
"spec": {
|
218
|
+
"finalizers": [
|
219
|
+
"kubernetes"
|
220
|
+
]
|
221
|
+
},
|
222
|
+
"status": {
|
223
|
+
"phase": "Active"
|
224
|
+
}
|
225
|
+
}
|
226
|
+
http_version:
|
227
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
180
228
|
recorded_with: VCR 2.9.3
|
@@ -185,4 +185,55 @@ http_interactions:
|
|
185
185
|
}
|
186
186
|
http_version:
|
187
187
|
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
188
|
+
- request:
|
189
|
+
method: get
|
190
|
+
uri: https://localhost:8443/api/v1/namespaces/default
|
191
|
+
body:
|
192
|
+
encoding: US-ASCII
|
193
|
+
string: ''
|
194
|
+
headers:
|
195
|
+
Accept:
|
196
|
+
- "*/*; q=0.5, application/xml"
|
197
|
+
Accept-Encoding:
|
198
|
+
- gzip, deflate
|
199
|
+
User-Agent:
|
200
|
+
- Ruby
|
201
|
+
response:
|
202
|
+
status:
|
203
|
+
code: 200
|
204
|
+
message: OK
|
205
|
+
headers:
|
206
|
+
Content-Type:
|
207
|
+
- application/json
|
208
|
+
Date:
|
209
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
210
|
+
Transfer-Encoding:
|
211
|
+
- chunked
|
212
|
+
body:
|
213
|
+
encoding: UTF-8
|
214
|
+
string: |-
|
215
|
+
{
|
216
|
+
"kind": "Namespace",
|
217
|
+
"apiVersion": "v1",
|
218
|
+
"metadata": {
|
219
|
+
"name": "default",
|
220
|
+
"selfLink": "/api/v1/namespaces/default",
|
221
|
+
"uid": "898268c8-4a36-11e5-9d81-42010af0194c",
|
222
|
+
"resourceVersion": "6",
|
223
|
+
"creationTimestamp": "2015-05-08T09:22:01Z",
|
224
|
+
"annotations": {
|
225
|
+
"workspaceId": "myWorkspaceName"
|
226
|
+
}
|
227
|
+
},
|
228
|
+
"spec": {
|
229
|
+
"finalizers": [
|
230
|
+
"kubernetes"
|
231
|
+
]
|
232
|
+
},
|
233
|
+
"status": {
|
234
|
+
"phase": "Active"
|
235
|
+
}
|
236
|
+
}
|
237
|
+
http_version:
|
238
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
188
239
|
recorded_with: VCR 2.9.3
|
@@ -177,4 +177,55 @@ http_interactions:
|
|
177
177
|
}
|
178
178
|
http_version:
|
179
179
|
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
180
|
+
- request:
|
181
|
+
method: get
|
182
|
+
uri: https://localhost:8443/api/v1/namespaces/default
|
183
|
+
body:
|
184
|
+
encoding: US-ASCII
|
185
|
+
string: ''
|
186
|
+
headers:
|
187
|
+
Accept:
|
188
|
+
- "*/*; q=0.5, application/xml"
|
189
|
+
Accept-Encoding:
|
190
|
+
- gzip, deflate
|
191
|
+
User-Agent:
|
192
|
+
- Ruby
|
193
|
+
response:
|
194
|
+
status:
|
195
|
+
code: 200
|
196
|
+
message: OK
|
197
|
+
headers:
|
198
|
+
Content-Type:
|
199
|
+
- application/json
|
200
|
+
Date:
|
201
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
202
|
+
Transfer-Encoding:
|
203
|
+
- chunked
|
204
|
+
body:
|
205
|
+
encoding: UTF-8
|
206
|
+
string: |-
|
207
|
+
{
|
208
|
+
"kind": "Namespace",
|
209
|
+
"apiVersion": "v1",
|
210
|
+
"metadata": {
|
211
|
+
"name": "default",
|
212
|
+
"selfLink": "/api/v1/namespaces/default",
|
213
|
+
"uid": "898268c8-4a36-11e5-9d81-42010af0194c",
|
214
|
+
"resourceVersion": "6",
|
215
|
+
"creationTimestamp": "2015-05-08T09:22:01Z",
|
216
|
+
"labels": {
|
217
|
+
"kubernetes.io/namespacetest": "somevalue"
|
218
|
+
}
|
219
|
+
},
|
220
|
+
"spec": {
|
221
|
+
"finalizers": [
|
222
|
+
"kubernetes"
|
223
|
+
]
|
224
|
+
},
|
225
|
+
"status": {
|
226
|
+
"phase": "Active"
|
227
|
+
}
|
228
|
+
}
|
229
|
+
http_version:
|
230
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
180
231
|
recorded_with: VCR 2.9.3
|
@@ -197,4 +197,52 @@ http_interactions:
|
|
197
197
|
}
|
198
198
|
http_version:
|
199
199
|
recorded_at: Sat, 09 May 2015 13:51:07 GMT
|
200
|
+
- request:
|
201
|
+
method: get
|
202
|
+
uri: https://localhost:8443/api/v1/namespaces/default
|
203
|
+
body:
|
204
|
+
encoding: US-ASCII
|
205
|
+
string: ''
|
206
|
+
headers:
|
207
|
+
Accept:
|
208
|
+
- "*/*; q=0.5, application/xml"
|
209
|
+
Accept-Encoding:
|
210
|
+
- gzip, deflate
|
211
|
+
User-Agent:
|
212
|
+
- Ruby
|
213
|
+
response:
|
214
|
+
status:
|
215
|
+
code: 200
|
216
|
+
message: OK
|
217
|
+
headers:
|
218
|
+
Content-Type:
|
219
|
+
- application/json
|
220
|
+
Date:
|
221
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
222
|
+
Transfer-Encoding:
|
223
|
+
- chunked
|
224
|
+
body:
|
225
|
+
encoding: UTF-8
|
226
|
+
string: |-
|
227
|
+
{
|
228
|
+
"kind": "Namespace",
|
229
|
+
"apiVersion": "v1",
|
230
|
+
"metadata": {
|
231
|
+
"name": "default",
|
232
|
+
"selfLink": "/api/v1/namespaces/default",
|
233
|
+
"uid": "898268c8-4a36-11e5-9d81-42010af0194c",
|
234
|
+
"resourceVersion": "6",
|
235
|
+
"creationTimestamp": "2015-05-08T09:22:01Z"
|
236
|
+
},
|
237
|
+
"spec": {
|
238
|
+
"finalizers": [
|
239
|
+
"kubernetes"
|
240
|
+
]
|
241
|
+
},
|
242
|
+
"status": {
|
243
|
+
"phase": "Active"
|
244
|
+
}
|
245
|
+
}
|
246
|
+
http_version:
|
247
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
200
248
|
recorded_with: VCR 2.9.3
|
@@ -225,4 +225,52 @@ http_interactions:
|
|
225
225
|
}
|
226
226
|
http_version:
|
227
227
|
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
228
|
+
- request:
|
229
|
+
method: get
|
230
|
+
uri: https://localhost:8443/api/v1/namespaces/default
|
231
|
+
body:
|
232
|
+
encoding: US-ASCII
|
233
|
+
string: ''
|
234
|
+
headers:
|
235
|
+
Accept:
|
236
|
+
- "*/*; q=0.5, application/xml"
|
237
|
+
Accept-Encoding:
|
238
|
+
- gzip, deflate
|
239
|
+
User-Agent:
|
240
|
+
- Ruby
|
241
|
+
response:
|
242
|
+
status:
|
243
|
+
code: 200
|
244
|
+
message: OK
|
245
|
+
headers:
|
246
|
+
Content-Type:
|
247
|
+
- application/json
|
248
|
+
Date:
|
249
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
250
|
+
Transfer-Encoding:
|
251
|
+
- chunked
|
252
|
+
body:
|
253
|
+
encoding: UTF-8
|
254
|
+
string: |-
|
255
|
+
{
|
256
|
+
"kind": "Namespace",
|
257
|
+
"apiVersion": "v1",
|
258
|
+
"metadata": {
|
259
|
+
"name": "default",
|
260
|
+
"selfLink": "/api/v1/namespaces/default",
|
261
|
+
"uid": "898268c8-4a36-11e5-9d81-42010af0194c",
|
262
|
+
"resourceVersion": "6",
|
263
|
+
"creationTimestamp": "2015-05-08T09:22:01Z"
|
264
|
+
},
|
265
|
+
"spec": {
|
266
|
+
"finalizers": [
|
267
|
+
"kubernetes"
|
268
|
+
]
|
269
|
+
},
|
270
|
+
"status": {
|
271
|
+
"phase": "Active"
|
272
|
+
}
|
273
|
+
}
|
274
|
+
http_version:
|
275
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
228
276
|
recorded_with: VCR 2.9.3
|
@@ -166,6 +166,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
166
166
|
'container_name' => 'fabric8-console-container',
|
167
167
|
'namespace_name' => 'default',
|
168
168
|
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
169
|
+
'master_url' => 'https://localhost:8443',
|
169
170
|
'labels' => {
|
170
171
|
'component' => 'fabric8Console'
|
171
172
|
}
|
@@ -194,6 +195,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
194
195
|
'namespace_name' => 'default',
|
195
196
|
'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
|
196
197
|
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
198
|
+
'master_url' => 'https://localhost:8443',
|
197
199
|
'labels' => {
|
198
200
|
'component' => 'fabric8Console'
|
199
201
|
}
|
@@ -221,6 +223,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
221
223
|
'container_name' => 'fabric8-console-container',
|
222
224
|
'namespace_name' => 'default',
|
223
225
|
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
226
|
+
'master_url' => 'https://localhost:8443',
|
224
227
|
'labels' => {
|
225
228
|
'component' => 'fabric8Console'
|
226
229
|
}
|
@@ -377,17 +380,27 @@ use_journal true
|
|
377
380
|
|
378
381
|
test 'with kubernetes dotted labels, de_dot enabled' do
|
379
382
|
VCR.use_cassette('kubernetes_docker_metadata_dotted_labels') do
|
380
|
-
es = emit(
|
383
|
+
es = emit({}, '
|
384
|
+
kubernetes_url https://localhost:8443
|
385
|
+
watch false
|
386
|
+
cache_size 1
|
387
|
+
include_namespace_metadata true
|
388
|
+
')
|
381
389
|
expected_kube_metadata = {
|
382
390
|
'docker' => {
|
383
391
|
'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
384
392
|
},
|
385
393
|
'kubernetes' => {
|
386
|
-
'host'
|
387
|
-
'pod_name'
|
388
|
-
'container_name'
|
389
|
-
'
|
390
|
-
'
|
394
|
+
'host' => 'jimmi-redhat.localnet',
|
395
|
+
'pod_name' => 'fabric8-console-controller-98rqc',
|
396
|
+
'container_name' => 'fabric8-console-container',
|
397
|
+
'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
|
398
|
+
'namespace_labels' => {
|
399
|
+
'kubernetes_io/namespacetest' => 'somevalue'
|
400
|
+
},
|
401
|
+
'namespace_name' => 'default',
|
402
|
+
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
403
|
+
'master_url' => 'https://localhost:8443',
|
391
404
|
'labels' => {
|
392
405
|
'kubernetes_io/test' => 'somevalue'
|
393
406
|
}
|
@@ -404,17 +417,23 @@ use_journal true
|
|
404
417
|
watch false
|
405
418
|
cache_size 1
|
406
419
|
de_dot false
|
420
|
+
include_namespace_metadata true
|
407
421
|
')
|
408
422
|
expected_kube_metadata = {
|
409
423
|
'docker' => {
|
410
424
|
'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
411
425
|
},
|
412
426
|
'kubernetes' => {
|
413
|
-
'host'
|
414
|
-
'pod_name'
|
415
|
-
'container_name'
|
416
|
-
'
|
417
|
-
'
|
427
|
+
'host' => 'jimmi-redhat.localnet',
|
428
|
+
'pod_name' => 'fabric8-console-controller-98rqc',
|
429
|
+
'container_name' => 'fabric8-console-container',
|
430
|
+
'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
|
431
|
+
'namespace_labels' => {
|
432
|
+
'kubernetes.io/namespacetest' => 'somevalue'
|
433
|
+
},
|
434
|
+
'namespace_name' => 'default',
|
435
|
+
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
436
|
+
'master_url' => 'https://localhost:8443',
|
418
437
|
'labels' => {
|
419
438
|
'kubernetes.io/test' => 'somevalue'
|
420
439
|
}
|
@@ -457,6 +476,7 @@ use_journal true
|
|
457
476
|
'container_name' => 'fabric8-console-container',
|
458
477
|
'namespace_name' => 'default',
|
459
478
|
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
479
|
+
'master_url' => 'https://localhost:8443',
|
460
480
|
'labels' => {
|
461
481
|
'component' => 'fabric8Console'
|
462
482
|
}
|
@@ -493,6 +513,7 @@ use_journal true
|
|
493
513
|
'namespace_name' => 'default',
|
494
514
|
'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
|
495
515
|
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
516
|
+
'master_url' => 'https://localhost:8443',
|
496
517
|
'labels' => {
|
497
518
|
'component' => 'fabric8Console'
|
498
519
|
}
|
@@ -520,6 +541,7 @@ use_journal true
|
|
520
541
|
'container_name' => 'fabric8-console-container',
|
521
542
|
'namespace_name' => 'default',
|
522
543
|
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
544
|
+
'master_url' => 'https://localhost:8443',
|
523
545
|
'labels' => {
|
524
546
|
'component' => 'fabric8Console'
|
525
547
|
},
|
@@ -533,5 +555,107 @@ use_journal true
|
|
533
555
|
end
|
534
556
|
end
|
535
557
|
|
558
|
+
test 'with records from journald and docker & kubernetes metadata, alternate form' do
|
559
|
+
# with use_journal true should ignore tags and use CONTAINER_NAME and CONTAINER_ID_FULL
|
560
|
+
tag = 'var.log.containers.junk1_junk2_junk3-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
|
561
|
+
msg = {
|
562
|
+
'CONTAINER_NAME' => 'alt_fabric8-console-container_fabric8-console-controller-98rqc_default_c76927af-f563-11e4-b32d-54ee7527188d_0',
|
563
|
+
'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
|
564
|
+
'randomfield' => 'randomvalue'
|
565
|
+
}
|
566
|
+
VCR.use_cassette('kubernetes_docker_metadata') do
|
567
|
+
es = emit_with_tag(tag, msg, '
|
568
|
+
kubernetes_url https://localhost:8443
|
569
|
+
watch false
|
570
|
+
cache_size 1
|
571
|
+
use_journal true
|
572
|
+
')
|
573
|
+
expected_kube_metadata = {
|
574
|
+
'docker' => {
|
575
|
+
'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
576
|
+
},
|
577
|
+
'kubernetes' => {
|
578
|
+
'host' => 'jimmi-redhat.localnet',
|
579
|
+
'pod_name' => 'fabric8-console-controller-98rqc',
|
580
|
+
'container_name' => 'fabric8-console-container',
|
581
|
+
'namespace_name' => 'default',
|
582
|
+
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
583
|
+
'master_url' => 'https://localhost:8443',
|
584
|
+
'labels' => {
|
585
|
+
'component' => 'fabric8Console'
|
586
|
+
}
|
587
|
+
}
|
588
|
+
}.merge(msg)
|
589
|
+
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
test 'with kubernetes namespace annotations' do
|
594
|
+
VCR.use_cassette('kubernetes_docker_metadata_annotations') do
|
595
|
+
es = emit({},'
|
596
|
+
kubernetes_url https://localhost:8443
|
597
|
+
watch false
|
598
|
+
cache_size 1
|
599
|
+
include_namespace_metadata true
|
600
|
+
annotation_match [ "^custom.+", "two", "workspace*"]
|
601
|
+
')
|
602
|
+
expected_kube_metadata = {
|
603
|
+
'docker' => {
|
604
|
+
'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
605
|
+
},
|
606
|
+
'kubernetes' => {
|
607
|
+
'host' => 'jimmi-redhat.localnet',
|
608
|
+
'pod_name' => 'fabric8-console-controller-98rqc',
|
609
|
+
'container_name' => 'fabric8-console-container',
|
610
|
+
'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
|
611
|
+
'namespace_name' => 'default',
|
612
|
+
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
613
|
+
'master_url' => 'https://localhost:8443',
|
614
|
+
'labels' => {
|
615
|
+
'component' => 'fabric8Console'
|
616
|
+
},
|
617
|
+
'annotations' => {
|
618
|
+
'custom_field1' => 'hello_kitty',
|
619
|
+
'field_two' => 'value'
|
620
|
+
},
|
621
|
+
'namespace_annotations' => {
|
622
|
+
'workspaceId' => 'myWorkspaceName'
|
623
|
+
}
|
624
|
+
}
|
625
|
+
}
|
626
|
+
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
test 'with kubernetes namespace annotations no match' do
|
631
|
+
VCR.use_cassette('kubernetes_docker_metadata_annotations') do
|
632
|
+
es = emit({},'
|
633
|
+
kubernetes_url https://localhost:8443
|
634
|
+
watch false
|
635
|
+
cache_size 1
|
636
|
+
include_namespace_metadata true
|
637
|
+
annotation_match [ "noMatch*"]
|
638
|
+
')
|
639
|
+
expected_kube_metadata = {
|
640
|
+
'docker' => {
|
641
|
+
'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
642
|
+
},
|
643
|
+
'kubernetes' => {
|
644
|
+
'host' => 'jimmi-redhat.localnet',
|
645
|
+
'pod_name' => 'fabric8-console-controller-98rqc',
|
646
|
+
'container_name' => 'fabric8-console-container',
|
647
|
+
'namespace_id' => '898268c8-4a36-11e5-9d81-42010af0194c',
|
648
|
+
'namespace_name' => 'default',
|
649
|
+
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
650
|
+
'master_url' => 'https://localhost:8443',
|
651
|
+
'labels' => {
|
652
|
+
'component' => 'fabric8Console'
|
653
|
+
}
|
654
|
+
}
|
655
|
+
}
|
656
|
+
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
536
660
|
end
|
537
661
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-kubernetes_metadata_filter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.27.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jimmi Dyson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -238,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
238
238
|
version: '0'
|
239
239
|
requirements: []
|
240
240
|
rubyforge_project:
|
241
|
-
rubygems_version: 2.6.
|
241
|
+
rubygems_version: 2.6.12
|
242
242
|
signing_key:
|
243
243
|
specification_version: 4
|
244
244
|
summary: Filter plugin to add Kubernetes metadata
|