fluent-plugin-kubernetes_metadata_filter 3.6.0 → 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/Rakefile +3 -4
  4. data/lib/fluent/plugin/filter_kubernetes_metadata.rb +307 -278
  5. data/lib/fluent/plugin/kubernetes_metadata_cache_strategy.rb +15 -11
  6. data/lib/fluent/plugin/kubernetes_metadata_common.rb +38 -40
  7. data/lib/fluent/plugin/kubernetes_metadata_stats.rb +5 -7
  8. data/lib/fluent/plugin/kubernetes_metadata_test_api_adapter.rb +39 -36
  9. data/lib/fluent/plugin/kubernetes_metadata_watch_namespaces.rb +15 -12
  10. data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +18 -17
  11. metadata +4 -174
  12. data/.circleci/config.yml +0 -48
  13. data/.gitignore +0 -18
  14. data/.rubocop.yml +0 -57
  15. data/Gemfile +0 -9
  16. data/Gemfile.lock +0 -170
  17. data/fluent-plugin-kubernetes_metadata_filter.gemspec +0 -34
  18. data/lib/fluent/plugin/kubernetes_metadata_util.rb +0 -33
  19. data/test/cassettes/invalid_api_server_config.yml +0 -53
  20. data/test/cassettes/kubernetes_docker_metadata_annotations.yml +0 -205
  21. data/test/cassettes/kubernetes_docker_metadata_dotted_slashed_labels.yml +0 -197
  22. data/test/cassettes/kubernetes_get_api_v1.yml +0 -193
  23. data/test/cassettes/kubernetes_get_api_v1_using_token.yml +0 -195
  24. data/test/cassettes/kubernetes_get_namespace_default.yml +0 -72
  25. data/test/cassettes/kubernetes_get_namespace_default_using_token.yml +0 -71
  26. data/test/cassettes/kubernetes_get_pod.yml +0 -146
  27. data/test/cassettes/kubernetes_get_pod_container_init.yml +0 -145
  28. data/test/cassettes/kubernetes_get_pod_using_token.yml +0 -148
  29. data/test/cassettes/kubernetes_get_pod_with_ownerrefs.yml +0 -156
  30. data/test/cassettes/metadata_from_tag_and_journald_fields.yml +0 -153
  31. data/test/cassettes/metadata_from_tag_journald_and_kubernetes_fields.yml +0 -285
  32. data/test/cassettes/valid_kubernetes_api_server.yml +0 -55
  33. data/test/cassettes/valid_kubernetes_api_server_using_token.yml +0 -57
  34. data/test/helper.rb +0 -82
  35. data/test/plugin/test.token +0 -1
  36. data/test/plugin/test_cache_stats.rb +0 -33
  37. data/test/plugin/test_cache_strategy.rb +0 -194
  38. data/test/plugin/test_filter_kubernetes_metadata.rb +0 -851
  39. data/test/plugin/test_watch_namespaces.rb +0 -245
  40. data/test/plugin/test_watch_pods.rb +0 -344
  41. data/test/plugin/watch_test.rb +0 -76
@@ -22,361 +22,390 @@
22
22
  require_relative 'kubernetes_metadata_cache_strategy'
23
23
  require_relative 'kubernetes_metadata_common'
24
24
  require_relative 'kubernetes_metadata_stats'
25
- require_relative 'kubernetes_metadata_util'
26
25
  require_relative 'kubernetes_metadata_watch_namespaces'
27
26
  require_relative 'kubernetes_metadata_watch_pods'
28
27
 
29
28
  require 'fluent/plugin/filter'
30
29
  require 'resolv'
31
30
 
