fluent-plugin-kubernetes_metadata_filter 0.23.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/fluent-plugin-kubernetes_metadata_filter.gemspec +1 -1
- data/lib/fluent/plugin/filter_kubernetes_metadata.rb +32 -3
- data/test/cassettes/kubernetes_docker_metadata_annotations.yml +188 -0
- data/test/plugin/test_filter_kubernetes_metadata.rb +31 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 718b00c62d8a5f40dd763c50b34ddc7ab4106a98
|
4
|
+
data.tar.gz: 4368cdeb4409e1416c7dfe12ab75b7c604c9f5a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f30bf120124b195306ab89945ecc415edd773d362b830213dade8968daa2fba48df54941a13db1eba83e778057d46319af0d3e9c329776205633e8c4d4a0a5d
|
7
|
+
data.tar.gz: 589952266c386bf83792e58dd404826357232ac68f798cb700ad5942c6e05f04b4c3848de3e575c6ff0782ab26ce8057060c3f8b7d06ec95328e95938cf93951
|
data/README.md
CHANGED
@@ -29,6 +29,7 @@ This must used named capture groups for `container_name`, `pod_name` & `namespac
|
|
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
31
|
* `container_name_to_kubernetes_regexp` - The regular expression used to extract the k8s metadata encoded in the journal `CONTAINER_NAME` field (default: `'^k8s_(?<container_name>[^\.]+)\.(?<container_hash>[a-z0-9]{8})_(?<pod_name>[^_]+)_(?<namespace>[^_]+)_(?<pod_id>[^_]+)_(?<pod_randhex>[a-z0-9]{8})$'`)
|
32
|
+
* `annotation_match` - Array of regular expressions matching annotation field names. Matched annotations are added to a log record.
|
32
33
|
|
33
34
|
Reading from the JSON formatted log files with `in_tail` and wildcard filenames:
|
34
35
|
```
|
@@ -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.24.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}
|
@@ -54,6 +54,8 @@ module Fluent
|
|
54
54
|
:string,
|
55
55
|
:default => '^k8s_(?<container_name>[^\.]+)\.[^_]+_(?<pod_name>[^_]+)_(?<namespace>[^_]+)_[^_]+_[a-f0-9]{8}$'
|
56
56
|
|
57
|
+
config_param :annotation_match, :array, default: []
|
58
|
+
|
57
59
|
def syms_to_strs(hsh)
|
58
60
|
newhsh = {}
|
59
61
|
hsh.each_pair do |kk,vv|
|
@@ -74,10 +76,11 @@ module Fluent
|
|
74
76
|
metadata = @client.get_pod(pod_name, namespace_name)
|
75
77
|
return if !metadata
|
76
78
|
labels = syms_to_strs(metadata['metadata']['labels'].to_h)
|
79
|
+
annotations = match_annotations(syms_to_strs(metadata['metadata']['annotations'].to_h))
|
77
80
|
if @de_dot
|
78
81
|
self.de_dot!(labels)
|
79
82
|
end
|
80
|
-
|
83
|
+
kubernetes_metadata = {
|
81
84
|
'namespace_name' => namespace_name,
|
82
85
|
'pod_id' => metadata['metadata']['uid'],
|
83
86
|
'pod_name' => pod_name,
|
@@ -85,6 +88,8 @@ module Fluent
|
|
85
88
|
'labels' => labels,
|
86
89
|
'host' => metadata['spec']['nodeName']
|
87
90
|
}
|
91
|
+
kubernetes_metadata['annotations'] = annotations unless annotations.empty?
|
92
|
+
return kubernetes_metadata
|
88
93
|
rescue KubeException
|
89
94
|
nil
|
90
95
|
end
|
@@ -180,6 +185,16 @@ module Fluent
|
|
180
185
|
@merge_json_log_key = 'log'
|
181
186
|
self.class.class_eval { alias_method :filter_stream, :filter_stream_from_files }
|
182
187
|
end
|
188
|
+
|
189
|
+
@annotations_regexps = []
|
190
|
+
@annotation_match.each do |regexp|
|
191
|
+
begin
|
192
|
+
@annotations_regexps << Regexp.compile(regexp)
|
193
|
+
rescue RegexpError => e
|
194
|
+
log.error "Error: invalid regular expression in annotation_match: #{e}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
183
198
|
end
|
184
199
|
|
185
200
|
def filter_stream_from_files(tag, es)
|
@@ -324,6 +339,18 @@ module Fluent
|
|
324
339
|
end
|
325
340
|
end
|
326
341
|
|
342
|
+
def match_annotations(annotations)
|
343
|
+
result = {}
|
344
|
+
@annotations_regexps.each do |regexp|
|
345
|
+
annotations.each do |key, value|
|
346
|
+
if ::Fluent::StringUtil.match_regexp(regexp, key.to_s)
|
347
|
+
result[key] = value
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
result
|
352
|
+
end
|
353
|
+
|
327
354
|
def start_watch
|
328
355
|
begin
|
329
356
|
resource_version = @client.get_pods.resourceVersion
|
@@ -341,13 +368,15 @@ module Fluent
|
|
341
368
|
cache_key = "#{pod_cache_key}_#{container_status['name']}"
|
342
369
|
cached = @cache[cache_key]
|
343
370
|
if cached
|
344
|
-
# Only thing that can be modified is labels
|
371
|
+
# Only thing that can be modified is labels and (possibly) annotations
|
345
372
|
labels = syms_to_strs(notice.object.metadata.labels.to_h)
|
373
|
+
annotations = match_annotations(syms_to_strs(notice.object.metadata.annotations.to_h))
|
346
374
|
if @de_dot
|
347
375
|
self.de_dot!(labels)
|
348
376
|
end
|
349
377
|
cached['kubernetes']['labels'] = labels
|
350
|
-
|
378
|
+
cached['kubernetes']['annotations'] = annotations unless annotations.empty?
|
379
|
+
@cache[cache_key] = cached
|
351
380
|
end
|
352
381
|
}
|
353
382
|
end
|
@@ -0,0 +1,188 @@
|
|
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
|
+
---
|
20
|
+
http_interactions:
|
21
|
+
- request:
|
22
|
+
method: get
|
23
|
+
uri: https://localhost:8443/api
|
24
|
+
body:
|
25
|
+
encoding: US-ASCII
|
26
|
+
string: ''
|
27
|
+
headers:
|
28
|
+
Accept:
|
29
|
+
- "*/*; q=0.5, application/xml"
|
30
|
+
Accept-Encoding:
|
31
|
+
- gzip, deflate
|
32
|
+
User-Agent:
|
33
|
+
- Ruby
|
34
|
+
response:
|
35
|
+
status:
|
36
|
+
code: 200
|
37
|
+
message: OK
|
38
|
+
headers:
|
39
|
+
Content-Type:
|
40
|
+
- application/json
|
41
|
+
Date:
|
42
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
43
|
+
Content-Length:
|
44
|
+
- '67'
|
45
|
+
body:
|
46
|
+
encoding: UTF-8
|
47
|
+
string: |-
|
48
|
+
{
|
49
|
+
"versions": [
|
50
|
+
"v1"
|
51
|
+
]
|
52
|
+
}
|
53
|
+
http_version:
|
54
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
55
|
+
- request:
|
56
|
+
method: get
|
57
|
+
uri: https://localhost:8443/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc
|
58
|
+
body:
|
59
|
+
encoding: US-ASCII
|
60
|
+
string: ''
|
61
|
+
headers:
|
62
|
+
Accept:
|
63
|
+
- "*/*; q=0.5, application/xml"
|
64
|
+
Accept-Encoding:
|
65
|
+
- gzip, deflate
|
66
|
+
User-Agent:
|
67
|
+
- Ruby
|
68
|
+
response:
|
69
|
+
status:
|
70
|
+
code: 200
|
71
|
+
message: OK
|
72
|
+
headers:
|
73
|
+
Content-Type:
|
74
|
+
- application/json
|
75
|
+
Date:
|
76
|
+
- Fri, 08 May 2015 10:35:37 GMT
|
77
|
+
Transfer-Encoding:
|
78
|
+
- chunked
|
79
|
+
body:
|
80
|
+
encoding: UTF-8
|
81
|
+
string: |-
|
82
|
+
{
|
83
|
+
"kind": "Pod",
|
84
|
+
"apiVersion": "v1",
|
85
|
+
"metadata": {
|
86
|
+
"name": "fabric8-console-controller-98rqc",
|
87
|
+
"generateName": "fabric8-console-controller-",
|
88
|
+
"namespace": "default",
|
89
|
+
"selfLink": "/api/v1/namespaces/default/pods/fabric8-console-controller-98rqc",
|
90
|
+
"uid": "c76927af-f563-11e4-b32d-54ee7527188d",
|
91
|
+
"resourceVersion": "122",
|
92
|
+
"creationTimestamp": "2015-05-08T09:22:42Z",
|
93
|
+
"labels": {
|
94
|
+
"component": "fabric8Console"
|
95
|
+
},
|
96
|
+
"annotations": {
|
97
|
+
"kubernetes.io/config.hash": "c171c44f5b9345c6dc17b0e95030318c",
|
98
|
+
"kubernetes.io/config.mirror": "c171c44f5b9345c6dc17b0e95030318c",
|
99
|
+
"kubernetes.io/config.seen": "2016-06-06T08:08:35.680437994Z",
|
100
|
+
"kubernetes.io/config.source": "file",
|
101
|
+
"custom.field1": "hello_kitty",
|
102
|
+
"field.two": "value"
|
103
|
+
}
|
104
|
+
},
|
105
|
+
"spec": {
|
106
|
+
"volumes": [
|
107
|
+
{
|
108
|
+
"name": "openshift-cert-secrets",
|
109
|
+
"hostPath": null,
|
110
|
+
"emptyDir": null,
|
111
|
+
"gcePersistentDisk": null,
|
112
|
+
"gitRepo": null,
|
113
|
+
"secret": {
|
114
|
+
"secretName": "openshift-cert-secrets"
|
115
|
+
},
|
116
|
+
"nfs": null,
|
117
|
+
"iscsi": null,
|
118
|
+
"glusterfs": null
|
119
|
+
}
|
120
|
+
],
|
121
|
+
"containers": [
|
122
|
+
{
|
123
|
+
"name": "fabric8-console-container",
|
124
|
+
"image": "fabric8/hawtio-kubernetes:latest",
|
125
|
+
"ports": [
|
126
|
+
{
|
127
|
+
"containerPort": 9090,
|
128
|
+
"protocol": "TCP"
|
129
|
+
}
|
130
|
+
],
|
131
|
+
"env": [
|
132
|
+
{
|
133
|
+
"name": "OAUTH_CLIENT_ID",
|
134
|
+
"value": "fabric8-console"
|
135
|
+
},
|
136
|
+
{
|
137
|
+
"name": "OAUTH_AUTHORIZE_URI",
|
138
|
+
"value": "https://localhost:8443/oauth/authorize"
|
139
|
+
}
|
140
|
+
],
|
141
|
+
"resources": {},
|
142
|
+
"volumeMounts": [
|
143
|
+
{
|
144
|
+
"name": "openshift-cert-secrets",
|
145
|
+
"readOnly": true,
|
146
|
+
"mountPath": "/etc/secret-volume"
|
147
|
+
}
|
148
|
+
],
|
149
|
+
"terminationMessagePath": "/dev/termination-log",
|
150
|
+
"imagePullPolicy": "IfNotPresent",
|
151
|
+
"capabilities": {}
|
152
|
+
}
|
153
|
+
],
|
154
|
+
"restartPolicy": "Always",
|
155
|
+
"dnsPolicy": "ClusterFirst",
|
156
|
+
"nodeName": "jimmi-redhat.localnet"
|
157
|
+
},
|
158
|
+
"status": {
|
159
|
+
"phase": "Running",
|
160
|
+
"Condition": [
|
161
|
+
{
|
162
|
+
"type": "Ready",
|
163
|
+
"status": "True"
|
164
|
+
}
|
165
|
+
],
|
166
|
+
"hostIP": "172.17.42.1",
|
167
|
+
"podIP": "172.17.0.8",
|
168
|
+
"containerStatuses": [
|
169
|
+
{
|
170
|
+
"name": "fabric8-console-container",
|
171
|
+
"state": {
|
172
|
+
"running": {
|
173
|
+
"startedAt": "2015-05-08T09:22:44Z"
|
174
|
+
}
|
175
|
+
},
|
176
|
+
"lastState": {},
|
177
|
+
"ready": true,
|
178
|
+
"restartCount": 0,
|
179
|
+
"image": "fabric8/hawtio-kubernetes:latest",
|
180
|
+
"imageID": "docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303",
|
181
|
+
"containerID": "docker://49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459"
|
182
|
+
}
|
183
|
+
]
|
184
|
+
}
|
185
|
+
}
|
186
|
+
http_version:
|
187
|
+
recorded_at: Fri, 08 May 2015 10:35:37 GMT
|
188
|
+
recorded_with: VCR 2.9.3
|
@@ -502,5 +502,36 @@ use_journal true
|
|
502
502
|
end
|
503
503
|
end
|
504
504
|
|
505
|
+
test 'with kubernetes annotations' do
|
506
|
+
VCR.use_cassette('kubernetes_docker_metadata_annotations') do
|
507
|
+
es = emit({},'
|
508
|
+
kubernetes_url https://localhost:8443
|
509
|
+
watch false
|
510
|
+
cache_size 1
|
511
|
+
annotation_match [ "^custom.+", "two"]
|
512
|
+
')
|
513
|
+
expected_kube_metadata = {
|
514
|
+
'docker' => {
|
515
|
+
'container_id' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
516
|
+
},
|
517
|
+
'kubernetes' => {
|
518
|
+
'host' => 'jimmi-redhat.localnet',
|
519
|
+
'pod_name' => 'fabric8-console-controller-98rqc',
|
520
|
+
'container_name' => 'fabric8-console-container',
|
521
|
+
'namespace_name' => 'default',
|
522
|
+
'pod_id' => 'c76927af-f563-11e4-b32d-54ee7527188d',
|
523
|
+
'labels' => {
|
524
|
+
'component' => 'fabric8Console'
|
525
|
+
},
|
526
|
+
'annotations' => {
|
527
|
+
'custom.field1' => 'hello_kitty',
|
528
|
+
'field.two' => 'value'
|
529
|
+
}
|
530
|
+
}
|
531
|
+
}
|
532
|
+
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
505
536
|
end
|
506
537
|
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.24.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: 2016-
|
11
|
+
date: 2016-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -223,6 +223,7 @@ files:
|
|
223
223
|
- lib/fluent/plugin/filter_kubernetes_metadata.rb
|
224
224
|
- test/cassettes/invalid_api_server_config.yml
|
225
225
|
- test/cassettes/kubernetes_docker_metadata.yml
|
226
|
+
- test/cassettes/kubernetes_docker_metadata_annotations.yml
|
226
227
|
- test/cassettes/kubernetes_docker_metadata_dotted_labels.yml
|
227
228
|
- test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml
|
228
229
|
- test/cassettes/metadata_with_namespace_id.yml
|
@@ -251,13 +252,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
251
252
|
version: '0'
|
252
253
|
requirements: []
|
253
254
|
rubyforge_project:
|
254
|
-
rubygems_version: 2.
|
255
|
+
rubygems_version: 2.5.1
|
255
256
|
signing_key:
|
256
257
|
specification_version: 4
|
257
258
|
summary: Filter plugin to add Kubernetes metadata
|
258
259
|
test_files:
|
259
260
|
- test/cassettes/invalid_api_server_config.yml
|
260
261
|
- test/cassettes/kubernetes_docker_metadata.yml
|
262
|
+
- test/cassettes/kubernetes_docker_metadata_annotations.yml
|
261
263
|
- test/cassettes/kubernetes_docker_metadata_dotted_labels.yml
|
262
264
|
- test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml
|
263
265
|
- test/cassettes/metadata_with_namespace_id.yml
|