fluent-plugin-kubernetes_metadata_filter 2.5.0 → 2.7.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/.circleci/config.yml +7 -7
- data/.rubocop.yml +57 -0
- data/Gemfile +4 -2
- data/Gemfile.lock +50 -42
- data/README.md +4 -2
- data/Rakefile +15 -11
- data/fluent-plugin-kubernetes_metadata_filter.gemspec +25 -27
- data/lib/fluent/plugin/filter_kubernetes_metadata.rb +110 -121
- data/lib/fluent/plugin/kubernetes_metadata_cache_strategy.rb +22 -18
- data/lib/fluent/plugin/kubernetes_metadata_common.rb +44 -63
- data/lib/fluent/plugin/kubernetes_metadata_stats.rb +6 -6
- data/lib/fluent/plugin/kubernetes_metadata_test_api_adapter.rb +68 -0
- data/lib/fluent/plugin/kubernetes_metadata_util.rb +53 -0
- data/lib/fluent/plugin/kubernetes_metadata_watch_namespaces.rb +75 -59
- data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +92 -64
- data/test/helper.rb +20 -2
- data/test/plugin/test_cache_stats.rb +10 -13
- data/test/plugin/test_cache_strategy.rb +158 -160
- data/test/plugin/test_filter_kubernetes_metadata.rb +366 -346
- data/test/plugin/test_utils.rb +56 -0
- data/test/plugin/test_watch_namespaces.rb +188 -125
- data/test/plugin/test_watch_pods.rb +282 -202
- data/test/plugin/watch_test.rb +14 -15
- metadata +49 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa36ffbcd940e1dbb15d59f6d1e331091aa44611fbbaf3e19f562dec80b8fa42
|
4
|
+
data.tar.gz: e9e3bc68ab9e2f5ed6e88ed42d609aa583d3a2fbe34cd1e10e826ad4a32b8f5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6fa67fa39f78c33377c5eab486d1cd4f24b38e5e81769a5a9e27c87c6002e5fecfe0f43da56302d798a31d69d83b14b9f56f684c0e2c729735669c0c9fa326db
|
7
|
+
data.tar.gz: 5c94737a18204e093672471b7f1b31221794a2aced8d5f65099aab1e97f1937635d4957b2f36406bf8ef43f4bd874e004a460a8b92ff7cc999299fa701d67f42
|
data/.circleci/config.yml
CHANGED
@@ -14,21 +14,21 @@ missingdeps: &missingdeps
|
|
14
14
|
sudo cp /tmp/sources.list /etc/apt/sources.list
|
15
15
|
sudo apt-get update
|
16
16
|
sudo apt-get install cmake libicu-dev libssl-dev
|
17
|
-
|
17
|
+
|
18
18
|
test: &test
|
19
19
|
name: Test bundle
|
20
|
-
command: bundle exec rake test
|
20
|
+
command: bundle exec rake test --trace
|
21
21
|
|
22
22
|
executors:
|
23
|
-
ruby-2-4:
|
24
|
-
docker:
|
25
|
-
- image: circleci/ruby:2.4.6
|
26
23
|
ruby-2-5:
|
27
24
|
docker:
|
28
25
|
- image: circleci/ruby:2.5.5
|
29
26
|
ruby-2-6:
|
30
27
|
docker:
|
31
28
|
- image: circleci/ruby:2.6.3
|
29
|
+
ruby-2-7:
|
30
|
+
docker:
|
31
|
+
- image: circleci/ruby:2.7.1
|
32
32
|
jobs:
|
33
33
|
"ruby-test":
|
34
34
|
parameters:
|
@@ -49,9 +49,9 @@ jobs:
|
|
49
49
|
workflows:
|
50
50
|
"test_multiple_ruby_versions":
|
51
51
|
jobs:
|
52
|
-
- ruby-test:
|
53
|
-
ruby-version: ruby-2-4
|
54
52
|
- ruby-test:
|
55
53
|
ruby-version: ruby-2-5
|
56
54
|
- ruby-test:
|
57
55
|
ruby-version: ruby-2-6
|
56
|
+
- ruby-test:
|
57
|
+
ruby-version: ruby-2-7
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.5 # keep in sync with .circleci/config.yml and gemspec
|
3
|
+
NewCops: enable
|
4
|
+
|
5
|
+
Style/EmptyMethod:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
Metrics:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
# not safe ... needs require 'English'
|
12
|
+
Style/SpecialGlobalVars:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Layout/LineLength:
|
16
|
+
Max: 205 # TODO: lower
|
17
|
+
|
18
|
+
Style/Documentation:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Naming/AccessorMethodName:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Naming/MethodParameterName:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Style/IfInsideElse:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/GuardClause:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Lint/NestedMethodDefinition:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
# TODO: fix
|
37
|
+
Style/StringConcatenation:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Style/NumericPredicate:
|
41
|
+
EnforcedStyle: comparison
|
42
|
+
|
43
|
+
Style/IfUnlessModifier:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Style/ClassAndModuleChildren:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
# TODO: enable ... somehow breaks tests
|
50
|
+
Style/HashEachMethods:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Style/WordArray:
|
54
|
+
EnforcedStyle: brackets
|
55
|
+
|
56
|
+
Style/SymbolArray:
|
57
|
+
EnforcedStyle: brackets
|
data/Gemfile
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
|
-
gem 'codeclimate-test-reporter', '<1.0.0', :
|
4
|
-
gem 'rubocop'
|
5
|
+
gem 'codeclimate-test-reporter', '<1.0.0', group: :test, require: nil
|
6
|
+
gem 'rubocop'
|
5
7
|
|
6
8
|
# Specify your gem's dependencies in fluent-plugin-add.gemspec
|
7
9
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fluent-plugin-kubernetes_metadata_filter (2.
|
5
|
-
fluentd (>= 0.14.0, < 1.
|
4
|
+
fluent-plugin-kubernetes_metadata_filter (2.7.0)
|
5
|
+
fluentd (>= 0.14.0, < 1.13)
|
6
6
|
kubeclient (< 5)
|
7
7
|
lru_redux
|
8
8
|
|
@@ -12,36 +12,38 @@ GEM
|
|
12
12
|
addressable (2.7.0)
|
13
13
|
public_suffix (>= 2.0.2, < 5.0)
|
14
14
|
ast (2.4.1)
|
15
|
-
bump (0.
|
15
|
+
bump (0.10.0)
|
16
16
|
charlock_holmes (0.7.7)
|
17
17
|
codeclimate-test-reporter (0.6.0)
|
18
18
|
simplecov (>= 0.7.1, < 1.0.0)
|
19
|
-
concurrent-ruby (1.1.
|
20
|
-
cool.io (1.
|
19
|
+
concurrent-ruby (1.1.8)
|
20
|
+
cool.io (1.7.1)
|
21
21
|
copyright-header (1.0.22)
|
22
22
|
github-linguist
|
23
|
-
crack (0.4.
|
24
|
-
|
25
|
-
docile (1.3.
|
23
|
+
crack (0.4.5)
|
24
|
+
rexml
|
25
|
+
docile (1.3.5)
|
26
26
|
domain_name (0.5.20190701)
|
27
27
|
unf (>= 0.0.5, < 1.0.0)
|
28
28
|
escape_utils (1.2.1)
|
29
|
-
ffi (1.
|
29
|
+
ffi (1.15.0)
|
30
30
|
ffi-compiler (1.0.1)
|
31
31
|
ffi (>= 1.0.0)
|
32
32
|
rake
|
33
|
-
fluentd (1.
|
33
|
+
fluentd (1.12.3)
|
34
|
+
bundler
|
34
35
|
cool.io (>= 1.4.5, < 2.0.0)
|
35
36
|
http_parser.rb (>= 0.5.1, < 0.7.0)
|
36
37
|
msgpack (>= 1.3.1, < 2.0.0)
|
37
|
-
serverengine (>= 2.
|
38
|
+
serverengine (>= 2.2.2, < 3.0.0)
|
38
39
|
sigdump (~> 0.2.2)
|
39
40
|
strptime (>= 0.2.2, < 1.0.0)
|
40
41
|
tzinfo (>= 1.0, < 3.0)
|
41
42
|
tzinfo-data (~> 1.0)
|
43
|
+
webrick (>= 1.4.2, < 1.8.0)
|
42
44
|
yajl-ruby (~> 1.0)
|
43
|
-
github-linguist (7.
|
44
|
-
charlock_holmes (~> 0.7.
|
45
|
+
github-linguist (7.12.2)
|
46
|
+
charlock_holmes (~> 0.7.7)
|
45
47
|
escape_utils (~> 1.2.0)
|
46
48
|
mini_mime (~> 1.0)
|
47
49
|
rugged (>= 0.25.1)
|
@@ -55,77 +57,83 @@ GEM
|
|
55
57
|
http-cookie (1.0.3)
|
56
58
|
domain_name (~> 0.5)
|
57
59
|
http-form_data (2.3.0)
|
58
|
-
http-parser (1.2.
|
60
|
+
http-parser (1.2.3)
|
59
61
|
ffi-compiler (>= 1.0, < 2.0)
|
60
62
|
http_parser.rb (0.6.0)
|
61
|
-
|
63
|
+
jsonpath (1.1.0)
|
64
|
+
multi_json
|
65
|
+
kubeclient (4.9.1)
|
62
66
|
http (>= 3.0, < 5.0)
|
67
|
+
jsonpath (~> 1.0)
|
63
68
|
recursive-open-struct (~> 1.1, >= 1.1.1)
|
64
69
|
rest-client (~> 2.0)
|
65
70
|
lru_redux (1.1.0)
|
66
71
|
mime-types (3.3.1)
|
67
72
|
mime-types-data (~> 3.2015)
|
68
|
-
mime-types-data (3.
|
73
|
+
mime-types-data (3.2021.0225)
|
69
74
|
mini_mime (1.0.2)
|
70
75
|
minitest (4.7.5)
|
71
|
-
msgpack (1.
|
76
|
+
msgpack (1.4.2)
|
77
|
+
multi_json (1.15.0)
|
72
78
|
netrc (0.11.0)
|
73
|
-
parallel (1.
|
74
|
-
parser (
|
79
|
+
parallel (1.20.1)
|
80
|
+
parser (3.0.0.0)
|
75
81
|
ast (~> 2.4.1)
|
76
82
|
power_assert (1.2.0)
|
77
|
-
public_suffix (4.0.
|
83
|
+
public_suffix (4.0.6)
|
78
84
|
rainbow (3.0.0)
|
79
|
-
rake (13.0.
|
80
|
-
recursive-open-struct (1.1.
|
81
|
-
regexp_parser (
|
85
|
+
rake (13.0.3)
|
86
|
+
recursive-open-struct (1.1.3)
|
87
|
+
regexp_parser (2.0.3)
|
82
88
|
rest-client (2.1.0)
|
83
89
|
http-accept (>= 1.7.0, < 2.0)
|
84
90
|
http-cookie (>= 1.0.2, < 2.0)
|
85
91
|
mime-types (>= 1.16, < 4.0)
|
86
92
|
netrc (~> 0.8)
|
87
|
-
rexml (3.2.
|
93
|
+
rexml (3.2.5)
|
88
94
|
rr (1.2.1)
|
89
|
-
rubocop (
|
95
|
+
rubocop (1.8.1)
|
90
96
|
parallel (~> 1.10)
|
91
|
-
parser (>=
|
97
|
+
parser (>= 3.0.0.0)
|
92
98
|
rainbow (>= 2.2.2, < 4.0)
|
93
|
-
regexp_parser (>= 1.
|
99
|
+
regexp_parser (>= 1.8, < 3.0)
|
94
100
|
rexml
|
95
|
-
rubocop-ast (>=
|
101
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
96
102
|
ruby-progressbar (~> 1.7)
|
97
|
-
unicode-display_width (>= 1.4.0, <
|
98
|
-
rubocop-ast (
|
99
|
-
parser (>= 2.7.
|
100
|
-
ruby-progressbar (1.
|
101
|
-
rugged (1.0
|
102
|
-
|
103
|
-
serverengine (2.2.1)
|
103
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
104
|
+
rubocop-ast (1.4.0)
|
105
|
+
parser (>= 2.7.1.5)
|
106
|
+
ruby-progressbar (1.11.0)
|
107
|
+
rugged (1.1.0)
|
108
|
+
serverengine (2.2.3)
|
104
109
|
sigdump (~> 0.2.2)
|
105
110
|
sigdump (0.2.4)
|
106
|
-
simplecov (0.
|
111
|
+
simplecov (0.21.2)
|
107
112
|
docile (~> 1.1)
|
108
113
|
simplecov-html (~> 0.11)
|
109
|
-
|
110
|
-
|
114
|
+
simplecov_json_formatter (~> 0.1)
|
115
|
+
simplecov-html (0.12.3)
|
116
|
+
simplecov_json_formatter (0.1.2)
|
117
|
+
strptime (0.2.5)
|
111
118
|
test-unit (3.0.9)
|
112
119
|
power_assert
|
113
120
|
test-unit-rr (1.0.5)
|
114
121
|
rr (>= 1.1.1)
|
115
122
|
test-unit (>= 2.5.2)
|
116
|
-
tzinfo (2.0.
|
123
|
+
tzinfo (2.0.4)
|
117
124
|
concurrent-ruby (~> 1.0)
|
118
|
-
tzinfo-data (1.
|
125
|
+
tzinfo-data (1.2021.1)
|
119
126
|
tzinfo (>= 1.0.0)
|
120
127
|
unf (0.1.4)
|
121
128
|
unf_ext
|
122
129
|
unf_ext (0.0.7.7)
|
123
|
-
unicode-display_width (
|
130
|
+
unicode-display_width (2.0.0)
|
124
131
|
vcr (6.0.0)
|
125
|
-
webmock (3.
|
132
|
+
webmock (3.11.1)
|
126
133
|
addressable (>= 2.3.6)
|
127
134
|
crack (>= 0.3.2)
|
128
135
|
hashdiff (>= 0.4.0, < 2.0.0)
|
136
|
+
webrick (1.7.0)
|
129
137
|
yajl-ruby (1.4.1)
|
130
138
|
|
131
139
|
PLATFORMS
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
[](https://circleci.com/gh/fabric8io/fluent-plugin-kubernetes_metadata_filter)
|
3
3
|
[](https://codeclimate.com/github/fabric8io/fluent-plugin-kubernetes_metadata_filter)
|
4
4
|
[](https://codeclimate.com/github/fabric8io/fluent-plugin-kubernetes_metadata_filter)
|
5
|
+
[](https://github.com/rubocop-hq/rubocop)
|
6
|
+
[](https://rubystyle.guide)
|
5
7
|
|
6
8
|
The Kubernetes metadata plugin filter enriches container log records with pod and namespace metadata.
|
7
9
|
|
@@ -39,7 +41,7 @@ Configuration options for fluent.conf are:
|
|
39
41
|
* `client_key` - path to a client key file to authenticate to the API server
|
40
42
|
* `bearer_token_file` - path to a file containing the bearer token to use for authentication
|
41
43
|
* `tag_to_kubernetes_name_regexp` - the regular expression used to extract kubernetes metadata (pod name, container name, namespace) from the current fluentd tag.
|
42
|
-
This must used named capture groups for `container_name`, `pod_name` & `namespace`
|
44
|
+
This must used named capture groups for `container_name`, `pod_name` & `namespace` default: See [code](https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter/blob/master/lib/fluent/plugin/filter_kubernetes_metadata.rb#L52)
|
43
45
|
* `cache_size` - size of the cache of Kubernetes metadata to reduce requests to the API server (default: `1000`)
|
44
46
|
* `cache_ttl` - TTL in seconds of each cached element. Set to negative value to disable TTL eviction (default: `3600` - 1 hour)
|
45
47
|
* `watch` - set up a watch on pods on the API server for updates to metadata (default: `true`)
|
@@ -47,7 +49,7 @@ This must used named capture groups for `container_name`, `pod_name` & `namespac
|
|
47
49
|
* `de_dot_separator` - separator to use if `de_dot` is enabled (default: `_`)
|
48
50
|
* *DEPRECATED* `use_journal` - If false, 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. If unset (the default), the plugin will use the `CONTAINER_NAME` and `CONTAINER_ID_FULL` fields
|
49
51
|
if available, otherwise, will use the tag in the `tag_to_kubernetes_name_regexp` format.
|
50
|
-
* `container_name_to_kubernetes_regexp` - The regular expression used to extract the k8s metadata encoded in the journal `CONTAINER_NAME` field
|
52
|
+
* `container_name_to_kubernetes_regexp` - The regular expression used to extract the k8s metadata encoded in the journal `CONTAINER_NAME` field default: See [code](https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter/blob/master/lib/fluent/plugin/filter_kubernetes_metadata.rb#L68)
|
51
53
|
* This corresponds to the definition [in the source](https://github.com/kubernetes/kubernetes/blob/release-1.6/pkg/kubelet/dockertools/docker.go#L317)
|
52
54
|
* `annotation_match` - Array of regular expressions matching annotation field names. Matched annotations are added to a log record.
|
53
55
|
* `allow_orphans` - Modify the namespace and namespace id to the values of `orphaned_namespace_name` and `orphaned_namespace_id`
|
data/Rakefile
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
1
4
|
require 'bundler/gem_tasks'
|
2
5
|
require 'rake/testtask'
|
3
6
|
require 'bump/tasks'
|
7
|
+
require 'rubocop/rake_task'
|
4
8
|
|
5
|
-
task :
|
9
|
+
task test: [:base_test]
|
10
|
+
task default: [:test, :build, :rubocop]
|
6
11
|
|
7
|
-
|
12
|
+
RuboCop::RakeTask.new
|
8
13
|
|
9
14
|
desc 'Run test_unit based test'
|
10
15
|
Rake::TestTask.new(:base_test) do |t|
|
@@ -13,7 +18,6 @@ Rake::TestTask.new(:base_test) do |t|
|
|
13
18
|
# $ bundle exec rake base_test TEST=test/test_*.rb
|
14
19
|
t.libs << 'test'
|
15
20
|
t.test_files = Dir['test/**/test_*.rb'].sort
|
16
|
-
#t.verbose = true
|
17
21
|
t.warning = false
|
18
22
|
end
|
19
23
|
|
@@ -23,15 +27,15 @@ task :headers do
|
|
23
27
|
require 'copyright_header'
|
24
28
|
|
25
29
|
args = {
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
30
|
+
license: 'Apache-2.0',
|
31
|
+
copyright_software: 'Fluentd Kubernetes Metadata Filter Plugin',
|
32
|
+
copyright_software_description: 'Enrich Fluentd events with Kubernetes metadata',
|
33
|
+
copyright_holders: ['Red Hat, Inc.'],
|
34
|
+
copyright_years: ['2015-2021'],
|
35
|
+
add_path: 'lib:test',
|
36
|
+
output_dir: '.'
|
33
37
|
}
|
34
38
|
|
35
|
-
command_line = CopyrightHeader::CommandLine.new(
|
39
|
+
command_line = CopyrightHeader::CommandLine.new(args)
|
36
40
|
command_line.execute
|
37
41
|
end
|
@@ -1,36 +1,34 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
|
5
6
|
Gem::Specification.new do |gem|
|
6
|
-
gem.name =
|
7
|
-
gem.version =
|
8
|
-
gem.authors = [
|
9
|
-
gem.email = [
|
10
|
-
gem.description =
|
11
|
-
gem.summary =
|
12
|
-
gem.homepage =
|
13
|
-
gem.license =
|
7
|
+
gem.name = 'fluent-plugin-kubernetes_metadata_filter'
|
8
|
+
gem.version = '2.7.0'
|
9
|
+
gem.authors = ['Jimmi Dyson']
|
10
|
+
gem.email = ['jimmidyson@gmail.com']
|
11
|
+
gem.description = 'Filter plugin to add Kubernetes metadata'
|
12
|
+
gem.summary = 'Fluentd filter plugin to add Kubernetes metadata'
|
13
|
+
gem.homepage = 'https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter'
|
14
|
+
gem.license = 'Apache-2.0'
|
14
15
|
|
15
16
|
gem.files = `git ls-files`.split($/)
|
16
|
-
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
-
gem.require_paths = ["lib"]
|
19
17
|
|
20
|
-
gem.required_ruby_version = '>= 2.
|
18
|
+
gem.required_ruby_version = '>= 2.5.0'
|
21
19
|
|
22
|
-
gem.add_runtime_dependency 'fluentd', ['>= 0.14.0', '< 1.
|
23
|
-
gem.add_runtime_dependency
|
24
|
-
gem.add_runtime_dependency
|
20
|
+
gem.add_runtime_dependency 'fluentd', ['>= 0.14.0', '< 1.13']
|
21
|
+
gem.add_runtime_dependency 'kubeclient', '< 5'
|
22
|
+
gem.add_runtime_dependency 'lru_redux'
|
25
23
|
|
26
|
-
gem.add_development_dependency
|
27
|
-
gem.add_development_dependency
|
28
|
-
gem.add_development_dependency
|
29
|
-
gem.add_development_dependency
|
30
|
-
gem.add_development_dependency
|
31
|
-
gem.add_development_dependency
|
32
|
-
gem.add_development_dependency
|
33
|
-
gem.add_development_dependency
|
34
|
-
gem.add_development_dependency
|
35
|
-
gem.add_development_dependency
|
24
|
+
gem.add_development_dependency 'bump'
|
25
|
+
gem.add_development_dependency 'bundler', '~> 2.0'
|
26
|
+
gem.add_development_dependency 'copyright-header'
|
27
|
+
gem.add_development_dependency 'minitest', '~> 4.0'
|
28
|
+
gem.add_development_dependency 'rake'
|
29
|
+
gem.add_development_dependency 'test-unit', '~> 3.0.2'
|
30
|
+
gem.add_development_dependency 'test-unit-rr', '~> 1.0.3'
|
31
|
+
gem.add_development_dependency 'vcr'
|
32
|
+
gem.add_development_dependency 'webmock'
|
33
|
+
gem.add_development_dependency 'yajl-ruby'
|
36
34
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
#
|
2
4
|
# Fluentd Kubernetes Metadata Filter Plugin - Enrich Fluentd events with
|
3
5
|
# Kubernetes metadata
|
@@ -20,6 +22,7 @@
|
|
20
22
|
require_relative 'kubernetes_metadata_cache_strategy'
|
21
23
|
require_relative 'kubernetes_metadata_common'
|
22
24
|
require_relative 'kubernetes_metadata_stats'
|
25
|
+
require_relative 'kubernetes_metadata_util'
|
23
26
|
require_relative 'kubernetes_metadata_watch_namespaces'
|
24
27
|
require_relative 'kubernetes_metadata_watch_pods'
|
25
28
|
|
@@ -33,6 +36,7 @@ module Fluent::Plugin
|
|
33
36
|
|
34
37
|
include KubernetesMetadata::CacheStrategy
|
35
38
|
include KubernetesMetadata::Common
|
39
|
+
include KubernetesMetadata::Util
|
36
40
|
include KubernetesMetadata::WatchNamespaces
|
37
41
|
include KubernetesMetadata::WatchPods
|
38
42
|
|
@@ -49,7 +53,7 @@ module Fluent::Plugin
|
|
49
53
|
config_param :verify_ssl, :bool, default: true
|
50
54
|
config_param :tag_to_kubernetes_name_regexp,
|
51
55
|
:string,
|
52
|
-
:
|
56
|
+
default: 'var\.log\.containers\.(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace>[^_]+)_(?<container_name>.+)-(?<docker_id>[a-z0-9]{64})\.log$'
|
53
57
|
config_param :bearer_token_file, :string, default: nil
|
54
58
|
config_param :secret_dir, :string, default: '/var/run/secrets/kubernetes.io/serviceaccount'
|
55
59
|
config_param :de_dot, :bool, default: true
|
@@ -65,7 +69,7 @@ module Fluent::Plugin
|
|
65
69
|
# parse format is defined here: https://github.com/kubernetes/kubernetes/blob/release-1.6/pkg/kubelet/dockertools/docker.go#L317
|
66
70
|
config_param :container_name_to_kubernetes_regexp,
|
67
71
|
:string,
|
68
|
-
:
|
72
|
+
default: '^(?<name_prefix>[^_]+)_(?<container_name>[^\._]+)(\.(?<container_hash>[^_]+))?_(?<pod_name>[^_]+)_(?<namespace>[^_]+)_[^_]+_[^_]+$'
|
69
73
|
|
70
74
|
config_param :annotation_match, :array, default: []
|
71
75
|
config_param :stats_interval, :integer, default: 30
|
@@ -81,6 +85,11 @@ module Fluent::Plugin
|
|
81
85
|
config_param :skip_container_metadata, :bool, default: false
|
82
86
|
config_param :skip_master_url, :bool, default: false
|
83
87
|
config_param :skip_namespace_metadata, :bool, default: false
|
88
|
+
|
89
|
+
# A classname in the form of Test::APIAdapter which will try
|
90
|
+
# to be resolved from a relative named file 'test_api_adapter'
|
91
|
+
config_param :test_api_adapter, :string, default: nil
|
92
|
+
|
84
93
|
# The time interval in seconds for retry backoffs when watch connections fail.
|
85
94
|
config_param :watch_retry_interval, :integer, default: 1
|
86
95
|
# The base number of exponential backoff for retries.
|
@@ -90,35 +99,25 @@ module Fluent::Plugin
|
|
90
99
|
|
91
100
|
def fetch_pod_metadata(namespace_name, pod_name)
|
92
101
|
log.trace("fetching pod metadata: #{namespace_name}/#{pod_name}") if log.trace?
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
return metadata
|
106
|
-
rescue Exception=>e
|
107
|
-
log.debug(e)
|
108
|
-
@stats.bump(:pod_cache_api_nil_bad_resp_payload)
|
109
|
-
log.trace("returning empty metadata for #{namespace_name}/#{pod_name} due to error '#{e}'") if log.trace?
|
110
|
-
end
|
111
|
-
end
|
112
|
-
rescue Exception=>e
|
113
|
-
@stats.bump(:pod_cache_api_nil_error)
|
114
|
-
log.debug "Exception '#{e}' encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
|
115
|
-
end
|
102
|
+
options = {
|
103
|
+
resource_version: '0' # Fetch from API server cache instead of etcd quorum read
|
104
|
+
}
|
105
|
+
pod_object = @client.get_pod(pod_name, namespace_name, options)
|
106
|
+
log.trace("raw metadata for #{namespace_name}/#{pod_name}: #{pod_object}") if log.trace?
|
107
|
+
metadata = parse_pod_metadata(pod_object)
|
108
|
+
@stats.bump(:pod_cache_api_updates)
|
109
|
+
log.trace("parsed metadata for #{namespace_name}/#{pod_name}: #{metadata}") if log.trace?
|
110
|
+
@cache[metadata['pod_id']] = metadata
|
111
|
+
rescue StandardError => e
|
112
|
+
@stats.bump(:pod_cache_api_nil_error)
|
113
|
+
log.debug "Exception '#{e}' encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
|
116
114
|
{}
|
117
115
|
end
|
118
116
|
|
119
117
|
def dump_stats
|
120
118
|
@curr_time = Time.now
|
121
119
|
return if @curr_time.to_i - @prev_time.to_i < @stats_interval
|
120
|
+
|
122
121
|
@prev_time = @curr_time
|
123
122
|
@stats.set(:pod_cache_size, @cache.count)
|
124
123
|
@stats.set(:namespace_cache_size, @namespace_cache.count) if @namespace_cache
|
@@ -132,29 +131,18 @@ module Fluent::Plugin
|
|
132
131
|
|
133
132
|
def fetch_namespace_metadata(namespace_name)
|
134
133
|
log.trace("fetching namespace metadata: #{namespace_name}") if log.trace?
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
return metadata
|
148
|
-
rescue Exception => e
|
149
|
-
log.debug(e)
|
150
|
-
@stats.bump(:namespace_cache_api_nil_bad_resp_payload)
|
151
|
-
log.trace("returning empty metadata for #{namespace_name} due to error '#{e}'") if log.trace?
|
152
|
-
end
|
153
|
-
end
|
154
|
-
rescue Exception => kube_error
|
155
|
-
@stats.bump(:namespace_cache_api_nil_error)
|
156
|
-
log.debug "Exception '#{kube_error}' encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
|
157
|
-
end
|
134
|
+
options = {
|
135
|
+
resource_version: '0' # Fetch from API server cache instead of etcd quorum read
|
136
|
+
}
|
137
|
+
namespace_object = @client.get_namespace(namespace_name, nil, options)
|
138
|
+
log.trace("raw metadata for #{namespace_name}: #{namespace_object}") if log.trace?
|
139
|
+
metadata = parse_namespace_metadata(namespace_object)
|
140
|
+
@stats.bump(:namespace_cache_api_updates)
|
141
|
+
log.trace("parsed metadata for #{namespace_name}: #{metadata}") if log.trace?
|
142
|
+
@namespace_cache[metadata['namespace_id']] = metadata
|
143
|
+
rescue StandardError => e
|
144
|
+
@stats.bump(:namespace_cache_api_nil_error)
|
145
|
+
log.debug "Exception '#{e}' encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
|
158
146
|
{}
|
159
147
|
end
|
160
148
|
|
@@ -174,12 +162,12 @@ module Fluent::Plugin
|
|
174
162
|
require 'lru_redux'
|
175
163
|
@stats = KubernetesMetadata::Stats.new
|
176
164
|
|
177
|
-
if @de_dot &&
|
165
|
+
if @de_dot && @de_dot_separator.include?('.')
|
178
166
|
raise Fluent::ConfigError, "Invalid de_dot_separator: cannot be or contain '.'"
|
179
167
|
end
|
180
168
|
|
181
169
|
if @cache_ttl < 0
|
182
|
-
log.info
|
170
|
+
log.info 'Setting the cache TTL to :none because it was <= 0'
|
183
171
|
@cache_ttl = :none
|
184
172
|
end
|
185
173
|
|
@@ -197,11 +185,11 @@ module Fluent::Plugin
|
|
197
185
|
|
198
186
|
# Use Kubernetes default service account if we're in a pod.
|
199
187
|
if @kubernetes_url.nil?
|
200
|
-
log.debug
|
188
|
+
log.debug 'Kubernetes URL is not set - inspecting environ'
|
201
189
|
|
202
190
|
env_host = ENV['KUBERNETES_SERVICE_HOST']
|
203
191
|
env_port = ENV['KUBERNETES_SERVICE_PORT']
|
204
|
-
if
|
192
|
+
if present?(env_host) && present?(env_port)
|
205
193
|
if env_host =~ Resolv::IPv6::Regex
|
206
194
|
# Brackets are needed around IPv6 addresses
|
207
195
|
env_host = "[#{env_host}]"
|
@@ -209,7 +197,7 @@ module Fluent::Plugin
|
|
209
197
|
@kubernetes_url = "https://#{env_host}:#{env_port}/api"
|
210
198
|
log.debug "Kubernetes URL is now '#{@kubernetes_url}'"
|
211
199
|
else
|
212
|
-
log.debug
|
200
|
+
log.debug 'No Kubernetes URL could be found in config or environ'
|
213
201
|
end
|
214
202
|
end
|
215
203
|
|
@@ -219,24 +207,23 @@ module Fluent::Plugin
|
|
219
207
|
ca_cert = File.join(@secret_dir, K8_POD_CA_CERT)
|
220
208
|
pod_token = File.join(@secret_dir, K8_POD_TOKEN)
|
221
209
|
|
222
|
-
if
|
210
|
+
if !present?(@ca_file) && File.exist?(ca_cert)
|
223
211
|
log.debug "Found CA certificate: #{ca_cert}"
|
224
212
|
@ca_file = ca_cert
|
225
213
|
end
|
226
214
|
|
227
|
-
if
|
215
|
+
if !present?(@bearer_token_file) && File.exist?(pod_token)
|
228
216
|
log.debug "Found pod token: #{pod_token}"
|
229
217
|
@bearer_token_file = pod_token
|
230
218
|
end
|
231
219
|
end
|
232
220
|
|
233
|
-
if @kubernetes_url
|
234
|
-
|
221
|
+
if present?(@kubernetes_url)
|
235
222
|
ssl_options = {
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
223
|
+
client_cert: present?(@client_cert) ? OpenSSL::X509::Certificate.new(File.read(@client_cert)) : nil,
|
224
|
+
client_key: present?(@client_key) ? OpenSSL::PKey::RSA.new(File.read(@client_key)) : nil,
|
225
|
+
ca_file: @ca_file,
|
226
|
+
verify_ssl: @verify_ssl ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
240
227
|
}
|
241
228
|
|
242
229
|
if @ssl_partial_chain
|
@@ -244,39 +231,53 @@ module Fluent::Plugin
|
|
244
231
|
require 'openssl'
|
245
232
|
ssl_store = OpenSSL::X509::Store.new
|
246
233
|
ssl_store.set_default_paths
|
247
|
-
if defined? OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
234
|
+
flagval = if defined? OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
|
235
|
+
OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
|
236
|
+
else
|
237
|
+
# this version of ruby does not define OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
|
238
|
+
0x80000
|
239
|
+
end
|
253
240
|
ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | flagval
|
254
241
|
ssl_options[:cert_store] = ssl_store
|
255
242
|
end
|
256
243
|
|
257
244
|
auth_options = {}
|
258
245
|
|
259
|
-
if @bearer_token_file
|
246
|
+
if present?(@bearer_token_file)
|
260
247
|
bearer_token = File.read(@bearer_token_file)
|
261
248
|
auth_options[:bearer_token] = bearer_token
|
262
249
|
end
|
263
250
|
|
264
|
-
log.debug
|
265
|
-
@client = Kubeclient::Client.new
|
266
|
-
|
267
|
-
|
251
|
+
log.debug 'Creating K8S client'
|
252
|
+
@client = Kubeclient::Client.new(
|
253
|
+
@kubernetes_url,
|
254
|
+
@apiVersion,
|
255
|
+
ssl_options: ssl_options,
|
256
|
+
auth_options: auth_options,
|
257
|
+
as: :parsed_symbolized
|
258
|
+
)
|
259
|
+
|
260
|
+
if @test_api_adapter
|
261
|
+
log.info "Extending client with test api adaper #{@test_api_adapter}"
|
262
|
+
require_relative @test_api_adapter.underscore
|
263
|
+
@client.extend(eval(@test_api_adapter))
|
264
|
+
end
|
268
265
|
|
269
266
|
begin
|
270
267
|
@client.api_valid?
|
271
|
-
rescue KubeException =>
|
272
|
-
raise Fluent::ConfigError, "Invalid Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}: #{
|
268
|
+
rescue KubeException => e
|
269
|
+
raise Fluent::ConfigError, "Invalid Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}: #{e.message}"
|
273
270
|
end
|
274
271
|
|
275
272
|
if @watch
|
276
|
-
|
273
|
+
if ENV['K8S_NODE_NAME'].nil? || ENV['K8S_NODE_NAME'].strip.empty?
|
274
|
+
log.warn("!! The environment variable 'K8S_NODE_NAME' is not set to the node name which can affect the API server and watch efficiency !!")
|
275
|
+
end
|
276
|
+
|
277
|
+
pod_thread = Thread.new(self, &:set_up_pod_thread)
|
277
278
|
pod_thread.abort_on_exception = true
|
278
279
|
|
279
|
-
namespace_thread = Thread.new(self
|
280
|
+
namespace_thread = Thread.new(self, &:set_up_namespace_thread)
|
280
281
|
namespace_thread.abort_on_exception = true
|
281
282
|
end
|
282
283
|
end
|
@@ -287,25 +288,22 @@ module Fluent::Plugin
|
|
287
288
|
|
288
289
|
@annotations_regexps = []
|
289
290
|
@annotation_match.each do |regexp|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
log.error "Error: invalid regular expression in annotation_match: #{e}"
|
294
|
-
end
|
291
|
+
@annotations_regexps << Regexp.compile(regexp)
|
292
|
+
rescue RegexpError => e
|
293
|
+
log.error "Error: invalid regular expression in annotation_match: #{e}"
|
295
294
|
end
|
296
|
-
|
297
295
|
end
|
298
296
|
|
299
297
|
def get_metadata_for_record(namespace_name, pod_name, container_name, container_id, create_time, batch_miss_cache)
|
300
298
|
metadata = {
|
301
|
-
'docker' => {'container_id' => container_id},
|
299
|
+
'docker' => { 'container_id' => container_id },
|
302
300
|
'kubernetes' => {
|
303
|
-
'container_name'
|
304
|
-
'namespace_name'
|
305
|
-
'pod_name'
|
301
|
+
'container_name' => container_name,
|
302
|
+
'namespace_name' => namespace_name,
|
303
|
+
'pod_name' => pod_name
|
306
304
|
}
|
307
305
|
}
|
308
|
-
if @kubernetes_url
|
306
|
+
if present?(@kubernetes_url)
|
309
307
|
pod_metadata = get_pod_metadata(container_id, namespace_name, pod_name, create_time, batch_miss_cache)
|
310
308
|
|
311
309
|
if (pod_metadata.include? 'containers') && (pod_metadata['containers'].include? container_id) && !@skip_container_metadata
|
@@ -319,22 +317,9 @@ module Fluent::Plugin
|
|
319
317
|
metadata
|
320
318
|
end
|
321
319
|
|
322
|
-
def create_time_from_record(record, internal_time)
|
323
|
-
time_key = @time_fields.detect{ |ii| record.has_key?(ii) }
|
324
|
-
time = record[time_key]
|
325
|
-
if time.nil? || time.chop.empty?
|
326
|
-
# `internal_time` is a Fluent::EventTime, it can't compare with Time.
|
327
|
-
return Time.at(internal_time.to_f)
|
328
|
-
end
|
329
|
-
if ['_SOURCE_REALTIME_TIMESTAMP', '__REALTIME_TIMESTAMP'].include?(time_key)
|
330
|
-
timei= time.to_i
|
331
|
-
return Time.at(timei / 1000000, timei % 1000000)
|
332
|
-
end
|
333
|
-
return Time.parse(time)
|
334
|
-
end
|
335
|
-
|
336
320
|
def filter_stream(tag, es)
|
337
321
|
return es if (es.respond_to?(:empty?) && es.empty?) || !es.is_a?(Fluent::EventStream)
|
322
|
+
|
338
323
|
new_es = Fluent::MultiEventStream.new
|
339
324
|
tag_match_data = tag.match(@tag_to_kubernetes_name_regexp_compiled) unless @use_journal
|
340
325
|
tag_metadata = nil
|
@@ -342,23 +327,23 @@ module Fluent::Plugin
|
|
342
327
|
es.each do |time, record|
|
343
328
|
if tag_match_data && tag_metadata.nil?
|
344
329
|
tag_metadata = get_metadata_for_record(tag_match_data['namespace'], tag_match_data['pod_name'], tag_match_data['container_name'],
|
345
|
-
|
330
|
+
tag_match_data['docker_id'], create_time_from_record(record, time), batch_miss_cache)
|
346
331
|
end
|
347
332
|
metadata = Marshal.load(Marshal.dump(tag_metadata)) if tag_metadata
|
348
333
|
if (@use_journal || @use_journal.nil?) &&
|
349
|
-
|
334
|
+
(j_metadata = get_metadata_for_journal_record(record, time, batch_miss_cache))
|
350
335
|
metadata = j_metadata
|
351
336
|
end
|
352
|
-
if @lookup_from_k8s_field && record.
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
337
|
+
if @lookup_from_k8s_field && record.key?('kubernetes') && record.key?('docker') &&
|
338
|
+
record['kubernetes'].respond_to?(:has_key?) && record['docker'].respond_to?(:has_key?) &&
|
339
|
+
record['kubernetes'].key?('namespace_name') &&
|
340
|
+
record['kubernetes'].key?('pod_name') &&
|
341
|
+
record['kubernetes'].key?('container_name') &&
|
342
|
+
record['docker'].key?('container_id') &&
|
343
|
+
(k_metadata = get_metadata_for_record(record['kubernetes']['namespace_name'], record['kubernetes']['pod_name'],
|
344
|
+
record['kubernetes']['container_name'], record['docker']['container_id'],
|
345
|
+
create_time_from_record(record, time), batch_miss_cache))
|
346
|
+
metadata = k_metadata
|
362
347
|
end
|
363
348
|
|
364
349
|
record = record.merge(metadata) if metadata
|
@@ -370,16 +355,16 @@ module Fluent::Plugin
|
|
370
355
|
|
371
356
|
def get_metadata_for_journal_record(record, time, batch_miss_cache)
|
372
357
|
metadata = nil
|
373
|
-
if record.
|
358
|
+
if record.key?('CONTAINER_NAME') && record.key?('CONTAINER_ID_FULL')
|
374
359
|
metadata = record['CONTAINER_NAME'].match(@container_name_to_kubernetes_regexp_compiled) do |match_data|
|
375
360
|
get_metadata_for_record(match_data['namespace'], match_data['pod_name'], match_data['container_name'],
|
376
|
-
|
361
|
+
record['CONTAINER_ID_FULL'], create_time_from_record(record, time), batch_miss_cache)
|
377
362
|
end
|
378
363
|
unless metadata
|
379
364
|
log.debug "Error: could not match CONTAINER_NAME from record #{record}"
|
380
365
|
@stats.bump(:container_name_match_failed)
|
381
366
|
end
|
382
|
-
elsif record.
|
367
|
+
elsif record.key?('CONTAINER_NAME') && record['CONTAINER_NAME'].start_with?('k8s_')
|
383
368
|
log.debug "Error: no container name and id in record #{record}"
|
384
369
|
@stats.bump(:container_name_id_missing)
|
385
370
|
end
|
@@ -388,13 +373,17 @@ module Fluent::Plugin
|
|
388
373
|
|
389
374
|
def de_dot!(h)
|
390
375
|
h.keys.each do |ref|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
376
|
+
next unless h[ref] && ref =~ /\./
|
377
|
+
|
378
|
+
v = h.delete(ref)
|
379
|
+
newref = ref.to_s.gsub('.', @de_dot_separator)
|
380
|
+
h[newref] = v
|
396
381
|
end
|
397
382
|
end
|
398
383
|
|
384
|
+
# copied from activesupport
|
385
|
+
def present?(object)
|
386
|
+
object.respond_to?(:empty?) ? !object.empty? : !!object
|
387
|
+
end
|
399
388
|
end
|
400
389
|
end
|