32
- module Fluent::Plugin
33
- class KubernetesMetadataFilter < Fluent::Plugin::Filter
34
- K8_POD_CA_CERT = 'ca.crt'
35
- K8_POD_TOKEN = 'token'
36
-
37
- include KubernetesMetadata::CacheStrategy
38
- include KubernetesMetadata::Common
39
- include KubernetesMetadata::WatchNamespaces
40
- include KubernetesMetadata::WatchPods
41
-
42
- Fluent::Plugin.register_filter('kubernetes_metadata', self)
43
-
44
- config_param :kubernetes_url, :string, default: nil
45
- config_param :cache_size, :integer, default: 1000
46
- config_param :cache_ttl, :integer, default: 60 * 60
47
- config_param :watch, :bool, default: true
48
- config_param :apiVersion, :string, default: 'v1'
49
- config_param :client_cert, :string, default: nil
50
- config_param :client_key, :string, default: nil
51
- config_param :ca_file, :string, default: nil
52
- config_param :verify_ssl, :bool, default: true
53
- config_param :open_timeout, :integer, default: 3
54
- config_param :read_timeout, :integer, default: 10
55
-
56
- REGEX_VAR_LOG_PODS = '(var\.log\.pods)\.(?<namespace>[^_]+)_(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<pod_uuid>[a-z0-9-]*)\.(?<container_name>.+)\..*\.log$'
57
- REGEX_VAR_LOG_CONTAINERS = '(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$'
58
-
59
- #tag_to_kubernetes_name_regexp which must include named capture groups:
60
- # namespace - The namespace in which the pod is deployed
61
- # pod_name - The pod name
62
- # container_name - The name of the container
63
- # pod_uuid (/var/log/pods) | docker_id (/var/log/containers) - Unique identifier used in caching of either pod_uuid or the container hash
64
- config_param :tag_to_kubernetes_name_regexp, :string, default: "(#{REGEX_VAR_LOG_PODS}|#{REGEX_VAR_LOG_CONTAINERS})"
65
-
66
- config_param :bearer_token_file, :string, default: nil
67
- config_param :secret_dir, :string, default: '/var/run/secrets/kubernetes.io/serviceaccount'
68
-
69
- config_param :annotation_match, :array, default: []
70
- config_param :stats_interval, :integer, default: 30
71
- config_param :allow_orphans, :bool, default: true
72
- config_param :orphaned_namespace_name, :string, default: '.orphaned'
73
- config_param :orphaned_namespace_id, :string, default: 'orphaned'
74
- config_param :lookup_from_k8s_field, :bool, default: true
75
- # if `ca_file` is for an intermediate CA, or otherwise we do not have the root CA and want
76
- # to trust the intermediate CA certs we do have, set this to `true` - this corresponds to
77
- # the openssl s_client -partial_chain flag and X509_V_FLAG_PARTIAL_CHAIN
78
- config_param :ssl_partial_chain, :bool, default: false
79
- config_param :skip_labels, :bool, default: false
80
- config_param :skip_pod_labels, :bool, default: false
81
- config_param :skip_namespace_labels, :bool, default: false
82
- config_param :skip_container_metadata, :bool, default: false
83
- config_param :skip_master_url, :bool, default: false
84
- config_param :skip_namespace_metadata, :bool, default: false
85
- config_param :include_ownerrefs_metadata, :bool, default: false
86
-
87
- # A classname in the form of Test::APIAdapter which will try
88
- # to be resolved from a relative named file 'test_api_adapter'
89
- config_param :test_api_adapter, :string, default: nil
90
-
91
- # The time interval in seconds for retry backoffs when watch connections fail.
92
- config_param :watch_retry_interval, :integer, default: 1
93
- # The base number of exponential backoff for retries.
94
- config_param :watch_retry_exponential_backoff_base, :integer, default: 2
95
- # The maximum number of times to retry pod and namespace watches.
96
- config_param :watch_retry_max_times, :integer, default: 10
97
-
98
- def fetch_pod_metadata(namespace_name, pod_name)
99
- log.trace("fetching pod metadata: #{namespace_name}/#{pod_name}")
100
- options = {
101
- resource_version: '0' # Fetch from API server cache instead of etcd quorum read
102
- }
103
- pod_object = @client.get_pod(pod_name, namespace_name, options)
104
- log.trace("raw metadata for #{namespace_name}/#{pod_name}: #{pod_object}")
105
- metadata = parse_pod_metadata(pod_object)
106
- @stats.bump(:pod_cache_api_updates)
107
- log.trace("parsed metadata for #{namespace_name}/#{pod_name}: #{metadata}")
108
- @cache[metadata['pod_id']] = metadata
31
+ module Fluent
32
+ module Plugin
33
+ class KubernetesMetadataFilter < Fluent::Plugin::Filter # rubocop:disable Metrics/ClassLength
34
+ K8_POD_CA_CERT = 'ca.crt'
35
+ K8_POD_TOKEN = 'token'
36
+
37
+ include KubernetesMetadata::CacheStrategy
38
+ include KubernetesMetadata::Common
39
+ include KubernetesMetadata::WatchNamespaces
40
+ include KubernetesMetadata::WatchPods
41
+
42
+ Fluent::Plugin.register_filter('kubernetes_metadata', self)
43
+
44
+ config_param :kubernetes_url, :string, default: nil
45
+ config_param :cache_size, :integer, default: 1000
46
+ config_param :cache_ttl, :integer, default: 60 * 60
47
+ config_param :ignore_nil, :integer, default: true
48
+ config_param :watch, :bool, default: true
49
+ config_param :apiVersion, :string, default: 'v1'
50
+ config_param :client_cert, :string, default: nil
51
+ config_param :client_key, :string, default: nil
52
+ config_param :ca_file, :string, default: nil
53
+ config_param :verify_ssl, :bool, default: true
54
+ config_param :open_timeout, :integer, default: 3
55
+ config_param :read_timeout, :integer, default: 10
56
+
57
+ REGEX_VAR_LOG_PODS = '(var\.log\.pods)\.(?<namespace>[^_]+)_(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<pod_uuid>[a-z0-9-]*)\.(?<container_name>.+)\..*\.log$' # rubocop:disable Layout/LineLength
58
+ REGEX_VAR_LOG_CONTAINERS = '(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$' # rubocop:disable Layout/LineLength
59
+
60
+ # tag_to_kubernetes_name_regexp which must include named capture groups:
61
+ # namespace - The namespace in which the pod is deployed
62
+ # pod_name - The pod name
63
+ # container_name - The name of the container
64
+ # pod_uuid (/var/log/pods) | docker_id (/var/log/containers) - Unique identifier used in caching of either
65
+ # pod_uuid or the container hash
66
+ config_param :tag_to_kubernetes_name_regexp, :string,
67
+ default: "(#{REGEX_VAR_LOG_PODS}|#{REGEX_VAR_LOG_CONTAINERS})"
68
+
69
+ config_param :bearer_token_file, :string, default: nil
70
+ config_param :secret_dir, :string, default: '/var/run/secrets/kubernetes.io/serviceaccount'
71
+
72
+ config_param :annotation_match, :array, default: []
73
+ config_param :stats_interval, :integer, default: 30
74
+ config_param :allow_orphans, :bool, default: true
75
+ config_param :orphaned_namespace_name, :string, default: '.orphaned'
76
+ config_param :orphaned_namespace_id, :string, default: 'orphaned'
77
+ config_param :lookup_from_k8s_field, :bool, default: true
78
+ # if `ca_file` is for an intermediate CA, or otherwise we do not have the root CA and want
79
+ # to trust the intermediate CA certs we do have, set this to `true` - this corresponds to
80
+ # the openssl s_client -partial_chain flag and X509_V_FLAG_PARTIAL_CHAIN
81
+ config_param :ssl_partial_chain, :bool, default: false
82
+ config_param :skip_labels, :bool, default: false
83
+ config_param :skip_pod_labels, :bool, default: false
84
+ config_param :skip_namespace_labels, :bool, default: false
85
+ config_param :skip_container_metadata, :bool, default: false
86
+ config_param :skip_master_url, :bool, default: false
87
+ config_param :skip_namespace_metadata, :bool, default: false
88
+ config_param :include_ownerrefs_metadata, :bool, default: false
89
+
90
+ # A classname in the form of Test::APIAdapter which will try
91
+ # to be resolved from a relative named file 'test_api_adapter'
92
+ config_param :test_api_adapter, :string, default: nil
93
+
94
+ # The time interval in seconds for retry backoffs when watch connections fail.
95
+ config_param :watch_retry_interval, :integer, default: 1
96
+ # The base number of exponential backoff for retries.
97
+ config_param :watch_retry_exponential_backoff_base, :integer, default: 2
98
+ # The maximum number of times to retry pod and namespace watches.
99
+ config_param :watch_retry_max_times, :integer, default: 10
100
+
101
+ def fetch_pod_metadata(namespace_name, pod_name) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
102
+ log.trace("fetching pod metadata: #{namespace_name}/#{pod_name}")
103
+ options = {
104
+ resource_version: '0' # Fetch from API server cache instead of etcd quorum read
105
+ }
106
+ pod_object = @client.get_pod(pod_name, namespace_name, options)
107
+ log.trace("raw metadata for #{namespace_name}/#{pod_name}: #{pod_object}")
108
+ metadata = parse_pod_metadata(pod_object)
109
+ @stats.bump(:pod_cache_api_updates)
110
+ log.trace("parsed metadata for #{namespace_name}/#{pod_name}: #{metadata}")
111
+ @cache[metadata['pod_id']] = metadata
109
112
  rescue KubeException => e
