logstash-mixin-ecs_compatibility_support 1.1.0-java → 1.2.0-java
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/CHANGELOG.md +6 -1
- data/README.md +19 -2
- data/lib/logstash/plugin_mixins/ecs_compatibility_support.rb +4 -0
- data/lib/logstash/plugin_mixins/ecs_compatibility_support/selector.rb +55 -6
- data/lib/logstash/plugin_mixins/ecs_compatibility_support/spec_helper.rb +3 -5
- data/spec/logstash/plugin_mixins/ecs_compatibility_support/selector_spec.rb +34 -0
- data/spec/logstash/plugin_mixins/ecs_compatibility_support/spec_helper_spec.rb +2 -2
- data/spec/logstash/plugin_mixins/ecs_compatibility_support_spec.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6ff73bf503783cc17b6fbc2ebebcf23398d52ffa01cfc2a9d397566833f9706
|
4
|
+
data.tar.gz: 69d950da27ad60c8fdb09a08e72f7a4ffce9ede7e85cad0bfb130854cf40a07b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5334c125b5e9b24567500ae94546b3acd5260d7f83232eaa173439d68e8d974ca294f4a3f5b0c33d0d760ac4d843ea67bcb920b0713f480848e6d5044a43895b
|
7
|
+
data.tar.gz: 3b5bddca9732f6f03f79d4bf8ebf0dbeedb120dd7b23703f68c7e8410f5896e7124e343a2a843ce0346eeee6463c02bf738d1add11fed102f7c12e4147707e8f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
-
# 1.
|
1
|
+
# 1.2.0
|
2
|
+
- Added support for resolution aliases, allowing a plugin that uses `ecs_select` to support multiple ECS versions with a single declaration.
|
3
|
+
|
4
|
+
# 1.1.0
|
5
|
+
- Added support for `ecs_select` helper, allowing plugins to declare mappings that are selected during plugin instantiation.
|
2
6
|
|
7
|
+
# 1.0.0
|
3
8
|
- Support Mixin for ensuring a plugin has an `ecs_compatibility` method that is configurable from an `ecs_compatibility` option that accepts the literal `disabled` or a v-prefixed integer representing a major ECS version (e.g., `v1`), using the implementation from Logstash core if available.
|
data/README.md
CHANGED
@@ -67,13 +67,13 @@ during initialization based on the instantiated plugin's effective
|
|
67
67
|
mappings, because it allows those mappings to be side-by-side where they are
|
68
68
|
unlikely to diverge and introduce bugs.
|
69
69
|
|
70
|
-
1. Add version `~>1.
|
70
|
+
1. Add version `~>1.2` of this gem as a runtime dependency of your Logstash plugin's `gemspec`:
|
71
71
|
|
72
72
|
~~~ ruby
|
73
73
|
Gem::Specification.new do |s|
|
74
74
|
# ...
|
75
75
|
|
76
|
-
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.
|
76
|
+
s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.2'
|
77
77
|
end
|
78
78
|
~~~
|
79
79
|
|
@@ -95,6 +95,20 @@ unlikely to diverge and introduce bugs.
|
|
95
95
|
whether that mode was explicitly defined for the plugin instance or implictly
|
96
96
|
defined by the pipeline in which the plugin is run.
|
97
97
|
|
98
|
+
You can also optionally provide an alias mapping, for when your plugin supports
|
99
|
+
multiple versions of ECS that are largely identical to each other. This can be
|
100
|
+
especially helpful when using `ecs_select`.
|
101
|
+
|
102
|
+
~~~ ruby
|
103
|
+
require 'logstash/plugin_mixins/ecs_compatibility_support'
|
104
|
+
|
105
|
+
class LogStash::Inputs::Foo < Logstash::Inputs::Base
|
106
|
+
include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1,:v8 => :v1)
|
107
|
+
|
108
|
+
# ...
|
109
|
+
end
|
110
|
+
~~~
|
111
|
+
|
98
112
|
3. As in the simple usage example, you can use the `ecs_compatibility` method.
|
99
113
|
|
100
114
|
But when supported versions are specified, you can also use the `ecs_select`
|
@@ -108,6 +122,9 @@ unlikely to diverge and introduce bugs.
|
|
108
122
|
end
|
109
123
|
~~~
|
110
124
|
|
125
|
+
If you initialized the mixin with an alias mapping, missing values will
|
126
|
+
be resolved by their alias.
|
127
|
+
|
111
128
|
NOTE: `ecs_select` should only be used during plugin initialization and
|
112
129
|
not during event-by-event processing.
|
113
130
|
|
@@ -101,6 +101,10 @@ module LogStash
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
+
##
|
105
|
+
# @override ECSCompatibilitySupport(*supported_versions, alias_map={})
|
106
|
+
# @param supported_versions [Array[Symbol]]: the supported ECS versions
|
107
|
+
# @param alias_map [Hash{Symbol=>Symbol}]: an optional mapping of aliases (keys) to supported version (values)
|
104
108
|
def self.ECSCompatibilitySupport(*supported_versions)
|
105
109
|
return ECSCompatibilitySupport if supported_versions.empty?
|
106
110
|
|
@@ -26,14 +26,31 @@ module LogStash
|
|
26
26
|
base.include(ECSCompatibilitySupport)
|
27
27
|
end
|
28
28
|
|
29
|
+
EMPTY_HASH = {}.freeze
|
30
|
+
private_constant :EMPTY_HASH
|
31
|
+
|
29
32
|
##
|
30
33
|
# @api private
|
31
34
|
# @see ECSCompatibilitySupport()
|
32
35
|
# @param ecs_modes_supported
|
33
|
-
def initialize(*
|
36
|
+
def initialize(*ecs_modes_and_optional_alias_map)
|
37
|
+
selector_module = self
|
38
|
+
|
39
|
+
alias_mapping = ecs_modes_and_optional_alias_map.last.kind_of?(Hash) ? ecs_modes_and_optional_alias_map.pop.dup.freeze : EMPTY_HASH
|
40
|
+
ecs_modes_supported = ecs_modes_and_optional_alias_map.dup
|
41
|
+
|
34
42
|
fail(ArgumentError, "one or more ecs_modes_supported required") if ecs_modes_supported.empty?
|
35
43
|
fail(ArgumentError, "ecs_modes_supported must only contain symbols") unless ecs_modes_supported.all? { |s| s.kind_of?(Symbol) }
|
36
44
|
|
45
|
+
fail(ArgumentError, "alias names must be symbols") unless alias_mapping.keys.all? { |v| v.kind_of?(Symbol) }
|
46
|
+
fail(ArgumentError, "alias targets must be symbols") unless alias_mapping.values.all? { |v| v.kind_of?(Symbol) }
|
47
|
+
fail(ArgumentError, "alias must not redefine") if alias_mapping.keys.any? {|v| ecs_modes_supported.include?(v) }
|
48
|
+
fail(ArgumentError, "alias map must not have circular references") if circular_references_present?(alias_mapping)
|
49
|
+
|
50
|
+
ecs_modes_supported |= alias_mapping.keys
|
51
|
+
|
52
|
+
fail(ArgumentError, "alias target doesn't exist") if alias_mapping.values.any? { |v| !ecs_modes_supported.include?(v) }
|
53
|
+
|
37
54
|
ecs_modes_supported.freeze
|
38
55
|
|
39
56
|
##
|
@@ -49,7 +66,7 @@ module LogStash
|
|
49
66
|
"Supported modes are: #{ecs_modes_supported}"
|
50
67
|
fail(LogStash::ConfigurationError, message)
|
51
68
|
end
|
52
|
-
@_ecs_select =
|
69
|
+
@_ecs_select = selector_module.state_for(effective_ecs_mode)
|
53
70
|
end
|
54
71
|
|
55
72
|
##
|
@@ -58,6 +75,13 @@ module LogStash
|
|
58
75
|
define_method(:ecs_select) { @_ecs_select }
|
59
76
|
|
60
77
|
define_singleton_method(:ecs_modes_supported) { ecs_modes_supported }
|
78
|
+
|
79
|
+
define_singleton_method(:state_for) do |selected_value|
|
80
|
+
unless ecs_modes_supported.include?(selected_value)
|
81
|
+
fail(NotImplementedError, "Unsupported state `#{selected_value}` (expected one of #{ecs_modes_supported})")
|
82
|
+
end
|
83
|
+
State.new(ecs_modes_supported, selected_value, alias_mapping)
|
84
|
+
end
|
61
85
|
end
|
62
86
|
|
63
87
|
##
|
@@ -66,6 +90,21 @@ module LogStash
|
|
66
90
|
"#{Selector}(#{ecs_modes_supported.join(',')})"
|
67
91
|
end
|
68
92
|
|
93
|
+
private
|
94
|
+
|
95
|
+
def circular_references_present?(alias_candidates)
|
96
|
+
alias_candidates.each do |candidate, target|
|
97
|
+
current = target
|
98
|
+
(alias_candidates.size + 1).times do
|
99
|
+
return true if current == candidate
|
100
|
+
break unless alias_candidates.include?(current)
|
101
|
+
current = alias_candidates.fetch(current)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
69
108
|
##
|
70
109
|
# A `State` contains the active mode and a list of all supported modes.
|
71
110
|
#
|
@@ -77,12 +116,15 @@ module LogStash
|
|
77
116
|
# @api private
|
78
117
|
class State
|
79
118
|
##
|
80
|
-
# @api private
|
119
|
+
# @api private -- Use Selector#state_for(current_value)
|
81
120
|
# @param supported_modes [Array<Symbol>]
|
82
121
|
# @param active_mode [Symbol]
|
83
|
-
def initialize(supported_modes, active_mode)
|
122
|
+
def initialize(supported_modes, active_mode, alias_map=EMPTY_HASH)
|
123
|
+
fail(ArgumentError, "invalid alias mapping") unless alias_map.flatten.all? {|v| supported_modes.include?(v) }
|
124
|
+
|
84
125
|
@supported_modes = supported_modes
|
85
126
|
@active_mode = active_mode
|
127
|
+
@alias_map = alias_map
|
86
128
|
end
|
87
129
|
|
88
130
|
attr_reader :active_mode
|
@@ -102,13 +144,20 @@ module LogStash
|
|
102
144
|
|
103
145
|
fail(ArgumentError, "at least one choice must be defined") if defined_choices.empty?
|
104
146
|
|
105
|
-
missing = @supported_modes - defined_choices.keys
|
147
|
+
missing = @supported_modes - (defined_choices.keys + @alias_map.keys)
|
106
148
|
fail(ArgumentError, "missing one or more required choice definition #{missing}") if missing.any?
|
107
149
|
|
108
150
|
unknown = defined_choices.keys - @supported_modes
|
109
151
|
fail(ArgumentError, "unknown choices #{unknown}; valid choices are #{@supported_modes}") if unknown.any?
|
110
152
|
|
111
|
-
|
153
|
+
# resolve aliases of missing choices
|
154
|
+
effective_mode = @active_mode
|
155
|
+
@alias_map.size.times do # theoretical upper limit of alias chain
|
156
|
+
break if defined_choices.include?(effective_mode)
|
157
|
+
effective_mode = @alias_map.fetch(effective_mode)
|
158
|
+
end
|
159
|
+
|
160
|
+
defined_choices.fetch(effective_mode)
|
112
161
|
end
|
113
162
|
alias_method :[], :value_from
|
114
163
|
end
|
@@ -28,15 +28,13 @@ module LogStash
|
|
28
28
|
# ~~~
|
29
29
|
module SpecHelper
|
30
30
|
def ecs_compatibility_matrix(*supported_modes,&block)
|
31
|
-
|
32
|
-
fail(ArgumentError, "ecs_compatibility_matrix(*supported_modes) requires one or more symbol supported_modes")
|
33
|
-
end
|
31
|
+
ecs_selector = Selector.new(*supported_modes)
|
34
32
|
|
35
|
-
|
33
|
+
ecs_selector.ecs_modes_supported.each do |active_mode|
|
36
34
|
context "`ecs_compatibility => #{active_mode}`" do
|
37
35
|
let(:ecs_compatibility) { active_mode }
|
38
36
|
|
39
|
-
ecs_select =
|
37
|
+
ecs_select = ecs_selector.state_for(active_mode)
|
40
38
|
instance_exec(ecs_select, &block)
|
41
39
|
end
|
42
40
|
end
|
@@ -34,6 +34,27 @@ describe LogStash::PluginMixins::ECSCompatibilitySupport::Selector do
|
|
34
34
|
expect(selector_mod.name).to include('v1')
|
35
35
|
end
|
36
36
|
end
|
37
|
+
it 'accepts an alias list' do
|
38
|
+
selector_mod = described_class.new(:disabled, :v1, :v8 => :v1)
|
39
|
+
aggregate_failures do
|
40
|
+
expect(selector_mod.ecs_modes_supported).to contain_exactly(:disabled, :v1, :v8)
|
41
|
+
expect(selector_mod.name).to include('disabled')
|
42
|
+
expect(selector_mod.name).to include('v1')
|
43
|
+
expect(selector_mod.name).to include('v8')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
it 'rejects alias list that doesnt resolve' do
|
47
|
+
expect { described_class.new(:disabled, :v1, :v8 => :v2) }.to raise_error(ArgumentError, /alias target/)
|
48
|
+
end
|
49
|
+
it 'rejects tight circular aliases' do
|
50
|
+
expect { described_class.new(:disabled, :v1, :v8 => :v8) }.to raise_error(ArgumentError, /circular/)
|
51
|
+
end
|
52
|
+
it 'rejects loose circular aliases' do
|
53
|
+
expect { described_class.new(:disabled, :v1, :v8 => :v7, :v7 => :v6, :v6 => :v8) }.to raise_error(ArgumentError, /circular/)
|
54
|
+
end
|
55
|
+
it 'rejects alias that redefines concrete definition' do
|
56
|
+
expect { described_class.new(:disabled, :v1, :v1 => :disabled) }.to raise_error(ArgumentError, /redefine/)
|
57
|
+
end
|
37
58
|
end
|
38
59
|
context 'included into a class' do
|
39
60
|
let(:ecs_compatibility_support) { LogStash::PluginMixins::ECSCompatibilitySupport }
|
@@ -111,6 +132,19 @@ describe LogStash::PluginMixins::ECSCompatibilitySupport::Selector do
|
|
111
132
|
it 'selects the correct effective value' do
|
112
133
|
expect(ecs_select[disabled: "nope", v1: "winner"]).to eq("winner")
|
113
134
|
end
|
135
|
+
context 'when aliases are given' do
|
136
|
+
let(:ecs_supported_modes) { [:disabled, :v1, :v8 => :v2, :v2 => :v1 ] }
|
137
|
+
let(:ecs_effective_mode) { :v8 }
|
138
|
+
it 'selects a given value' do
|
139
|
+
expect(ecs_select[disabled: "nope", v1: "nah", v8: "hooray"]).to eq("hooray")
|
140
|
+
end
|
141
|
+
it 'resolves the deepest alias of a missing value' do
|
142
|
+
expect(ecs_select[disabled: "sad-trombone", v1: "wahoo"]).to eq("wahoo")
|
143
|
+
end
|
144
|
+
it 'resolves the intermediate alias of a missing value' do
|
145
|
+
expect(ecs_select[disabled: "sad-trombone", v1: "oh-no", v2: "nice"]).to eq("nice")
|
146
|
+
end
|
147
|
+
end
|
114
148
|
end
|
115
149
|
end
|
116
150
|
end
|
@@ -6,14 +6,14 @@ require "logstash/plugin_mixins/ecs_compatibility_support/spec_helper"
|
|
6
6
|
|
7
7
|
describe LogStash::PluginMixins::ECSCompatibilitySupport::SpecHelper, :ecs_compatibility_support do
|
8
8
|
context '::ecs_compatibility_matrix(*modes)' do
|
9
|
-
ecs_compatibility_matrix(:disabled,:v1) do |ecs_select|
|
9
|
+
ecs_compatibility_matrix(:disabled,:v1,:v8 => :v1) do |ecs_select|
|
10
10
|
it("sets `ecs_compatibility` with the current active mode `#{ecs_select.active_mode}`") do
|
11
11
|
expect(ecs_compatibility).to eq(ecs_select.active_mode)
|
12
12
|
end
|
13
13
|
context 'the yielded value' do
|
14
14
|
subject { ecs_select }
|
15
15
|
it { is_expected.to be_a_kind_of LogStash::PluginMixins::ECSCompatibilitySupport::Selector::State }
|
16
|
-
its(:supported_modes) { is_expected.to contain_exactly(:disabled,:v1) }
|
16
|
+
its(:supported_modes) { is_expected.to contain_exactly(:disabled,:v1,:v8) }
|
17
17
|
its(:active_mode) { is_expected.to be ecs_compatibility }
|
18
18
|
end
|
19
19
|
end
|
@@ -155,5 +155,12 @@ describe 'LogStash::PluginMixins::ECSCompatibilitySupport()' do
|
|
155
155
|
expect(selector_module.ecs_modes_supported).to contain_exactly(:disabled,:v1)
|
156
156
|
end
|
157
157
|
end
|
158
|
+
context 'with symbol arguments and alias mapping' do
|
159
|
+
it 'returns a properly-configured LogStash::PluginMixins::ECSCompatibilitySupport::Selector' do
|
160
|
+
selector_module = LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1,:v8 => :v1)
|
161
|
+
expect(selector_module).to be_a_kind_of(LogStash::PluginMixins::ECSCompatibilitySupport::Selector)
|
162
|
+
expect(selector_module.ecs_modes_supported).to contain_exactly(:disabled,:v1,:v8)
|
163
|
+
end
|
164
|
+
end
|
158
165
|
end
|
159
166
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-mixin-ecs_compatibility_support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|