fluent-plugin-kubernetes_metadata_filter 2.5.2 → 2.6.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 +6 -6
- data/Gemfile.lock +43 -43
- data/fluent-plugin-kubernetes_metadata_filter.gemspec +3 -6
- data/lib/fluent/plugin/filter_kubernetes_metadata.rb +38 -59
- data/lib/fluent/plugin/kubernetes_metadata_common.rb +20 -46
- data/lib/fluent/plugin/kubernetes_metadata_watch_namespaces.rb +17 -12
- data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +33 -16
- data/test/helper.rb +17 -1
- data/test/plugin/test_cache_stats.rb +2 -5
- data/test/plugin/test_cache_strategy.rb +5 -8
- data/test/plugin/test_filter_kubernetes_metadata.rb +11 -10
- data/test/plugin/test_watch_namespaces.rb +90 -68
- data/test/plugin/test_watch_pods.rb +164 -135
- data/test/plugin/watch_test.rb +3 -10
- metadata +7 -28
@@ -16,6 +16,7 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
|
+
# TODO: this is mostly copy-paste from kubernetes_metadata_watch_pods.rb unify them
|
19
20
|
require_relative 'kubernetes_metadata_common'
|
20
21
|
|
21
22
|
module KubernetesMetadata
|
@@ -45,7 +46,7 @@ module KubernetesMetadata
|
|
45
46
|
@stats.bump(:namespace_watch_gone_errors)
|
46
47
|
log.info("410 Gone encountered. Restarting namespace watch to reset resource versions.", e)
|
47
48
|
namespace_watcher = nil
|
48
|
-
rescue
|
49
|
+
rescue => e
|
49
50
|
@stats.bump(:namespace_watch_failures)
|
50
51
|
if Thread.current[:namespace_watch_retry_count] < @watch_retry_max_times
|
51
52
|
# Instead of raising exceptions and crashing Fluentd, swallow
|
@@ -74,8 +75,8 @@ module KubernetesMetadata
|
|
74
75
|
end
|
75
76
|
|
76
77
|
def start_namespace_watch
|
77
|
-
|
78
|
-
rescue
|
78
|
+
get_namespaces_and_start_watcher
|
79
|
+
rescue => e
|
79
80
|
message = "start_namespace_watch: Exception encountered setting up " \
|
80
81
|
"namespace watch from Kubernetes API #{@apiVersion} endpoint " \
|
81
82
|
"#{@kubernetes_url}: #{e.message}"
|
@@ -89,16 +90,20 @@ module KubernetesMetadata
|
|
89
90
|
# starting from that resourceVersion.
|
90
91
|
def get_namespaces_and_start_watcher
|
91
92
|
options = {
|
92
|
-
resource_version: '0' # Fetch from API server
|
93
|
+
resource_version: '0' # Fetch from API server cache instead of etcd quorum read
|
93
94
|
}
|
94
95
|
namespaces = @client.get_namespaces(options)
|
95
|
-
namespaces.each do |namespace|
|
96
|
-
cache_key = namespace
|
96
|
+
namespaces[:items].each do |namespace|
|
97
|
+
cache_key = namespace[:metadata][:uid]
|
97
98
|
@namespace_cache[cache_key] = parse_namespace_metadata(namespace)
|
98
99
|
@stats.bump(:namespace_cache_host_updates)
|
99
100
|
end
|
100
|
-
|
101
|
+
|
102
|
+
# continue watching from most recent resourceVersion
|
103
|
+
options[:resource_version] = namespaces[:metadata][:resourceVersion]
|
104
|
+
|
101
105
|
watcher = @client.watch_namespaces(options)
|
106
|
+
reset_namespace_watch_retry_stats
|
102
107
|
watcher
|
103
108
|
end
|
104
109
|
|
@@ -112,13 +117,13 @@ module KubernetesMetadata
|
|
112
117
|
# Process a watcher notice and potentially raise an exception.
|
113
118
|
def process_namespace_watcher_notices(watcher)
|
114
119
|
watcher.each do |notice|
|
115
|
-
case notice
|
120
|
+
case notice[:type]
|
116
121
|
when 'MODIFIED'
|
117
122
|
reset_namespace_watch_retry_stats
|
118
|
-
cache_key = notice
|
123
|
+
cache_key = notice[:object][:metadata][:uid]
|
119
124
|
cached = @namespace_cache[cache_key]
|
120
125
|
if cached
|
121
|
-
@namespace_cache[cache_key] = parse_namespace_metadata(notice
|
126
|
+
@namespace_cache[cache_key] = parse_namespace_metadata(notice[:object])
|
122
127
|
@stats.bump(:namespace_cache_watch_updates)
|
123
128
|
else
|
124
129
|
@stats.bump(:namespace_cache_watch_misses)
|
@@ -129,12 +134,12 @@ module KubernetesMetadata
|
|
129
134
|
# deleted but still processing logs
|
130
135
|
@stats.bump(:namespace_cache_watch_deletes_ignored)
|
131
136
|
when 'ERROR'
|
132
|
-
if notice
|
137
|
+
if notice[:object] && notice[:object][:code] == 410
|
133
138
|
@stats.bump(:namespace_watch_gone_notices)
|
134
139
|
raise GoneError
|
135
140
|
else
|
136
141
|
@stats.bump(:namespace_watch_error_type_notices)
|
137
|
-
message = notice[
|
142
|
+
message = notice[:object][:message] if notice[:object] && notice[:object][:message]
|
138
143
|
raise "Error while watching namespaces: #{message}"
|
139
144
|
end
|
140
145
|
else
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
|
+
# TODO: this is mostly copy-paste from kubernetes_metadata_watch_namespaces.rb unify them
|
19
20
|
require_relative 'kubernetes_metadata_common'
|
20
21
|
|
21
22
|
module KubernetesMetadata
|
@@ -29,6 +30,7 @@ module KubernetesMetadata
|
|
29
30
|
# Fluent:ConfigError, so that users can inspect potential errors in
|
30
31
|
# the configuration.
|
31
32
|
pod_watcher = start_pod_watch
|
33
|
+
|
32
34
|
Thread.current[:pod_watch_retry_backoff_interval] = @watch_retry_interval
|
33
35
|
Thread.current[:pod_watch_retry_count] = 0
|
34
36
|
|
@@ -46,7 +48,7 @@ module KubernetesMetadata
|
|
46
48
|
@stats.bump(:pod_watch_gone_errors)
|
47
49
|
log.info("410 Gone encountered. Restarting pod watch to reset resource versions.", e)
|
48
50
|
pod_watcher = nil
|
49
|
-
rescue
|
51
|
+
rescue => e
|
50
52
|
@stats.bump(:pod_watch_failures)
|
51
53
|
if Thread.current[:pod_watch_retry_count] < @watch_retry_max_times
|
52
54
|
# Instead of raising exceptions and crashing Fluentd, swallow
|
@@ -76,7 +78,7 @@ module KubernetesMetadata
|
|
76
78
|
|
77
79
|
def start_pod_watch
|
78
80
|
get_pods_and_start_watcher
|
79
|
-
rescue
|
81
|
+
rescue => e
|
80
82
|
message = "start_pod_watch: Exception encountered setting up pod watch " \
|
81
83
|
"from Kubernetes API #{@apiVersion} endpoint " \
|
82
84
|
"#{@kubernetes_url}: #{e.message}"
|
@@ -90,19 +92,27 @@ module KubernetesMetadata
|
|
90
92
|
# from that resourceVersion.
|
91
93
|
def get_pods_and_start_watcher
|
92
94
|
options = {
|
93
|
-
resource_version: '0' # Fetch from API server
|
95
|
+
resource_version: '0' # Fetch from API server cache instead of etcd quorum read
|
94
96
|
}
|
95
97
|
if ENV['K8S_NODE_NAME']
|
96
98
|
options[:field_selector] = 'spec.nodeName=' + ENV['K8S_NODE_NAME']
|
97
99
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
if @last_seen_resource_version
|
101
|
+
options[:resource_version] = @last_seen_resource_version
|
102
|
+
else
|
103
|
+
pods = @client.get_pods(options)
|
104
|
+
pods[:items].each do |pod|
|
105
|
+
cache_key = pod[:metadata][:uid]
|
106
|
+
@cache[cache_key] = parse_pod_metadata(pod)
|
107
|
+
@stats.bump(:pod_cache_host_updates)
|
108
|
+
end
|
109
|
+
|
110
|
+
# continue watching from most recent resourceVersion
|
111
|
+
options[:resource_version] = pods[:metadata][:resourceVersion]
|
103
112
|
end
|
104
|
-
|
113
|
+
|
105
114
|
watcher = @client.watch_pods(options)
|
115
|
+
reset_pod_watch_retry_stats
|
106
116
|
watcher
|
107
117
|
end
|
108
118
|
|
@@ -116,16 +126,22 @@ module KubernetesMetadata
|
|
116
126
|
# Process a watcher notice and potentially raise an exception.
|
117
127
|
def process_pod_watcher_notices(watcher)
|
118
128
|
watcher.each do |notice|
|
119
|
-
|
129
|
+
# store version we processed to not reprocess it ... do not unset when there is no version in response
|
130
|
+
version = ( # TODO: replace with &.dig once we are on ruby 2.5+
|
131
|
+
notice[:object] && notice[:object][:metadata] && notice[:object][:metadata][:resourceVersion]
|
132
|
+
)
|
133
|
+
@last_seen_resource_version = version if version
|
134
|
+
|
135
|
+
case notice[:type]
|
120
136
|
when 'MODIFIED'
|
121
137
|
reset_pod_watch_retry_stats
|
122
|
-
cache_key = notice.object
|
138
|
+
cache_key = notice.dig(:object, :metadata, :uid)
|
123
139
|
cached = @cache[cache_key]
|
124
140
|
if cached
|
125
|
-
@cache[cache_key] = parse_pod_metadata(notice
|
141
|
+
@cache[cache_key] = parse_pod_metadata(notice[:object])
|
126
142
|
@stats.bump(:pod_cache_watch_updates)
|
127
|
-
elsif ENV['K8S_NODE_NAME'] == notice
|
128
|
-
@cache[cache_key] = parse_pod_metadata(notice
|
143
|
+
elsif ENV['K8S_NODE_NAME'] == notice[:object][:spec][:nodeName] then
|
144
|
+
@cache[cache_key] = parse_pod_metadata(notice[:object])
|
129
145
|
@stats.bump(:pod_cache_host_updates)
|
130
146
|
else
|
131
147
|
@stats.bump(:pod_cache_watch_misses)
|
@@ -136,12 +152,13 @@ module KubernetesMetadata
|
|
136
152
|
# deleted but still processing logs
|
137
153
|
@stats.bump(:pod_cache_watch_delete_ignored)
|
138
154
|
when 'ERROR'
|
139
|
-
if notice
|
155
|
+
if notice[:object] && notice[:object][:code] == 410
|
156
|
+
@last_seen_resource_version = nil # requested resourceVersion was too old, need to reset
|
140
157
|
@stats.bump(:pod_watch_gone_notices)
|
141
158
|
raise GoneError
|
142
159
|
else
|
143
160
|
@stats.bump(:pod_watch_error_type_notices)
|
144
|
-
message = notice[
|
161
|
+
message = notice[:object][:message] if notice[:object] && notice[:object][:message]
|
145
162
|
raise "Error while watching pods: #{message}"
|
146
163
|
end
|
147
164
|
else
|
data/test/helper.rb
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
|
+
require 'bundler/setup'
|
19
20
|
require 'codeclimate-test-reporter'
|
20
21
|
SimpleCov.start do
|
21
22
|
formatter SimpleCov::Formatter::MultiFormatter.new [
|
@@ -31,8 +32,14 @@ require 'fileutils'
|
|
31
32
|
require 'fluent/log'
|
32
33
|
require 'fluent/test'
|
33
34
|
require 'minitest/autorun'
|
34
|
-
require 'webmock/test_unit'
|
35
35
|
require 'vcr'
|
36
|
+
require 'ostruct'
|
37
|
+
require 'fluent/plugin/filter_kubernetes_metadata'
|
38
|
+
require 'fluent/test/driver/filter'
|
39
|
+
require 'kubeclient'
|
40
|
+
|
41
|
+
require 'webmock/test_unit'
|
42
|
+
WebMock.disable_net_connect!
|
36
43
|
|
37
44
|
VCR.configure do |config|
|
38
45
|
config.cassette_library_dir = 'test/cassettes'
|
@@ -62,3 +69,12 @@ def ipv6_enabled?
|
|
62
69
|
false
|
63
70
|
end
|
64
71
|
end
|
72
|
+
|
73
|
+
# TEST_NAME='foo' ruby test_file.rb to run a single test case
|
74
|
+
if ENV["TEST_NAME"]
|
75
|
+
(class << Test::Unit::TestCase; self; end).prepend(Module.new do
|
76
|
+
def test(name)
|
77
|
+
super if name == ENV["TEST_NAME"]
|
78
|
+
end
|
79
|
+
end)
|
80
|
+
end
|
@@ -17,12 +17,9 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
require_relative '../helper'
|
20
|
-
require 'fluent/plugin/kubernetes_metadata_stats'
|
21
|
-
require 'webmock/test_unit'
|
22
|
-
WebMock.disable_net_connect!
|
23
20
|
|
24
21
|
class KubernetesMetadataCacheStatsTest < Test::Unit::TestCase
|
25
|
-
|
22
|
+
|
26
23
|
test 'watch stats' do
|
27
24
|
require 'lru_redux'
|
28
25
|
stats = KubernetesMetadata::Stats.new
|
@@ -32,5 +29,5 @@ class KubernetesMetadataCacheStatsTest < Test::Unit::TestCase
|
|
32
29
|
|
33
30
|
assert_equal("stats - deleted: 2, missed: 1", stats.to_s)
|
34
31
|
end
|
35
|
-
|
32
|
+
|
36
33
|
end
|
@@ -17,11 +17,6 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
require_relative '../helper'
|
20
|
-
require_relative '../../lib/fluent/plugin/kubernetes_metadata_cache_strategy'
|
21
|
-
require_relative '../../lib/fluent/plugin/kubernetes_metadata_stats'
|
22
|
-
require 'lru_redux'
|
23
|
-
require 'webmock/test_unit'
|
24
|
-
WebMock.disable_net_connect!
|
25
20
|
|
26
21
|
class TestCacheStrategy
|
27
22
|
include KubernetesMetadata::CacheStrategy
|
@@ -38,9 +33,11 @@ class TestCacheStrategy
|
|
38
33
|
attr_accessor :stats, :cache, :id_cache, :namespace_cache, :allow_orphans
|
39
34
|
|
40
35
|
def fetch_pod_metadata(namespace_name, pod_name)
|
36
|
+
{}
|
41
37
|
end
|
42
38
|
|
43
39
|
def fetch_namespace_metadata(namespace_name)
|
40
|
+
{}
|
44
41
|
end
|
45
42
|
|
46
43
|
def log
|
@@ -56,7 +53,7 @@ class TestCacheStrategy
|
|
56
53
|
end
|
57
54
|
|
58
55
|
class KubernetesMetadataCacheStrategyTest < Test::Unit::TestCase
|
59
|
-
|
56
|
+
|
60
57
|
def setup
|
61
58
|
@strategy = TestCacheStrategy.new
|
62
59
|
@cache_key = 'some_long_container_id'
|
@@ -114,7 +111,7 @@ class KubernetesMetadataCacheStrategyTest < Test::Unit::TestCase
|
|
114
111
|
# we ever will have and should allow us to process all the deleted
|
115
112
|
# pod records
|
116
113
|
exp = {
|
117
|
-
'pod_id'=> @cache_key,
|
114
|
+
'pod_id'=> @cache_key,
|
118
115
|
'namespace_id'=> @namespace_uuid
|
119
116
|
}
|
120
117
|
@strategy.stub :fetch_pod_metadata, {} do
|
@@ -175,7 +172,7 @@ class KubernetesMetadataCacheStrategyTest < Test::Unit::TestCase
|
|
175
172
|
end
|
176
173
|
assert_equal({}, @strategy.get_pod_metadata(@cache_key,'namespace', 'pod', @time, batch_miss_cache))
|
177
174
|
end
|
178
|
-
|
175
|
+
|
179
176
|
test 'when metadata is not cached and no metadata can be fetched and allowing orphans for multiple records' do
|
180
177
|
# we should never see this since pod meta should not be retrievable
|
181
178
|
# unless the namespace exists
|
@@ -17,11 +17,6 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
require_relative '../helper'
|
20
|
-
require 'fluent/test/driver/filter'
|
21
|
-
require 'fluent/plugin/filter_kubernetes_metadata'
|
22
|
-
|
23
|
-
require 'webmock/test_unit'
|
24
|
-
WebMock.disable_net_connect!
|
25
20
|
|
26
21
|
class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
27
22
|
include Fluent
|
@@ -122,8 +117,8 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
122
117
|
secret_dir #{dir}
|
123
118
|
")
|
124
119
|
assert_equal(d.instance.kubernetes_url, "https://localhost:8443/api")
|
125
|
-
|
126
|
-
|
120
|
+
assert_nil(d.instance.ca_file, nil)
|
121
|
+
assert_nil(d.instance.bearer_token_file)
|
127
122
|
}
|
128
123
|
ensure
|
129
124
|
ENV['KUBERNETES_SERVICE_HOST'] = nil
|
@@ -769,9 +764,13 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
769
764
|
'CONTAINER_ID_FULL' => '49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed459',
|
770
765
|
'randomfield' => 'randomvalue'
|
771
766
|
}
|
772
|
-
VCR.use_cassettes([
|
773
|
-
|
774
|
-
|
767
|
+
VCR.use_cassettes([
|
768
|
+
{name: 'valid_kubernetes_api_server'},
|
769
|
+
{name: 'kubernetes_get_api_v1'},
|
770
|
+
{name: 'kubernetes_get_pod'},
|
771
|
+
{name: 'kubernetes_get_namespace_default'},
|
772
|
+
{name: 'metadata_from_tag_and_journald_fields'}
|
773
|
+
]) do
|
775
774
|
filtered = emit_with_tag(tag, msg, '
|
776
775
|
kubernetes_url https://localhost:8443
|
777
776
|
watch false
|
@@ -873,6 +872,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
873
872
|
assert_equal(expected_kube_metadata, filtered[0])
|
874
873
|
end
|
875
874
|
end
|
875
|
+
|
876
876
|
test 'with CONTAINER_NAME that does not match' do
|
877
877
|
tag = 'var.log.containers.junk4_junk5_junk6-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
|
878
878
|
msg = {
|
@@ -897,6 +897,7 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
897
897
|
assert_equal(expected_kube_metadata, filtered[0])
|
898
898
|
end
|
899
899
|
end
|
900
|
+
|
900
901
|
test 'with CONTAINER_NAME starts with k8s_ that does not match' do
|
901
902
|
tag = 'var.log.containers.junk4_junk5_junk6-49095a2894da899d3b327c5fde1e056a81376cc9a8f8b09a195f2a92bceed450.log'
|
902
903
|
msg = {
|
@@ -17,7 +17,6 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
require_relative '../helper'
|
20
|
-
require 'ostruct'
|
21
20
|
require_relative 'watch_test'
|
22
21
|
|
23
22
|
class WatchNamespacesTestTest < WatchTest
|
@@ -25,71 +24,72 @@ class WatchNamespacesTestTest < WatchTest
|
|
25
24
|
include KubernetesMetadata::WatchNamespaces
|
26
25
|
|
27
26
|
setup do
|
28
|
-
@initial =
|
29
|
-
'NamespaceList',
|
30
|
-
'123',
|
31
|
-
[
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
]
|
45
|
-
|
46
|
-
|
27
|
+
@initial = {
|
28
|
+
kind: 'NamespaceList',
|
29
|
+
metadata: {resourceVersion: '123'},
|
30
|
+
items: [
|
31
|
+
{
|
32
|
+
metadata: {
|
33
|
+
name: 'initial',
|
34
|
+
uid: 'initial_uid'
|
35
|
+
}
|
36
|
+
},
|
37
|
+
{
|
38
|
+
metadata: {
|
39
|
+
name: 'modified',
|
40
|
+
uid: 'modified_uid'
|
41
|
+
}
|
42
|
+
}
|
43
|
+
]
|
44
|
+
}
|
45
|
+
|
46
|
+
@created = {
|
47
47
|
type: 'CREATED',
|
48
48
|
object: {
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
metadata: {
|
50
|
+
name: 'created',
|
51
|
+
uid: 'created_uid'
|
52
|
+
}
|
53
53
|
}
|
54
|
-
|
55
|
-
@modified =
|
54
|
+
}
|
55
|
+
@modified = {
|
56
56
|
type: 'MODIFIED',
|
57
57
|
object: {
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
metadata: {
|
59
|
+
name: 'foo',
|
60
|
+
uid: 'modified_uid'
|
61
|
+
}
|
62
62
|
}
|
63
|
-
|
64
|
-
@deleted =
|
63
|
+
}
|
64
|
+
@deleted = {
|
65
65
|
type: 'DELETED',
|
66
66
|
object: {
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
metadata: {
|
68
|
+
name: 'deleteme',
|
69
|
+
uid: 'deleted_uid'
|
70
|
+
}
|
71
71
|
}
|
72
|
-
|
73
|
-
@error =
|
72
|
+
}
|
73
|
+
@error = {
|
74
74
|
type: 'ERROR',
|
75
75
|
object: {
|
76
|
-
|
76
|
+
message: 'some error message'
|
77
77
|
}
|
78
|
-
|
79
|
-
@gone =
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
78
|
+
}
|
79
|
+
@gone = {
|
80
|
+
type: 'ERROR',
|
81
|
+
object: {
|
82
|
+
code: 410,
|
83
|
+
kind: 'Status',
|
84
|
+
message: 'too old resource version: 123 (391079)',
|
85
|
+
metadata: {
|
86
|
+
name: 'gone',
|
87
|
+
namespace: 'gone',
|
88
|
+
uid: 'gone_uid'
|
89
|
+
},
|
90
|
+
reason: 'Gone'
|
91
|
+
}
|
92
|
+
}
|
93
93
|
end
|
94
94
|
|
95
95
|
test 'namespace list caches namespaces' do
|
@@ -148,30 +148,52 @@ class WatchNamespacesTestTest < WatchTest
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
151
|
-
test 'namespace watch
|
151
|
+
test 'namespace watch raises Fluent::UnrecoverableError when cannot re-establish connection to k8s API server' do
|
152
|
+
# Stub start_namespace_watch to simulate initial successful connection to API server
|
153
|
+
stub(self).start_namespace_watch
|
154
|
+
# Stub watch_namespaces to simluate not being able to set up watch connection to API server
|
155
|
+
stub(@client).watch_namespaces { raise }
|
156
|
+
@client.stub :get_namespaces, @initial do
|
157
|
+
assert_raise Fluent::UnrecoverableError do
|
158
|
+
set_up_namespace_thread
|
159
|
+
end
|
160
|
+
end
|
161
|
+
assert_equal(3, @stats[:namespace_watch_failures])
|
162
|
+
assert_equal(2, Thread.current[:namespace_watch_retry_count])
|
163
|
+
assert_equal(4, Thread.current[:namespace_watch_retry_backoff_interval])
|
164
|
+
assert_nil(@stats[:namespace_watch_error_type_notices])
|
165
|
+
end
|
166
|
+
|
167
|
+
test 'namespace watch resets watch retry count when exceptions are encountered and connection to k8s API server is re-established' do
|
152
168
|
@client.stub :get_namespaces, @initial do
|
153
169
|
@client.stub :watch_namespaces, [[@created, @exception_raised]] do
|
154
|
-
|
155
|
-
|
170
|
+
# Force the infinite watch loop to exit after 3 seconds. Verifies that
|
171
|
+
# no unrecoverable error was thrown during this period of time.
|
172
|
+
assert_raise Timeout::Error.new('execution expired') do
|
173
|
+
Timeout.timeout(3) do
|
174
|
+
set_up_namespace_thread
|
175
|
+
end
|
156
176
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
assert_nil(@stats[:namespace_watch_error_type_notices])
|
177
|
+
assert_operator(@stats[:namespace_watch_failures], :>=, 3)
|
178
|
+
assert_operator(Thread.current[:namespace_watch_retry_count], :<=, 1)
|
179
|
+
assert_operator(Thread.current[:namespace_watch_retry_backoff_interval], :<=, 1)
|
161
180
|
end
|
162
181
|
end
|
163
182
|
end
|
164
183
|
|
165
|
-
test 'namespace watch
|
184
|
+
test 'namespace watch resets watch retry count when error is received and connection to k8s API server is re-established' do
|
166
185
|
@client.stub :get_namespaces, @initial do
|
167
186
|
@client.stub :watch_namespaces, [@error] do
|
168
|
-
|
169
|
-
|
187
|
+
# Force the infinite watch loop to exit after 3 seconds. Verifies that
|
188
|
+
# no unrecoverable error was thrown during this period of time.
|
189
|
+
assert_raise Timeout::Error.new('execution expired') do
|
190
|
+
Timeout.timeout(3) do
|
191
|
+
set_up_namespace_thread
|
192
|
+
end
|
170
193
|
end
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
assert_equal(3, @stats[:namespace_watch_error_type_notices])
|
194
|
+
assert_operator(@stats[:namespace_watch_failures], :>=, 3)
|
195
|
+
assert_operator(Thread.current[:namespace_watch_retry_count], :<=, 1)
|
196
|
+
assert_operator(Thread.current[:namespace_watch_retry_backoff_interval], :<=, 1)
|
175
197
|
end
|
176
198
|
end
|
177
199
|
end
|