110
113
  if e.error_code == 401
111
114
  # recreate client to refresh token
112
115
  log.info("Encountered '401 Unauthorized' exception, recreating client to refresh token")
113
- create_client()
116
+ create_client
114
117
  elsif e.error_code == 404
115
- log.debug "Encountered '404 Not Found' exception, pod not found"
118
+ log.debug("Encountered '404 Not Found' exception, pod not found")
116
119
  @stats.bump(:pod_cache_api_nil_error)
117
120
  else
118
- log.error "Exception '#{e}' encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
121
+ log.error("Exception '#{e}' encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}") # rubocop:disable Layout/LineLength
119
122
  @stats.bump(:pod_cache_api_nil_error)
120
123
  end
121
124
  {}
122
125
  rescue StandardError => e
123
126
  @stats.bump(:pod_cache_api_nil_error)
124
- log.error "Exception '#{e}' encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
127
+ log.error("Exception '#{e}' encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}") # rubocop:disable Layout/LineLength
125
128
  {}
126
129
  end
127
130
 
128
- def dump_stats
129
- @curr_time = Time.now
130
- return if @curr_time.to_i - @prev_time.to_i < @stats_interval
131
+ def dump_stats # rubocop:disable Metrics/AbcSize
132
+ @curr_time = Time.now
133
+ return if @curr_time.to_i - @prev_time.to_i < @stats_interval
134
+
135
+ @prev_time = @curr_time
136
+ @stats.set(:pod_cache_size, @cache.count)
137
+ @stats.set(:namespace_cache_size, @namespace_cache.count) if @namespace_cache
138
+ log.info(@stats)
139
+ return unless log.level == Fluent::Log::LEVEL_TRACE
131
140
 
