fluent-plugin-kubernetes_metadata_filter 0.10.0 → 0.11.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e0fcd32fc3504d09147c16350c4596822151394
|
4
|
+
data.tar.gz: d6032d7ec7cd42cf46fcf101e3d8579883502caf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 606ac89791ceec0de9f1f46d80ced6b126dff9325513c1bc177dcb1cb7f35896f9cdedea4a9aff657f5b0eab1569b0a0eb0143c38c51678cc86cbc5d47c6e1e7
|
7
|
+
data.tar.gz: 98c9aa0d292a7dc9d679ab46961136986ecfbfcfdd2c9276ded1bca00c67fa6ca11a52581942ff3a3d10c32267b259d0267efc0db462f2d8331454f3af6f869c
|
@@ -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.11.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}
|
@@ -34,20 +34,20 @@ module Fluent
|
|
34
34
|
:default => '\.(?<pod_name>[^\._]+)_(?<namespace>[^_]+)_(?<container_name>.+)-(?<docker_id>[a-z0-9]{64})\.log$'
|
35
35
|
config_param :bearer_token_file, :string, default: ''
|
36
36
|
config_param :merge_json_log, :bool, default: true
|
37
|
+
config_param :include_namespace_id, :bool, default: false
|
37
38
|
|
38
|
-
def get_metadata(
|
39
|
+
def get_metadata(namespace_name, pod_name, container_name)
|
39
40
|
begin
|
40
|
-
metadata = @client.get_pod(pod_name,
|
41
|
-
if metadata
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
41
|
+
metadata = @client.get_pod(pod_name, namespace_name)
|
42
|
+
return if !metadata
|
43
|
+
return {
|
44
|
+
namespace_name: namespace_name,
|
45
|
+
pod_id: metadata['metadata']['uid'],
|
46
|
+
pod_name: pod_name,
|
47
|
+
container_name: container_name,
|
48
|
+
labels: metadata['metadata']['labels'].to_h,
|
49
|
+
host: metadata['spec']['host']
|
50
|
+
}
|
51
51
|
rescue KubeException
|
52
52
|
nil
|
53
53
|
end
|
@@ -67,7 +67,10 @@ module Fluent
|
|
67
67
|
if @cache_ttl < 0
|
68
68
|
@cache_ttl = :none
|
69
69
|
end
|
70
|
-
@cache
|
70
|
+
@cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
|
71
|
+
if @include_namespace_id
|
72
|
+
@namespace_cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
|
73
|
+
end
|
71
74
|
@tag_to_kubernetes_name_regexp_compiled = Regexp.compile(@tag_to_kubernetes_name_regexp)
|
72
75
|
|
73
76
|
if @kubernetes_url.present?
|
@@ -97,10 +100,12 @@ module Fluent
|
|
97
100
|
end
|
98
101
|
|
99
102
|
if @watch
|
100
|
-
thread
|
101
|
-
this.start_watch
|
102
|
-
}
|
103
|
+
thread = Thread.new(self) { |this| this.start_watch }
|
103
104
|
thread.abort_on_exception = true
|
105
|
+
if @include_namespace_id
|
106
|
+
namespace_thread = Thread.new(self) { |this| this.start_namespace_watch }
|
107
|
+
namespace_thread.abort_on_exception = true
|
108
|
+
end
|
104
109
|
end
|
105
110
|
end
|
106
111
|
end
|
@@ -116,20 +121,20 @@ module Fluent
|
|
116
121
|
container_id: match_data['docker_id']
|
117
122
|
},
|
118
123
|
kubernetes: {
|
119
|
-
|
124
|
+
namespace_name: match_data['namespace'],
|
120
125
|
pod_name: match_data['pod_name'],
|
121
126
|
container_name: match_data['container_name']
|
122
127
|
}
|
123
128
|
}
|
124
129
|
|
125
130
|
if @kubernetes_url.present?
|
126
|
-
cache_key = "#{metadata[:kubernetes][:
|
131
|
+
cache_key = "#{metadata[:kubernetes][:namespace_name]}_#{metadata[:kubernetes][:pod_name]}_#{metadata[:kubernetes][:container_name]}"
|
127
132
|
|
128
133
|
this = self
|
129
134
|
metadata = @cache.getset(cache_key) {
|
130
135
|
if metadata
|
131
136
|
kubernetes_metadata = this.get_metadata(
|
132
|
-
metadata[:kubernetes][:
|
137
|
+
metadata[:kubernetes][:namespace_name],
|
133
138
|
metadata[:kubernetes][:pod_name],
|
134
139
|
metadata[:kubernetes][:container_name]
|
135
140
|
)
|
@@ -137,6 +142,14 @@ module Fluent
|
|
137
142
|
metadata
|
138
143
|
end
|
139
144
|
}
|
145
|
+
if @include_namespace_id
|
146
|
+
namespace_name = metadata[:kubernetes][:namespace_name]
|
147
|
+
namespace_id = @namespace_cache.getset(namespace_name) {
|
148
|
+
namespace = @client.get_namespace(namespace_name)
|
149
|
+
namespace['metadata']['uid'] if namespace
|
150
|
+
}
|
151
|
+
metadata[:kubernetes][:namespace_id] = namespace_id if namespace_id
|
152
|
+
end
|
140
153
|
end
|
141
154
|
end
|
142
155
|
|
@@ -196,7 +209,23 @@ module Fluent
|
|
196
209
|
}
|
197
210
|
end
|
198
211
|
else
|
199
|
-
#
|
212
|
+
# Don't pay attention to creations, since the created pod may not
|
213
|
+
# end up on this node.
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def start_namespace_watch
|
219
|
+
resource_version = @client.get_namespaces.resourceVersion
|
220
|
+
watcher = @client.watch_namespaces(resource_version)
|
221
|
+
watcher.each do |notice|
|
222
|
+
puts notice
|
223
|
+
case notice.type
|
224
|
+
when 'DELETED'
|
225
|
+
@namespace_cache.delete(notice.object['metadata']['uid'])
|
226
|
+
else
|
227
|
+
# We only care about each namespace's name and UID, neither of which
|
228
|
+
# is modifiable, so we only have to care about deletions.
|
200
229
|
end
|
201
230
|
end
|
202
231
|
end
|
@@ -0,0 +1,228 @@
|
|
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
|
+
},
|
97
|
+
"spec": {
|
98
|
+
"volumes": [
|
99
|
+
{
|
100
|
+
"name": "openshift-cert-secrets",
|
101
|
+
"hostPath": null,
|
102
|
+
"emptyDir": null,
|
103
|
+
"gcePersistentDisk": null,
|
104
|
+
"gitRepo": null,
|
105
|
+
"secret": {
|
106
|
+
"secretName": "openshift-cert-secrets"
|
107
|
+
},
|
108
|
+
"nfs": null,
|
109
|
+
"iscsi": null,
|
110
|
+
"glusterfs": null
|
111
|
+
}
|
112
|
+
],
|
113
|
+
"containers": [
|
114
|
+
{
|
115
|
+
"name": "fabric8-console-container",
|
116
|
+
"image": "fabric8/hawtio-kubernetes:latest",
|
117
|
+
"ports": [
|
118
|
+
{
|
119
|
+
"containerPort": 9090,
|
120
|
+
"protocol": "TCP"
|
121
|
+
}
|
122
|
+
],
|
123
|
+
"env": [
|
124
|
+
{
|
125
|
+
"name": "OAUTH_CLIENT_ID",
|
126
|
+
"value": "fabric8-console"
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"name": "OAUTH_AUTHORIZE_URI",
|
130
|
+
"value": "https://localhost:8443/oauth/authorize"
|
131
|
+
}
|
132
|
+
],
|
133
|
+
"resources": {},
|
134
|
+
"volumeMounts": [
|
135
|
+
{
|
136
|
+
"name": "openshift-cert-secrets",
|
137
|
+
"readOnly": true,
|
138
|
+
"mountPath": "/etc/secret-volume"
|
139
|
+
}
|
140
|
+
],
|
141
|
+
"terminationMessagePath": "/dev/termination-log",
|
142
|
+
"imagePullPolicy": "IfNotPresent",
|
143
|
+
"capabilities": {}
|
144
|
+
}
|
145
|
+
],
|
146
|
+
"restartPolicy": "Always",
|
147
|
+
"dnsPolicy": "ClusterFirst",
|
148
|
+
"host": "jimmi-redhat.localnet"
|
149
|
+
},
|
150
|
+
"status": {
|
151
|
+
"phase": "Running",
|
152
|
+
"Condition": [
|
153
|
+
{
|
154
|
+
"type": "Ready",
|
155
|
+
"status": "True"
|
156
|
+
}
|
157
|
+
],
|
158
|
+
"hostIP": "172.17.42.1",
|
159
|
+
"podIP": "172.17.0.8",
|
160
|
+
"containerStatuses": [
|
161
|
+
{
|
162
|
+
"name": "fabric8-console-container",
|
163
|
+
"state": {
|
164
|
+
"running": {
|
165
|
+
"startedAt": "2015-05-08T09:22:44Z"
|
166
|
+
}
|
167
|
+
},
|
168
|
+
"lastState": {},
|
169
|
+
"ready": true,
|
170
|
+
"restartCount": 0,
|
171
|
+
"image": "fabric8/hawtio-kubernetes:latest",
|
172
|
+
"imageID": "docker://b2bd1a24a68356b2f30128e6e28e672c1ef92df0d9ec01ec0c7faea5d77d2303",
|
173
|
+
"containerID": "docker://49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459"
|
174
|
+
}
|
175
|
+
]
|
176
|
+
}
|
177
|
+
}
|
178
|
+
http_version:
|
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
|
228
|
+
recorded_with: VCR 2.9.3
|
@@ -112,8 +112,36 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
112
112
|
host: 'jimmi-redhat.localnet',
|
113
113
|
pod_name: 'fabric8-console-controller-98rqc',
|
114
114
|
container_name: 'fabric8-console-container',
|
115
|
-
|
116
|
-
|
115
|
+
namespace_name: 'default',
|
116
|
+
pod_id: 'c76927af-f563-11e4-b32d-54ee7527188d',
|
117
|
+
labels: {
|
118
|
+
component: 'fabric8Console'
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
test 'with docker & kubernetes metadata & namespace_id enabled' do
|
127
|
+
VCR.use_cassette('metadata_with_namespace_id') do
|
128
|
+
es = emit({}, '
|
129
|
+
kubernetes_url https://localhost:8443
|
130
|
+
watch false
|
131
|
+
cache_size 1
|
132
|
+
include_namespace_id true
|
133
|
+
')
|
134
|
+
expected_kube_metadata = {
|
135
|
+
docker: {
|
136
|
+
container_id: '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459'
|
137
|
+
},
|
138
|
+
kubernetes: {
|
139
|
+
host: 'jimmi-redhat.localnet',
|
140
|
+
pod_name: 'fabric8-console-controller-98rqc',
|
141
|
+
container_name: 'fabric8-console-container',
|
142
|
+
namespace_name: 'default',
|
143
|
+
namespace_id: '898268c8-4a36-11e5-9d81-42010af0194c',
|
144
|
+
pod_id: 'c76927af-f563-11e4-b32d-54ee7527188d',
|
117
145
|
labels: {
|
118
146
|
component: 'fabric8Console'
|
119
147
|
}
|
@@ -139,8 +167,8 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
139
167
|
host: 'jimmi-redhat.localnet',
|
140
168
|
pod_name: 'fabric8-console-controller-98rqc',
|
141
169
|
container_name: 'fabric8-console-container',
|
142
|
-
|
143
|
-
|
170
|
+
namespace_name: 'default',
|
171
|
+
pod_id: 'c76927af-f563-11e4-b32d-54ee7527188d',
|
144
172
|
labels: {
|
145
173
|
component: 'fabric8Console'
|
146
174
|
}
|
@@ -159,7 +187,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
159
187
|
kubernetes: {
|
160
188
|
pod_name: 'fabric8-console-controller-98rqc',
|
161
189
|
container_name: 'fabric8-console-container',
|
162
|
-
|
190
|
+
namespace_name: 'default',
|
163
191
|
}
|
164
192
|
}
|
165
193
|
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
@@ -180,7 +208,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
180
208
|
kubernetes: {
|
181
209
|
pod_name: 'fabric8-console-controller-98rqc',
|
182
210
|
container_name: 'fabric8-console-container',
|
183
|
-
|
211
|
+
namespace_name: 'default'
|
184
212
|
}
|
185
213
|
}
|
186
214
|
assert_equal(expected_kube_metadata, es.instance_variable_get(:@record_array)[0])
|
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.11.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: 2015-09-
|
11
|
+
date: 2015-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -225,6 +225,7 @@ files:
|
|
225
225
|
- test/cassettes/invalid_api_server_config.yml
|
226
226
|
- test/cassettes/kubernetes_docker_metadata.yml
|
227
227
|
- test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml
|
228
|
+
- test/cassettes/metadata_with_namespace_id.yml
|
228
229
|
- test/cassettes/non_kubernetes_docker_metadata.yml
|
229
230
|
- test/cassettes/valid_kubernetes_api_server.yml
|
230
231
|
- test/helper.rb
|
@@ -258,6 +259,7 @@ test_files:
|
|
258
259
|
- test/cassettes/invalid_api_server_config.yml
|
259
260
|
- test/cassettes/kubernetes_docker_metadata.yml
|
260
261
|
- test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml
|
262
|
+
- test/cassettes/metadata_with_namespace_id.yml
|
261
263
|
- test/cassettes/non_kubernetes_docker_metadata.yml
|
262
264
|
- test/cassettes/valid_kubernetes_api_server.yml
|
263
265
|
- test/helper.rb
|