fluent-plugin-label-router 0.1.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +103 -25
- data/fluent-plugin-label-router.gemspec +1 -1
- data/lib/fluent/plugin/out_label_router.rb +104 -30
- data/test/plugin/test_out_label_router.rb +153 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e7a22624dbabbce0daa1bcf3d6845bf15e377d9453a5e733ad6c91b1c9d886d5
|
4
|
+
data.tar.gz: 5cb0f6eed3e37706bd2f09c0f399acd4fb6dc714aadb7d9879309575904dccfe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1240df83181e1e6188121c48dbffc4fbe226c756064155e1457dd2478aae79d6740dcb5b403202fd2ef0d55b7850f1937e6aed9f414dc73615f24f5ae3e0f2a
|
7
|
+
data.tar.gz: 13093eb11d980427a8bc5540612da4bca7a199a6aa848c2054ec157a930b4db372cd6c6ceed4ec854f783e165bfe7448f6ad53add6409f150460b49f522ea1e4
|
data/README.md
CHANGED
@@ -32,7 +32,10 @@ $ bundle
|
|
32
32
|
|
33
33
|
## Configuration
|
34
34
|
|
35
|
-
The configuration builds from `<route>` sections.
|
35
|
+
The configuration builds from `<route>` sections. Each `route` section
|
36
|
+
can have several `<match>` statement. These statements computed in order and
|
37
|
+
positive (or in case of *negate true* negative) results break the evaluation.
|
38
|
+
We can say that the sections are coupled in a **lazy evaluation OR**.
|
36
39
|
|
37
40
|
```
|
38
41
|
<match example.tag**>
|
@@ -41,32 +44,88 @@ The configuration builds from `
|
|
41
44
|
...
|
42
45
|
</route>
|
43
46
|
<route>
|
44
|
-
|
47
|
+
<match>
|
48
|
+
...
|
49
|
+
</match>
|
50
|
+
<match> #Exclude
|
51
|
+
negate true
|
52
|
+
...
|
53
|
+
</match>
|
45
54
|
</route>
|
46
55
|
</match>
|
47
56
|
```
|
48
57
|
|
49
|
-
|
50
|
-
|
51
|
-
|
|
52
|
-
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
Configuration reference
|
59
|
+
|
60
|
+
| Parameter | Description | Type | Default |
|
61
|
+
|---------------|--------------------------------------------------------------------------------------------------------|---------|---------|
|
62
|
+
| emit_mode | Emit mode. If `batch`, the plugin will emit events per labels matched. Enum: record, batch | enum | batch |
|
63
|
+
| sticky_tags | Sticky tags will match only one record from an event stream. The same tag will be treated the same way | bool | true |
|
64
|
+
| default_route | If defined all non-matching record passes to this label. | string | "" |
|
65
|
+
| default_tag | If defined all non-matching record rewrited to this tag. (Can be used with label simoultanesly) | string | "" |
|
66
|
+
| \<route\> | Route the log if match with parameters defined | []route | nil |
|
67
|
+
|
68
|
+
#### \<route\>
|
69
|
+
| Parameter | Description | Type | Default |
|
70
|
+
|---------------|--------------------------------------------------------------------------------------------------------|---------|---------|
|
71
|
+
| @label | Route the matching record to the given `label` | string | "" |
|
72
|
+
| tag | Tag the matching record to the given `tag` | string | "" |
|
73
|
+
| \<match\> | List of match statements. Repeatable. | []match | nil |
|
74
|
+
|
75
|
+
|
76
|
+
#### \<match\>
|
77
|
+
| Parameter | Description | Type | Default |
|
78
|
+
|-----------------|-------------------------------------------------------------------------------|----------|----------|
|
79
|
+
| labels | Label definition to match record. Example: `app:nginx` | Hash | nil |
|
80
|
+
| namespaces | Comma separated list of namespaces. Ignored if left empty. | []string | nil |
|
81
|
+
| hosts | Comma separated list of hosts. Ignored if left empty. | []string | nil |
|
82
|
+
| container_names | Comma separated list of container names. Ignored if left empty. | []string | nil |
|
83
|
+
| negate | Negate the selector meaning to exclude matches | bool | false |
|
84
|
+
|
85
|
+
## Rules of thumb
|
86
|
+
|
87
|
+
1. Defining more than one namespace in `namespaces` inside a `match` statement
|
88
|
+
will check whether any of that namespaces matches.
|
89
|
+
|
90
|
+
2. Using `sticky_tags` means that only the **first** record will be analysed per `tag`.
|
91
|
+
Keep that in mind if you are ingesting traffic that is not unique on a per tag bases.
|
92
|
+
Fluentd and fluent-bit tail logs from Kubernetes are unique per container.
|
93
|
+
|
94
|
+
3. The plugin does not check if the configuration is valid so be careful to not define
|
95
|
+
statements like identical `match` statement with negate because the negate rule will never
|
96
|
+
be evaluated.
|
57
97
|
|
58
98
|
## Examples
|
59
99
|
|
60
|
-
### 1. Route specific `labels` and `
|
100
|
+
### 1. Route specific `labels` and `namespaces` to `@label` and new `tag`
|
61
101
|
Configuration to re-tag and re-label all logs from `default` namespace with label `app=nginx` and `env=dev`.
|
62
102
|
```
|
63
103
|
<match example.tag**>
|
64
104
|
@type label_router
|
65
105
|
<route>
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
106
|
+
@label @NGINX
|
107
|
+
tag new_tag
|
108
|
+
<match>
|
109
|
+
labels app:nginx,env:dev
|
110
|
+
namespaces default
|
111
|
+
</match>
|
112
|
+
</route>
|
113
|
+
</match>
|
114
|
+
```
|
115
|
+
|
116
|
+
### 2. Exclude specific `labels` and `namespaces`
|
117
|
+
Configuration to re-tag and re-label all logs that **not** from `default` namespace **and not** have labels `ap=nginx` and `env=dev`
|
118
|
+
```
|
119
|
+
<match example.tag**>
|
120
|
+
@type label_router
|
121
|
+
<route>
|
122
|
+
@label @NGINX
|
123
|
+
tag new_tag
|
124
|
+
<match>
|
125
|
+
negate true
|
126
|
+
labels app:nginx,env:dev
|
127
|
+
namespaces default
|
128
|
+
</match>
|
70
129
|
</route>
|
71
130
|
</match>
|
72
131
|
```
|
@@ -91,9 +150,11 @@ Only `labels`
|
|
91
150
|
<match example.tag**>
|
92
151
|
@type label_router
|
93
152
|
<route>
|
94
|
-
|
95
|
-
|
96
|
-
|
153
|
+
@label @NGINX
|
154
|
+
tag new_tag
|
155
|
+
<match>
|
156
|
+
labels app:nginx
|
157
|
+
</match>
|
97
158
|
</route>
|
98
159
|
</match>
|
99
160
|
```
|
@@ -102,9 +163,11 @@ Only `namespace`
|
|
102
163
|
<match example.tag**>
|
103
164
|
@type label_router
|
104
165
|
<route>
|
105
|
-
|
106
|
-
|
107
|
-
|
166
|
+
@label @NGINX
|
167
|
+
tag new_tag
|
168
|
+
<match>
|
169
|
+
namespaces default
|
170
|
+
</match>
|
108
171
|
</route>
|
109
172
|
</match>
|
110
173
|
```
|
@@ -112,16 +175,31 @@ Rewrite all
|
|
112
175
|
```
|
113
176
|
<match example.tag**>
|
114
177
|
@type label_router
|
115
|
-
<
|
116
|
-
|
117
|
-
|
118
|
-
</
|
178
|
+
<match>
|
179
|
+
@label @NGINX
|
180
|
+
tag new_tag
|
181
|
+
</match>
|
119
182
|
</match>
|
120
183
|
```
|
121
184
|
|
122
185
|
### 3. One of `@label` ot `tag` configuration should be specified
|
123
186
|
If you don't rewrite either of them fluent will **likely to crash** because it will reprocess the same messages again.
|
124
187
|
|
188
|
+
### 4. Default route/tag
|
189
|
+
|
190
|
+
Use `default_label` and/or `default_tag` to route non matching records.
|
191
|
+
|
192
|
+
```
|
193
|
+
<match example.tag**>
|
194
|
+
@type label_router
|
195
|
+
default_route @default_sink
|
196
|
+
<route>
|
197
|
+
...
|
198
|
+
</route>
|
199
|
+
</match>
|
200
|
+
```
|
201
|
+
|
202
|
+
|
125
203
|
## Copyright
|
126
204
|
|
127
205
|
* Copyright(c) 2019- Banzai Cloud
|
@@ -26,33 +26,77 @@ module Fluent
|
|
26
26
|
#record_accessor_create("log")
|
27
27
|
#record_accessor_create("$.key1.key2")
|
28
28
|
#record_accessor_create("$['key1'][0]['key2']")
|
29
|
+
desc "Emit mode. If `batch`, the plugin will emit events per labels matched."
|
30
|
+
config_param :emit_mode, :enum, list: [:record, :batch], default: :batch
|
31
|
+
desc "Sticky tags will match only one record from an event stream. The same tag will be treated the same way"
|
32
|
+
config_param :sticky_tags, :bool, default: true
|
33
|
+
desc "Default label to drain unmatched patterns"
|
34
|
+
config_param :default_route, :string, :default => ""
|
35
|
+
desc "Default tag to drain unmatched patterns"
|
36
|
+
config_param :default_tag, :string, :default => ""
|
29
37
|
|
30
38
|
config_section :route, param_name: :routes, multi: true do
|
31
|
-
desc "Label definition to match record. Example: app:nginx. You can specify more values as comma separated list: key1:value1,key2:value2"
|
32
|
-
config_param :labels, :hash, :default => {}
|
33
|
-
desc "Namespaces definition to filter the record. Ignored if left empty."
|
34
|
-
config_param :namespace, :string, :default => ""
|
35
39
|
desc "New @LABEL if selectors matched"
|
36
40
|
config_param :@label, :string, :default => nil
|
37
41
|
desc "New tag if selectors matched"
|
38
42
|
config_param :tag, :string, :default => ""
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
|
44
|
+
config_section :match, param_name: :matches, multi: true do
|
45
|
+
desc "Label definition to match record. Example: app:nginx. You can specify more values as comma separated list: key1:value1,key2:value2"
|
46
|
+
config_param :labels, :hash, :default => {}
|
47
|
+
desc "List of namespace definition to filter the record. Ignored if left empty."
|
48
|
+
config_param :namespaces, :array, :default => [], value_type: :string
|
49
|
+
desc "List of hosts definition to filter the record. Ignored if left empty."
|
50
|
+
config_param :hosts, :array, :default => [], value_type: :string
|
51
|
+
desc "List of container names definition to filter the record. Ignored if left empty."
|
52
|
+
config_param :container_names, :array, :default => [], value_type: :string
|
53
|
+
desc "Negate the selection making it an exclude"
|
54
|
+
config_param :negate, :bool, :default => false
|
55
|
+
end
|
43
56
|
end
|
44
57
|
|
45
58
|
class Route
|
46
|
-
def initialize(
|
59
|
+
def initialize(matches, tag, router)
|
47
60
|
@router = router
|
48
|
-
@
|
49
|
-
@namespace = namespace
|
61
|
+
@matches = matches
|
50
62
|
@tag = tag
|
51
63
|
end
|
52
64
|
|
53
|
-
|
54
|
-
|
55
|
-
|
65
|
+
# Evaluate selectors
|
66
|
+
# We evaluate <match> statements in order:
|
67
|
+
# 1. If match == true and negate == false -> return true
|
68
|
+
# 2. If match == true and negate == true -> return false
|
69
|
+
# 3. If match == false and negate == false -> continue
|
70
|
+
# 4. If match == false and negate == true -> continue
|
71
|
+
# There is no match at all -> return false
|
72
|
+
def match?(metadata)
|
73
|
+
@matches.each do |match|
|
74
|
+
if filter_select(match, metadata) and !match.negate
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
if filter_select(match, metadata) and match.negate
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns true if filter passes (filter match)
|
85
|
+
def filter_select(match, metadata)
|
86
|
+
# Break on container_name mismatch
|
87
|
+
unless match.hosts.empty? || match.hosts.include?(metadata[:host])
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
# Break on host mismatch
|
91
|
+
unless match.container_names.empty? || match.container_names.include?(metadata[:container])
|
92
|
+
return false
|
93
|
+
end
|
94
|
+
# Break if list of namespaces is not empty and does not include actual namespace
|
95
|
+
unless match.namespaces.empty? || match.namespaces.include?(metadata[:namespace])
|
96
|
+
return false
|
97
|
+
end
|
98
|
+
|
99
|
+
match_labels(metadata[:labels], match.labels)
|
56
100
|
end
|
57
101
|
|
58
102
|
def emit(tag, time, record)
|
@@ -70,29 +114,38 @@ module Fluent
|
|
70
114
|
@router.emit_stream(@tag, es)
|
71
115
|
end
|
72
116
|
end
|
117
|
+
|
73
118
|
def match_labels(input, match)
|
74
|
-
|
119
|
+
(match.to_a - input.to_a).empty?
|
75
120
|
end
|
76
121
|
end
|
77
122
|
|
78
123
|
def process(tag, es)
|
79
124
|
if @sticky_tags
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
125
|
+
@mutex.synchronize {
|
126
|
+
if @route_map.has_key?(tag)
|
127
|
+
# We already matched with this tag send events to the routers
|
128
|
+
@route_map[tag].each do |r|
|
129
|
+
r.emit_es(tag, es.dup)
|
130
|
+
end
|
131
|
+
return
|
84
132
|
end
|
85
|
-
|
86
|
-
end
|
133
|
+
}
|
87
134
|
end
|
88
135
|
event_stream = Hash.new {|h, k| h[k] = Fluent::MultiEventStream.new }
|
89
136
|
es.each do |time, record|
|
90
|
-
|
91
|
-
|
137
|
+
input_metadata = { labels: @access_to_labels.call(record).to_h,
|
138
|
+
namespace: @access_to_namespace.call(record).to_s,
|
139
|
+
container: @access_to_container_name.call(record).to_s,
|
140
|
+
host: @access_to_host.call(record).to_s}
|
141
|
+
orphan_record = true
|
92
142
|
@routers.each do |r|
|
93
|
-
if r.match?(
|
143
|
+
if r.match?(input_metadata)
|
144
|
+
orphan_record = false
|
94
145
|
if @sticky_tags
|
95
|
-
@
|
146
|
+
@mutex.synchronize {
|
147
|
+
@route_map[tag].add(r)
|
148
|
+
}
|
96
149
|
end
|
97
150
|
if @batch
|
98
151
|
event_stream[r].add(time, record)
|
@@ -101,25 +154,46 @@ module Fluent
|
|
101
154
|
end
|
102
155
|
end
|
103
156
|
end
|
104
|
-
if
|
105
|
-
|
106
|
-
|
157
|
+
if !@default_router.nil? && orphan_record
|
158
|
+
if @sticky_tags
|
159
|
+
@mutex.synchronize {
|
160
|
+
@route_map[tag].add(@default_router)
|
161
|
+
}
|
162
|
+
end
|
163
|
+
if @batch
|
164
|
+
event_stream[@default_router].add(time, record)
|
165
|
+
else
|
166
|
+
@default_router.emit(tag, time, record.dup)
|
107
167
|
end
|
108
168
|
end
|
109
169
|
end
|
170
|
+
if @batch
|
171
|
+
event_stream.each do |r, es|
|
172
|
+
r.emit_es(tag, es.dup)
|
173
|
+
end
|
174
|
+
end
|
110
175
|
end
|
111
176
|
|
112
177
|
def configure(conf)
|
113
178
|
super
|
114
|
-
@route_map = Hash.new { |h, k| h[k] =
|
179
|
+
@route_map = Hash.new { |h, k| h[k] = Set.new }
|
180
|
+
@mutex = Mutex.new
|
115
181
|
@routers = []
|
182
|
+
@default_router = nil
|
116
183
|
@routes.each do |rule|
|
117
184
|
route_router = event_emitter_router(rule['@label'])
|
118
|
-
|
185
|
+
puts rule
|
186
|
+
@routers << Route.new(rule.matches, rule.tag.to_s, route_router)
|
187
|
+
end
|
188
|
+
|
189
|
+
if @default_route != '' or @default_tag != ''
|
190
|
+
@default_router = Route.new(nil, @default_tag, event_emitter_router(@default_route))
|
119
191
|
end
|
120
192
|
|
121
193
|
@access_to_labels = record_accessor_create("$.kubernetes.labels")
|
122
194
|
@access_to_namespace = record_accessor_create("$.kubernetes.namespace_name")
|
195
|
+
@access_to_host = record_accessor_create("$.kubernetes.host")
|
196
|
+
@access_to_container_name = record_accessor_create("$.kubernetes.container_name")
|
123
197
|
|
124
198
|
@batch = @emit_mode == :batch
|
125
199
|
end
|
@@ -34,11 +34,88 @@ class LabelRouterOutputTest < Test::Unit::TestCase
|
|
34
34
|
d.configure(conf)
|
35
35
|
end
|
36
36
|
|
37
|
+
sub_test_case 'test_routing' do
|
38
|
+
test 'basic configuration' do
|
39
|
+
routing_conf = %(
|
40
|
+
<route>
|
41
|
+
<match>
|
42
|
+
labels app:app1
|
43
|
+
</match>
|
44
|
+
<match>
|
45
|
+
labels app2:app2
|
46
|
+
negate true
|
47
|
+
</match>
|
48
|
+
tag new_app_tag
|
49
|
+
</route>
|
50
|
+
<route>
|
51
|
+
<match>
|
52
|
+
labels app:app1
|
53
|
+
namespaces default,test
|
54
|
+
</match>
|
55
|
+
<match>
|
56
|
+
labels app:app2
|
57
|
+
namespaces system
|
58
|
+
negate true
|
59
|
+
</match>
|
60
|
+
tag new_app_tag
|
61
|
+
</route>
|
62
|
+
<route>
|
63
|
+
<match>
|
64
|
+
labels app:nginx
|
65
|
+
namespaces dev,sandbox
|
66
|
+
</match>
|
67
|
+
</route>
|
68
|
+
<route>
|
69
|
+
<match>
|
70
|
+
labels app:nginx
|
71
|
+
namespaces dev,sandbox
|
72
|
+
container_names mycontainer
|
73
|
+
</match>
|
74
|
+
</route>
|
75
|
+
)
|
76
|
+
d = Fluent::Test::Driver::BaseOwner.new(Fluent::Plugin::LabelRouterOutput)
|
77
|
+
d.configure(routing_conf)
|
78
|
+
|
79
|
+
r1 = Fluent::Plugin::LabelRouterOutput::Route.new(d.instance.routes[0].matches, d.instance.routes[0].tag,nil)
|
80
|
+
# Selector matched: GO
|
81
|
+
assert_equal(true, r1.match?(labels: { 'app' => 'app1' }, namespace: ''))
|
82
|
+
# Exclude match: NO GO
|
83
|
+
assert_equal(false, r1.match?(labels: { 'app' => 'app2' }, namespace: ''))
|
84
|
+
# Nothing matched: NO GO
|
85
|
+
assert_equal(false, r1.match?(labels: { 'app3' => 'app2' }, namespace: ''))
|
86
|
+
|
87
|
+
r2 = Fluent::Plugin::LabelRouterOutput::Route.new(d.instance.routes[1].matches, d.instance.routes[1].tag,nil)
|
88
|
+
# Match selector and namespace: GO
|
89
|
+
assert_equal(true, r2.match?(labels: { 'app' => 'app1' }, namespace: 'test'))
|
90
|
+
# Exclude via namespace
|
91
|
+
assert_equal(false, r2.match?(labels: { 'app' => 'app2' }, namespace: 'system'))
|
92
|
+
# Nothing matched: NO GO
|
93
|
+
assert_equal(false, r2.match?(labels: { 'app3' => 'app' }, namespace: 'system'))
|
94
|
+
|
95
|
+
r3 = Fluent::Plugin::LabelRouterOutput::Route.new(d.instance.routes[2].matches, d.instance.routes[2].tag,nil)
|
96
|
+
assert_equal(true, r3.match?(labels: { 'app' => 'nginx' }, namespace: 'dev'))
|
97
|
+
assert_equal(true, r3.match?(labels: { 'app' => 'nginx' }, namespace: 'sandbox'))
|
98
|
+
assert_equal(false, r3.match?(labels: { 'app' => 'nginx2' }, namespace: 'sandbox'))
|
99
|
+
|
100
|
+
r4 = Fluent::Plugin::LabelRouterOutput::Route.new(d.instance.routes[3].matches, d.instance.routes[3].tag,nil)
|
101
|
+
# Matching container name
|
102
|
+
assert_equal(true, r4.match?(labels: { 'app' => 'nginx' }, namespace: 'dev', container: 'mycontainer'))
|
103
|
+
# Missing container name is equal to wrong container
|
104
|
+
assert_equal(false, r4.match?(labels: { 'app' => 'nginx' }, namespace: 'sandbox'))
|
105
|
+
# Wrong container name
|
106
|
+
assert_equal(false, r4.match?(labels: { 'app' => 'nginx' }, namespace: 'dev', container: 'mycontainer2'))
|
107
|
+
# Wrong label but good namespace and container_name
|
108
|
+
assert_equal(false, r4.match?(labels: { 'app' => 'nginx2' }, namespace: 'sandbox', container_name: 'mycontainer2'))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
37
112
|
sub_test_case 'test_tag' do
|
38
113
|
test 'normal' do
|
39
114
|
CONFIG = %[
|
40
115
|
<route>
|
41
|
-
|
116
|
+
<match>
|
117
|
+
labels app:app1
|
118
|
+
</match>
|
42
119
|
tag new_app_tag
|
43
120
|
</route>
|
44
121
|
]
|
@@ -56,4 +133,79 @@ class LabelRouterOutputTest < Test::Unit::TestCase
|
|
56
133
|
assert_equal ["new_app_tag", event_time, {"kubernetes" => {"labels" => {"app" => "app1"} } }], events[0]
|
57
134
|
end
|
58
135
|
end
|
136
|
+
|
137
|
+
|
138
|
+
sub_test_case 'test_multiple_events_batched' do
|
139
|
+
test 'normal' do
|
140
|
+
conf = %[
|
141
|
+
<route>
|
142
|
+
<match>
|
143
|
+
</match>
|
144
|
+
</route>
|
145
|
+
]
|
146
|
+
event_time = event_time("2019-07-17 11:11:11 UTC")
|
147
|
+
d = create_driver(conf)
|
148
|
+
d.run(expect_emits: 1, expect_records: 2) do
|
149
|
+
d.feed("test", [
|
150
|
+
[event_time, {"kubernetes" => {} } ],
|
151
|
+
[event_time, {"kubernetes" => {} } ],
|
152
|
+
])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
sub_test_case 'test_default_router' do
|
158
|
+
test 'normal' do
|
159
|
+
CONFIG2 = %[
|
160
|
+
<route>
|
161
|
+
<match>
|
162
|
+
labels app:app1
|
163
|
+
</match>
|
164
|
+
tag new_app_tag
|
165
|
+
</route>
|
166
|
+
default_route @default
|
167
|
+
default_tag "new_tag"
|
168
|
+
]
|
169
|
+
event_time = event_time("2019-07-17 11:11:11 UTC")
|
170
|
+
d = create_driver(CONFIG2)
|
171
|
+
d.run() do
|
172
|
+
d.feed("test", [
|
173
|
+
[event_time, {"kubernetes" => {"labels" => {"app" => "app1"} } } ],
|
174
|
+
[event_time, {"kubernetes" => {"labels" => {"app" => "app2"} } } ],
|
175
|
+
])
|
176
|
+
end
|
177
|
+
events = d.events
|
178
|
+
|
179
|
+
assert_equal(2, events.size)
|
180
|
+
assert_equal ["new_app_tag", event_time, {"kubernetes" => {"labels" => {"app" => "app1"} } }], events[0]
|
181
|
+
assert_equal ["new_tag", event_time, {"kubernetes" => {"labels" => {"app" => "app2"} } }], events[1]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
sub_test_case 'test_empty_router' do
|
186
|
+
test 'normal' do
|
187
|
+
CONFIG3 = %[
|
188
|
+
<route>
|
189
|
+
tag new_app_tag
|
190
|
+
<match>
|
191
|
+
labels
|
192
|
+
namespaces
|
193
|
+
</match>
|
194
|
+
</route>
|
195
|
+
]
|
196
|
+
event_time = event_time("2019-07-17 11:11:11 UTC")
|
197
|
+
d = create_driver(CONFIG3)
|
198
|
+
d.run(default_tag: 'test') do
|
199
|
+
d.feed(event_time, {"kubernetes" => {"labels" => {"app" => "app1"} } } )
|
200
|
+
end
|
201
|
+
d.run(default_tag: 'test2') do
|
202
|
+
d.feed(event_time, {"kubernetes" => {"labels" => {"app" => "app2"} } } )
|
203
|
+
end
|
204
|
+
events = d.events
|
205
|
+
|
206
|
+
assert_equal(2, events.size)
|
207
|
+
assert_equal ["new_app_tag", event_time, {"kubernetes" => {"labels" => {"app" => "app1"} } }], events[0]
|
208
|
+
assert_equal ["new_app_tag", event_time, {"kubernetes" => {"labels" => {"app" => "app2"} } }], events[1]
|
209
|
+
end
|
210
|
+
end
|
59
211
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-label-router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Banzai Cloud
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -107,8 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
|
-
|
111
|
-
rubygems_version: 2.5.2.3
|
110
|
+
rubygems_version: 3.0.3
|
112
111
|
signing_key:
|
113
112
|
specification_version: 4
|
114
113
|
summary: Routing records based on Kubernetes labels.
|