132
- @prev_time = @curr_time
133
- @stats.set(:pod_cache_size, @cache.count)
134
- @stats.set(:namespace_cache_size, @namespace_cache.count) if @namespace_cache
135
- log.info(@stats)
136
- if log.level == Fluent::Log::LEVEL_TRACE
137
141
  log.trace(" id cache: #{@id_cache.to_a}")
138
142
  log.trace(" pod cache: #{@cache.to_a}")
139
143
  log.trace("namespace cache: #{@namespace_cache.to_a}")
140
144
  end
141
- end
142
145
 
143
- def fetch_namespace_metadata(namespace_name)
144
- log.trace("fetching namespace metadata: #{namespace_name}")
145
- options = {
146
- resource_version: '0' # Fetch from API server cache instead of etcd quorum read
147
- }
148
- namespace_object = @client.get_namespace(namespace_name, nil, options)
149
- log.trace("raw metadata for #{namespace_name}: #{namespace_object}")
150
- metadata = parse_namespace_metadata(namespace_object)
151
- @stats.bump(:namespace_cache_api_updates)
152
- log.trace("parsed metadata for #{namespace_name}: #{metadata}")
153
- @namespace_cache[metadata['namespace_id']] = metadata
146
+ def fetch_namespace_metadata(namespace_name) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
147
+ log.trace("fetching namespace metadata: #{namespace_name}")
148
+ options = {
149
+ resource_version: '0' # Fetch from API server cache instead of etcd quorum read
150
+ }
151
+ namespace_object = @client.get_namespace(namespace_name, nil, options)
152
+ log.trace("raw metadata for #{namespace_name}: #{namespace_object}")
153
+ metadata = parse_namespace_metadata(namespace_object)
154
+ @stats.bump(:namespace_cache_api_updates)
155
+ log.trace("parsed metadata for #{namespace_name}: #{metadata}")
156
+ @namespace_cache[metadata['namespace_id']] = metadata
154
157
  rescue KubeException => e
155
158
  if e.error_code == 401
156
159
  # recreate client to refresh token
157
160
  log.info("Encountered '401 Unauthorized' exception, recreating client to refresh token")
158
- create_client()
161
+ create_client
159
162
  else
160
- log.error "Exception '#{e}' encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
163
+ log.error("Exception '#{e}' encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}") # rubocop:disable Layout/LineLength
161
164
  @stats.bump(:namespace_cache_api_nil_error)
162
165
  end
163
166
  {}
164
167
  rescue StandardError => e
165
168
  @stats.bump(:namespace_cache_api_nil_error)
166
- log.error "Exception '#{e}' encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}"
169
+ log.error("Exception '#{e}' encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}") # rubocop:disable Layout/LineLength
167
170
  {}
168
- end
171
+ end
169
172
 
170
- def initialize
171
- super
172
- @prev_time = Time.now
173
- @ssl_options = {}
174
- @auth_options = {}
175
- end
173
+ def initialize
174
+ super
175
+ @prev_time = Time.now
176
+ @ssl_options = {}
177
+ @auth_options = {}
178
+ end
176
179
 
177
- def configure(conf)
178
- super
180
+ def configure(conf) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
181
+ super
179
182
 
180
- require 'kubeclient'
181
- require 'lru_redux'
183
+ require 'kubeclient'
184
+ require 'lru_redux'
182
185
 
183
- @stats = KubernetesMetadata::Stats.new
184
- if @stats_interval <= 0
185
- @stats = KubernetesMetadata::NoOpStats.new
186
- self.define_singleton_method(:dump_stats) {}
187
- end
186
+ @stats = KubernetesMetadata::Stats.new
187
+ if @stats_interval <= 0
188
+ @stats = KubernetesMetadata::NoOpStats.new
189
+ define_singleton_method(:dump_stats) {} # rubocop:disable Lint/EmptyBlock
190
+ end
188
191
 
189
- if @cache_ttl < 0
190
- log.info 'Setting the cache TTL to :none because it was <= 0'
191
- @cache_ttl = :none
192
- end
192
+ if @cache_ttl < 0
193
+ log.info 'Setting the cache TTL to :none because it was <= 0'
194
+ @cache_ttl = :none
195
+ end
193
196
 
194
- # Caches pod/namespace UID tuples for a given container UID.
195
- @id_cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
197
+ # Caches pod/namespace UID tuples for a given container UID.
198
+ @id_cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl, @ignore_nil)
196
199
 
197
- # Use the container UID as the key to fetch a hash containing pod metadata
198
- @cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
200
+ # Use the container UID as the key to fetch a hash containing pod metadata
201
+ @cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl, @ignore_nil)
199
202
 
200
- # Use the namespace UID as the key to fetch a hash containing namespace metadata
201
- @namespace_cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl)
203
+ # Use the namespace UID as the key to fetch a hash containing namespace metadata
204
+ @namespace_cache = LruRedux::TTL::ThreadSafeCache.new(@cache_size, @cache_ttl, @ignore_nil)
202
205
 
203
- @tag_to_kubernetes_name_regexp_compiled = Regexp.compile(@tag_to_kubernetes_name_regexp)
206
+ @tag_to_kubernetes_name_regexp_compiled = Regexp.compile(@tag_to_kubernetes_name_regexp)
204
207
 
205
- # Use Kubernetes default service account if we're in a pod.
206
- if @kubernetes_url.nil?
207
- log.debug 'Kubernetes URL is not set - inspecting environ'
208
+ # Use Kubernetes default service account if we're in a pod.
209
+ if @kubernetes_url.nil?
210
+ log.debug('Kubernetes URL is not set - inspecting environ')
211
+ env_host = ENV['KUBERNETES_SERVICE_HOST']
212
+ env_port = ENV['KUBERNETES_SERVICE_PORT']
208
213
 
209
- env_host = ENV['KUBERNETES_SERVICE_HOST']
210
- env_port = ENV['KUBERNETES_SERVICE_PORT']
211
- if present?(env_host) && present?(env_port)
212
- if env_host =~ Resolv::IPv6::Regex
213
- # Brackets are needed around IPv6 addresses
214
- env_host = "[#{env_host}]"
214
+ if present?(env_host) && present?(env_port)
215
+ if Resolv::IPv6::Regex.match?(env_host)
216
+ # Brackets are needed around IPv6 addresses
217
+ env_host = "[#{env_host}]"
218
+ end
219
+ @kubernetes_url = "https://#{env_host}:#{env_port}/api"
220
+ log.debug("Kubernetes URL is now '#{@kubernetes_url}'")
221
+ else
222
+ log.debug('No Kubernetes URL could be found in config or environ')
215
223
  end
216
- @kubernetes_url = "https://#{env_host}:#{env_port}/api"
217
- log.debug "Kubernetes URL is now '#{@kubernetes_url}'"
218
- else
219
- log.debug 'No Kubernetes URL could be found in config or environ'
220
224
  end
221
- end
222
225
 
223
- # Use SSL certificate and bearer token from Kubernetes service account.
224
- if Dir.exist?(@secret_dir)
225
- log.debug "Found directory with secrets: #{@secret_dir}"
226
- ca_cert = File.join(@secret_dir, K8_POD_CA_CERT)
227
- pod_token = File.join(@secret_dir, K8_POD_TOKEN)
226
+ # Use SSL certificate and bearer token from Kubernetes service account.
227
+ if Dir.exist?(@secret_dir)
228
+ log.debug("Found directory with secrets: #{@secret_dir}")
229
+ ca_cert = File.join(@secret_dir, K8_POD_CA_CERT)
230
+ pod_token = File.join(@secret_dir, K8_POD_TOKEN)
228
231
 
229
- if !present?(@ca_file) && File.exist?(ca_cert)
230
- log.debug "Found CA certificate: #{ca_cert}"
231
- @ca_file = ca_cert
232
- end
232
+ if !present?(@ca_file) && File.exist?(ca_cert)
233
+ log.debug("Found CA certificate: #{ca_cert}")
234
+ @ca_file = ca_cert
235
+ end
233
236
 
234
- if !present?(@bearer_token_file) && File.exist?(pod_token)
235
- log.debug "Found pod token: #{pod_token}"
236
- @bearer_token_file = pod_token
237
+ if !present?(@bearer_token_file) && File.exist?(pod_token)
238
+ log.debug("Found pod token: #{pod_token}")
239
+ @bearer_token_file = pod_token
240
+ end
237
241
  end
238
- end
239
242
 
240
- if present?(@kubernetes_url)
241
- @ssl_options = {
242
- client_cert: present?(@client_cert) ? OpenSSL::X509::Certificate.new(File.read(@client_cert)) : nil,
243
- client_key: present?(@client_key) ? OpenSSL::PKey::RSA.new(File.read(@client_key)) : nil,
244
- ca_file: @ca_file,
245
- verify_ssl: @verify_ssl ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
246
- }
243
+ if present?(@kubernetes_url)
244
+ @ssl_options = {
245
+ client_cert: present?(@client_cert) ? OpenSSL::X509::Certificate.new(File.read(@client_cert)) : nil,
246
+ client_key: present?(@client_key) ? OpenSSL::PKey::RSA.new(File.read(@client_key)) : nil,
247
+ ca_file: @ca_file,
248
+ verify_ssl: @verify_ssl ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
249
+ }
250
+
251
+ if @ssl_partial_chain
252
+ # taken from the ssl.rb OpenSSL::SSL::SSLContext code for DEFAULT_CERT_STORE
253
+ require 'openssl'
254
+
255
+ ssl_store = OpenSSL::X509::Store.new
256
+ ssl_store.set_default_paths
257
+ flagval = if defined? OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
258
+ OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
259
+ else
260
+ # this version of ruby does not define OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
261
+ 0x80000
262
+ end
263
+ ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | flagval
264
+ @ssl_options[:cert_store] = ssl_store
265
+ end
247
266
 
248
- if @ssl_partial_chain
249
- # taken from the ssl.rb OpenSSL::SSL::SSLContext code for DEFAULT_CERT_STORE
250
- require 'openssl'
251
- ssl_store = OpenSSL::X509::Store.new
252
- ssl_store.set_default_paths
253
- flagval = if defined? OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
254
- OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
255
- else
256
- # this version of ruby does not define OpenSSL::X509::V_FLAG_PARTIAL_CHAIN
257
- 0x80000
258
- end
259
- ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | flagval
260
- @ssl_options[:cert_store] = ssl_store
261
- end
267
+ @auth_options[:bearer_token_file] = @bearer_token_file if present?(@bearer_token_file)
262
268
 
263
- if present?(@bearer_token_file)
264
- @auth_options[:bearer_token_file] = @bearer_token_file
265
- end
269
+ create_client
266
270
 
267
- create_client()
271
+ if @test_api_adapter
272
+ log.info "Extending client with test api adapter #{@test_api_adapter}"
273
+ @test_api_adapter = @test_api_adapter.gsub('::', '_')
274
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
275
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
276
+ .tr('-', '_')
277
+ .downcase
278
+ require_relative @test_api_adapter
279
+ @client.extend(eval(@test_api_adapter)) # rubocop:disable Security/Eval
280
+ end
268
281
 
269
- if @test_api_adapter
270
- log.info "Extending client with test api adaper #{@test_api_adapter}"
271
- require_relative @test_api_adapter.underscore
272
- @client.extend(eval(@test_api_adapter))
273
- end
282
+ begin
283
+ @client.api_valid?
284
+ rescue KubeException => e
285
+ raise Fluent::ConfigError, "Invalid Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}: #{e.message}"
286
+ end
274
287
 
275
- begin
276
- @client.api_valid?
277
- rescue KubeException => e
278
- raise Fluent::ConfigError, "Invalid Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}: #{e.message}"
279
- end
288
+ if @watch
289
+ if ENV['K8S_NODE_NAME'].nil? || ENV['K8S_NODE_NAME'].strip.empty?
290
+ log.warn("!! The environment variable 'K8S_NODE_NAME' is not set to the node name which can affect the API server and watch efficiency !!") # rubocop:disable Layout/LineLength
291
+ end
280
292
 
281
- if @watch
282
- if ENV['K8S_NODE_NAME'].nil? || ENV['K8S_NODE_NAME'].strip.empty?
283
- log.warn("!! The environment variable 'K8S_NODE_NAME' is not set to the node name which can affect the API server and watch efficiency !!")
284
- end
293
+ pod_thread = Thread.new(self, &:set_up_pod_thread)
294
+ pod_thread.abort_on_exception = true
285
295
 
286
- pod_thread = Thread.new(self, &:set_up_pod_thread)
287
- pod_thread.abort_on_exception = true
296
+ namespace_thread = Thread.new(self, &:set_up_namespace_thread)
297
+ namespace_thread.abort_on_exception = true
298
+ end
299
+ end
288
300
 
289
- namespace_thread = Thread.new(self, &:set_up_namespace_thread)
290
- namespace_thread.abort_on_exception = true
301
+ @annotations_regexps = []
302
+ @annotation_match.each do |regexp|
303
+ @annotations_regexps << Regexp.compile(regexp)
304
+ rescue RegexpError => e
305
+ log.error("Error: invalid regular expression in annotation_match: #{e}")
291
306
  end
292
307
  end
293
308
 
294
- @annotations_regexps = []
295
- @annotation_match.each do |regexp|
296
- @annotations_regexps << Regexp.compile(regexp)
297
- rescue RegexpError => e
298
- log.error "Error: invalid regular expression in annotation_match: #{e}"
309
+ def create_client # rubocop:disable Metrics/MethodLength
310
+ log.debug('Creating K8S client')
311
+ @client = nil
312
+ @client = Kubeclient::Client.new(
313
+ @kubernetes_url,
314
+ @apiVersion,
315
+ ssl_options: @ssl_options,
316
+ auth_options: @auth_options,
317
+ timeouts: {
318
+ open: @open_timeout,
319
+ read: @read_timeout
320
+ },
321
+ as: :parsed_symbolized
322
+ )
299
323
  end
300
- end
301
324
 
302
- def create_client()
303
- log.debug 'Creating K8S client'
304
- @client = nil
305
- @client = Kubeclient::Client.new(
306
- @kubernetes_url,
307
- @apiVersion,
308
- ssl_options: @ssl_options,
309
- auth_options: @auth_options,
310
- timeouts: {
311
- open: @open_timeout,
312
- read: @read_timeout
313
- },
314
- as: :parsed_symbolized
315
- )
316
- end
317
-
318
- def get_metadata_for_record(namespace_name, pod_name, container_name, cache_key, create_time, batch_miss_cache, docker_id)
319
- metadata = {
320
- 'docker' => { 'container_id' => "" },
321
- 'kubernetes' => {
322
- 'container_name' => container_name,
323
- 'namespace_name' => namespace_name,
324
- 'pod_name' => pod_name
325
+ def get_metadata_for_record(namespace_name, pod_name, container_name, cache_key, create_time, batch_miss_cache, # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/ParameterLists, Metrics/PerceivedComplexity
326
+ docker_id)
327
+ metadata = {
328
+ 'docker' => { 'container_id' => '' },
329
+ 'kubernetes' => {
330
+ 'container_name' => container_name,
331
+ 'namespace_name' => namespace_name,
332
+ 'pod_name' => pod_name
333
+ }
325
334
  }
326
- }
327
- metadata['docker']['container_id'] = docker_id unless docker_id.nil?
328
- container_cache_key = container_name
329
- if present?(@kubernetes_url)
330
- pod_metadata = get_pod_metadata(cache_key, namespace_name, pod_name, create_time, batch_miss_cache)
331
- if (pod_metadata.include? 'containers') && (pod_metadata['containers'].include? container_cache_key) && !@skip_container_metadata
332
- metadata['kubernetes']['container_image'] = pod_metadata['containers'][container_cache_key]['image']
333
- metadata['kubernetes']['container_image_id'] = pod_metadata['containers'][container_cache_key]['image_id'] unless pod_metadata['containers'][container_cache_key]['image_id'].empty?
334
- metadata['docker']['container_id'] = pod_metadata['containers'][container_cache_key]['containerID'] unless pod_metadata['containers'][container_cache_key]['containerID'].empty?
335
+ metadata['docker']['container_id'] = docker_id unless docker_id.nil?
336
+ container_cache_key = container_name
337
+ if present?(@kubernetes_url)
338
+ pod_metadata = get_pod_metadata(cache_key, namespace_name, pod_name, create_time, batch_miss_cache)
339
+ if (pod_metadata.include? 'containers') && (pod_metadata['containers'].include? container_cache_key) && !@skip_container_metadata # rubocop:disable Layout/LineLength
340
+ metadata['kubernetes']['container_image'] = pod_metadata['containers'][container_cache_key]['image']
341
+ unless pod_metadata['containers'][container_cache_key]['image_id'].empty?
342
+ metadata['kubernetes']['container_image_id'] =
343
+ pod_metadata['containers'][container_cache_key]['image_id']
344
+ end
345
+ unless pod_metadata['containers'][container_cache_key]['containerID'].empty?
346
+ metadata['docker']['container_id'] =
347
+ pod_metadata['containers'][container_cache_key]['containerID']
348
+ end
349
+ end
350
+ metadata['kubernetes'].merge!(pod_metadata) if pod_metadata
351
+ metadata['kubernetes'].delete('containers')
335
352
  end
336
-
337
- metadata['kubernetes'].merge!(pod_metadata) if pod_metadata
338
- metadata['kubernetes'].delete('containers')
339
- end
340
- metadata['kubernetes'].tap do |kube|
341
- kube.each_pair do |k,v|
342
- kube[k.dup] = v.dup
353
+ metadata['kubernetes'].tap do |kube|
354
+ kube.each_pair do |k, v|
355
+ kube[k.dup] = v.dup
356
+ end
343
357
  end
358
+ if metadata['docker'] && (metadata['docker']['container_id'].nil? || metadata['docker']['container_id'].empty?)
359
+ metadata.delete('docker')
360
+ end
361
+ metadata
344
362
  end
345
- metadata.delete('docker') if metadata['docker'] && (metadata['docker']['container_id'].nil? || metadata['docker']['container_id'].empty?)
346
- metadata
347
- end
348
363
 
349
- def filter(tag, time, record)
350
- tag_match_data = tag.match(@tag_to_kubernetes_name_regexp_compiled)
351
- batch_miss_cache = {}
352
- if tag_match_data
353
- cache_key = if tag_match_data.names.include?('pod_uuid') && !tag_match_data['pod_uuid'].nil?
354
- tag_match_data['pod_uuid']
355
- else
356
- tag_match_data['docker_id']
364
+ def filter(tag, time, record) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
365
+ tag_match_data = tag.match(@tag_to_kubernetes_name_regexp_compiled)
366
+ batch_miss_cache = {}
367
+ if tag_match_data
368
+ cache_key = if tag_match_data.names.include?('pod_uuid') && !tag_match_data['pod_uuid'].nil?
369
+ tag_match_data['pod_uuid']
370
+ else
371
+ tag_match_data['docker_id']
372
+ end
373
+ docker_id = tag_match_data.names.include?('docker_id') ? tag_match_data['docker_id'] : nil
374
+ metadata = get_metadata_for_record(
375
+ tag_match_data['namespace'],
376
+ tag_match_data['pod_name'],
377
+ tag_match_data['container_name'],
378
+ cache_key,
379
+ time,
380
+ batch_miss_cache,
381
+ docker_id
382
+ )
357
383
  end
358
- docker_id = tag_match_data.names.include?('docker_id') ? tag_match_data['docker_id'] : nil
359
- metadata = get_metadata_for_record(tag_match_data['namespace'], tag_match_data['pod_name'], tag_match_data['container_name'],
360
- cache_key, time, batch_miss_cache, docker_id)
361
- end
362
- if @lookup_from_k8s_field && record.key?('kubernetes') && record.key?('docker') &&
363
- record['kubernetes'].respond_to?(:has_key?) && record['docker'].respond_to?(:has_key?) &&
364
- record['kubernetes'].key?('namespace_name') &&
365
- record['kubernetes'].key?('pod_name') &&
366
- record['kubernetes'].key?('container_name') &&
367
- record['docker'].key?('container_id') &&
368
- (k_metadata = get_metadata_for_record(record['kubernetes']['namespace_name'], record['kubernetes']['pod_name'],
369
- record['kubernetes']['container_name'], record['docker']['container_id'],
370
- time, batch_miss_cache, record['docker']['container_id']))
371
- metadata = k_metadata
384
+ if @lookup_from_k8s_field && record.key?('kubernetes') && record.key?('docker') &&
385
+ record['kubernetes'].respond_to?(:has_key?) && record['docker'].respond_to?(:has_key?) &&
386
+ record['kubernetes'].key?('namespace_name') &&
387
+ record['kubernetes'].key?('pod_name') &&
388
+ record['kubernetes'].key?('container_name') &&
389
+ record['docker'].key?('container_id')
390
+ k_metadata = get_metadata_for_record(
391
+ record['kubernetes']['namespace_name'],
392
+ record['kubernetes']['pod_name'],
393
+ record['kubernetes']['container_name'],
394
+ record['docker']['container_id'],
395
+ time,
396
+ batch_miss_cache,
397
+ record['docker']['container_id']
398
+ )
399
+ metadata = k_metadata if k_metadata
400
+ end
401
+ dump_stats
402
+ metadata ? record.merge(metadata) : record
372
403
  end
373
- dump_stats
374
- metadata ? record.merge(metadata) : record
375
- end
376
404
 
377
- # copied from activesupport
378
- def present?(object)
379
- object.respond_to?(:empty?) ? !object.empty? : !!object
405
+ # copied from activesupport
406
+ def present?(object)
407
+ object.respond_to?(:empty?) ? !object.empty? : !!object
408
+ end
380
409
  end
381
410
  end
382
411
  end