logstash-mixin-ecs_compatibility_support 1.0.0-java → 1.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba10e5399ac0d62b035fb98cbb351e9e3c2cc857a25fa541a18998072e40b20c
4
- data.tar.gz: e303a40b0d20f12de4bf57639957c59f12ca30db8e568b99136863e2246e3480
3
+ metadata.gz: '08a8069171fd7a69e9adec65ef751e693ef6a3979e7d9b6346773f880d07a753'
4
+ data.tar.gz: 7ff7dc6c1bbabc1db323e253dc2c7e99bd7e08b701b59ce3e69bda5dc2c3012d
5
5
  SHA512:
6
- metadata.gz: 65f069880870f66b57b018108fad026d440d665a8fc06fc49c14aeeca1f3e8c4c93e1abfbb2227e2bb87a61a85d8c6bdf220c4efb093e4781f398f5c4334a6da
7
- data.tar.gz: 9281a716c7101934d7803baf628b165cfed31716517eeaa8043e585710cb8ade34799b47891ef5679cfaa1342bbc79c107a52187178edf1873c50b77f125624b
6
+ metadata.gz: 732274d0877f02583087f9181e862c8ce47c4eb8a8c8aba42557b5e149e3d17cfdabb5b23c240107c38194f730511f107084fe4d5ba2bd376fb56b36382ba811
7
+ data.tar.gz: d80b1895da371395f72dab57cb2cb61f858f68d9a0a001416ab7406ebb94c4ba9fbe74efeab7adc9e22ae7be50a2c58f7b628aa1c3de7e1bcac823a0cbd74865
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ECS Compatibility Support Mixin
2
2
 
3
- [![Build Status](https://travis-ci.org/logstash-plugins/logstash-mixin-ecs_compatibility_support.svg?branch=master)](https://travis-ci.org/logstash-plugins/logstash-mixin-ecs_compatibility_support)
3
+ [![Build Status](https://travis-ci.com/logstash-plugins/logstash-mixin-ecs_compatibility_support.svg?branch=master)](https://travis-ci.com/logstash-plugins/logstash-mixin-ecs_compatibility_support)
4
4
 
5
5
  This gem provides an API-compatible implementation of ECS-compatiblity mode,
6
6
  allowing plugins to be explicitly configured with `ecs_compatibility` in a way
@@ -8,7 +8,7 @@ that respects pipeline- and process-level settings where they are available.
8
8
  It can be added as a dependency of any plugin that wishes to implement one or
9
9
  more ECS-compatibility modes while still supporting older Logstash versions.
10
10
 
11
- ## Usage
11
+ ## Usage (simple)
12
12
 
13
13
  1. Add version `~>1.0` of this gem as a runtime dependency of your Logstash plugin's `gemspec`:
14
14
 
@@ -57,8 +57,62 @@ more ECS-compatibility modes while still supporting older Logstash versions.
57
57
  end
58
58
  ~~~
59
59
 
60
+ ## Usage (advanced)
61
+
62
+ Release 1.1 of this support gem includes support for constraining a plugin
63
+ to only operate in specified ECS-Compatibility modes, and advanced support for
64
+ runtime selectors that provide developers a way to provide alternate _values_
65
+ during initialization based on the instantiated plugin's effective
66
+ `ecs_compatibility` mode. This is helpful in plugins that define large field
67
+ mappings, because it allows those mappings to be side-by-side where they are
68
+ unlikely to diverge and introduce bugs.
69
+
70
+ 1. Add version `~>1.1` of this gem as a runtime dependency of your Logstash plugin's `gemspec`:
71
+
72
+ ~~~ ruby
73
+ Gem::Specification.new do |s|
74
+ # ...
75
+
76
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.1'
77
+ end
78
+ ~~~
79
+
80
+ 2. In your plugin code, require this library and include it into your plugin class
81
+ that already inherits `LogStash::Plugin`, but this time specify which versions
82
+ of ECS your plugin supports:
83
+
84
+ ~~~ ruby
85
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
86
+
87
+ class LogStash::Inputs::Foo < Logstash::Inputs::Base
88
+ include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1)
89
+
90
+ # ...
91
+ end
92
+ ~~~
93
+
94
+ This prevents the plugin from being instantiated with an unsupported mode,
95
+ whether that mode was explicitly defined for the plugin instance or implictly
96
+ defined by the pipeline in which the plugin is run.
97
+
98
+ 3. As in the simple usage example, you can use the `ecs_compatibility` method.
99
+
100
+ But when supported versions are specified, you can also use the `ecs_select`
101
+ method to define alternates in-line. At runtime, the correct value will be
102
+ selected based on the current effective `ecs_compatibility` mode.
103
+
104
+ ~~~ ruby
105
+ def register
106
+ @field_hostname = ecs_select[disabled: "hostname", v1: "[host][name]"]
107
+ @field_hostip = ecs_select[disabled: "ip", v1: "[host][ip]" ]
108
+ end
109
+ ~~~
110
+
111
+ NOTE: `ecs_select` should only be used during plugin initialization and
112
+ not during event-by-event processing.
113
+
60
114
  ## Development
61
115
 
62
116
  This gem:
63
117
  - *MUST* remain API-stable at 1.x
64
- - *MUST NOT* introduce additional runtime dependencies
118
+ - *MUST NOT* introduce additional runtime dependencies
@@ -17,9 +17,9 @@ module LogStash
17
17
  module ECSCompatibilitySupport
18
18
  ##
19
19
  # @api internal (use: `LogStash::Plugin::include`)
20
- # @param: a class that inherits `LogStash::Plugin`, typically one
21
- # descending from one of the four plugin base classes (e.g.,
22
- # `LogStash::Inputs::Base`)
20
+ # @param base [Class]: a class that inherits `LogStash::Plugin`, typically one
21
+ # descending from one of the four plugin base classes
22
+ # (e.g., `LogStash::Inputs::Base`)
23
23
  # @return [void]
24
24
  def self.included(base)
25
25
  fail(ArgumentError, "`#{base}` must inherit LogStash::Plugin") unless base < LogStash::Plugin
@@ -100,5 +100,12 @@ module LogStash
100
100
  end
101
101
  end
102
102
  end
103
+
104
+ def self.ECSCompatibilitySupport(*supported_versions)
105
+ return ECSCompatibilitySupport if supported_versions.empty?
106
+
107
+ require_relative "ecs_compatibility_support/selector"
108
+ ECSCompatibilitySupport::Selector.new(*supported_versions)
109
+ end
103
110
  end
104
111
  end
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../ecs_compatibility_support'
4
+
5
+ module LogStash
6
+ module PluginMixins
7
+ module ECSCompatibilitySupport
8
+ # A `ECSCompatibilitySupport::Selector` is a `Module` that can be included into any `LogStash::Plugin`
9
+ # to constrain instances to a specific set of supported `ecs_compatibility` modes.
10
+ #
11
+ # It also provides an `ecs_select` that allows plugin developers to specify ECS alternatives
12
+ # in-line with their existing code.
13
+ #
14
+ # @api private
15
+ # @see ECSCompatibilitySupport()
16
+ class Selector < Module
17
+
18
+ ##
19
+ # @api internal (use: `LogStash::Plugin::include`)
20
+ # @param base [Class]: a class that inherits `LogStash::Plugin`, typically one
21
+ # descending from one of the four plugin base classes
22
+ # (e.g., `LogStash::Inputs::Base`)
23
+ # @return [void]
24
+ def included(base)
25
+ fail(ArgumentError, "`#{base}` must inherit LogStash::Plugin") unless base < LogStash::Plugin
26
+ base.include(ECSCompatibilitySupport)
27
+ end
28
+
29
+ ##
30
+ # @api private
31
+ # @see ECSCompatibilitySupport()
32
+ # @param ecs_modes_supported
33
+ def initialize(*ecs_modes_supported)
34
+ fail(ArgumentError, "one or more ecs_modes_supported required") if ecs_modes_supported.empty?
35
+ fail(ArgumentError, "ecs_modes_supported must only contain symbols") unless ecs_modes_supported.all? { |s| s.kind_of?(Symbol) }
36
+
37
+ ecs_modes_supported.freeze
38
+
39
+ ##
40
+ # Hooks initialization to throw a configuration error if plugin is initialized with
41
+ # an unsupported `ecs_compatibility` mode.
42
+ # @method initialize
43
+ define_method(:initialize) do |*args|
44
+ super(*args) # Plugin#initialize
45
+
46
+ effective_ecs_mode = ecs_compatibility
47
+ if !ecs_modes_supported.include?(effective_ecs_mode)
48
+ message = "#{config_name} #{@plugin_type} plugin does not support `ecs_compatibility => #{effective_ecs_mode}`. "+
49
+ "Supported modes are: #{ecs_modes_supported}"
50
+ fail(LogStash::ConfigurationError, message)
51
+ end
52
+ @_ecs_select = State.new(ecs_modes_supported, effective_ecs_mode)
53
+ end
54
+
55
+ ##
56
+ # @method ecs_select
57
+ # @return [State]
58
+ define_method(:ecs_select) { @_ecs_select }
59
+
60
+ define_singleton_method(:ecs_modes_supported) { ecs_modes_supported }
61
+ end
62
+
63
+ ##
64
+ # @return [String]
65
+ def name
66
+ "#{Selector}(#{ecs_modes_supported.join(',')})"
67
+ end
68
+
69
+ ##
70
+ # A `State` contains the active mode and a list of all supported modes.
71
+ #
72
+ # It allows a developer to safely define mappings of alternative values, exactly
73
+ # one of which will be selected based on the effective mode.
74
+ #
75
+ # It is _NOT_ designed for performance, but may be helpful during instantiation.
76
+ #
77
+ # @api private
78
+ class State
79
+ ##
80
+ # @api private
81
+ # @param supported_modes [Array<Symbol>]
82
+ # @param active_mode [Symbol]
83
+ def initialize(supported_modes, active_mode)
84
+ @supported_modes = supported_modes
85
+ @active_mode = active_mode
86
+ end
87
+
88
+ attr_reader :active_mode
89
+ attr_reader :supported_modes
90
+
91
+ # With the active mode, select one of the provided options.
92
+ # @param defined_choices [Hash{Symbol=>Object}]: the options to chose between.
93
+ # it is an `ArgumentError` to provide a different set of
94
+ # options than those this `State` was initialized with.
95
+ # This ensures that all reachable code implements all
96
+ # supported options.
97
+ # @return [Object]
98
+ def value_from(defined_choices)
99
+ fail(ArgumentError, "defined_choices must be a Hash") unless defined_choices.kind_of?(Hash)
100
+ fail(ArgumentError, "defined_choices cannot be empty") if defined_choices.empty?
101
+ fail(ArgumentError, "defined_choices must have Symbol keys") unless defined_choices.keys.all? { |k| k.kind_of?(Symbol) }
102
+
103
+ fail(ArgumentError, "at least one choice must be defined") if defined_choices.empty?
104
+
105
+ missing = @supported_modes - defined_choices.keys
106
+ fail(ArgumentError, "missing one or more required choice definition #{missing}") if missing.any?
107
+
108
+ unknown = defined_choices.keys - @supported_modes
109
+ fail(ArgumentError, "unknown choices #{unknown}; valid choices are #{@supported_modes}") if unknown.any?
110
+
111
+ defined_choices.fetch(@active_mode)
112
+ end
113
+ alias_method :[], :value_from
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'selector'
4
+
5
+ module LogStash
6
+ module PluginMixins
7
+ module ECSCompatibilitySupport
8
+ # The `SpecHelper` is meant to be extended into an rspec context to provide it with
9
+ # tools for vaidating the ecs_compatibility matrix.
10
+ #
11
+ # It creates one sub-context per provided mode, and yields a Selector::State
12
+ # to the provided block primed with the list of supported supported_modes and the active mode.
13
+ #
14
+ # It also memoizes an `ecs_compatibility` set to the active mode. It is up to the user
15
+ # to plumb this into the initialization of your plugin.
16
+ #
17
+ # ~~~ ruby
18
+ # require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
19
+ #
20
+ # describe YourClass, :ecs_compatibility_support
21
+ # ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
22
+ # context "#description" do
23
+ # subject(:result) { instance.description }
24
+ # it { is_expected.to eq ecs_select[disabled: "legacy", v1: "novel"] }
25
+ # end
26
+ # end
27
+ # end
28
+ # ~~~
29
+ module SpecHelper
30
+ def ecs_compatibility_matrix(*supported_modes,&block)
31
+ if supported_modes.empty? || supported_modes.any? { |mode| !mode.kind_of?(Symbol) }
32
+ fail(ArgumentError, "ecs_compatibility_matrix(*supported_modes) requires one or more symbol supported_modes")
33
+ end
34
+
35
+ supported_modes.each do |active_mode|
36
+ context "`ecs_compatibility => #{active_mode}`" do
37
+ let(:ecs_compatibility) { active_mode }
38
+
39
+ ecs_select = Selector::State.new(supported_modes, active_mode)
40
+ instance_exec(ecs_select, &block)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ ::RSpec.configure { |c| c.extend(SpecHelper, :ecs_compatibility_support) } if defined?(::RSpec)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,119 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/its'
4
+
5
+ require "logstash-core"
6
+
7
+ require 'logstash/inputs/base'
8
+ require 'logstash/filters/base'
9
+ require 'logstash/codecs/base'
10
+ require 'logstash/outputs/base'
11
+
12
+ require "logstash/plugin_mixins/ecs_compatibility_support/selector"
13
+
14
+ describe LogStash::PluginMixins::ECSCompatibilitySupport::Selector do
15
+ context 'initialize' do
16
+ it 'rejects zero arguments' do
17
+ expect { described_class.new }.to raise_error(ArgumentError, /one or more/)
18
+ end
19
+ it 'rejects non-symbol arguments' do
20
+ expect { described_class.new("v1") }.to raise_error(ArgumentError, /symbol/)
21
+ end
22
+ it 'accepts one symbol argument'do
23
+ selector_mod = described_class.new(:disabled)
24
+ aggregate_failures do
25
+ expect(selector_mod.ecs_modes_supported).to contain_exactly(:disabled)
26
+ expect(selector_mod.name).to include('disabled')
27
+ end
28
+ end
29
+ it 'accepts many symbol arguments'do
30
+ selector_mod = described_class.new(:disabled, :v1)
31
+ aggregate_failures do
32
+ expect(selector_mod.ecs_modes_supported).to contain_exactly(:disabled, :v1)
33
+ expect(selector_mod.name).to include('disabled')
34
+ expect(selector_mod.name).to include('v1')
35
+ end
36
+ end
37
+ end
38
+ context 'included into a class' do
39
+ let(:ecs_compatibility_support) { LogStash::PluginMixins::ECSCompatibilitySupport }
40
+ let(:selector_module) { described_class.new(:disabled,:v1) }
41
+ context 'that does not inherit from LogStash::Plugin' do
42
+ let(:plugin_class) { Class.new }
43
+ it 'fails with an ArgumentError' do
44
+ expect do
45
+ plugin_class.send(:include, selector_module)
46
+ end.to raise_error(ArgumentError, /LogStash::Plugin/)
47
+ end
48
+ end
49
+
50
+ [
51
+ LogStash::Inputs::Base,
52
+ LogStash::Filters::Base,
53
+ LogStash::Codecs::Base,
54
+ LogStash::Outputs::Base
55
+ ].each do |base_class|
56
+ context "that inherits from `#{base_class}`" do
57
+ let(:ecs_supported_modes) { [:disabled, :v1] }
58
+ let(:selector_module) { described_class.new(*ecs_supported_modes) }
59
+ let(:plugin_base_class) { base_class }
60
+ subject(:plugin_class) do
61
+ klass = Class.new(plugin_base_class) do
62
+ config_name 'test'
63
+ end
64
+ klass.send(:include, selector_module)
65
+ klass
66
+ end
67
+ context 'the result' do
68
+ its(:ancestors) { is_expected.to include(ecs_compatibility_support) }
69
+ its(:instance_methods) { is_expected.to include(:ecs_select) }
70
+ end
71
+ context '#ecs_select' do
72
+ let(:plugin_options) { Hash.new }
73
+ let(:plugin_instance) { plugin_class.new(plugin_options) }
74
+ let(:ecs_effective_mode) { :v1 }
75
+
76
+ before(:each) do
77
+ # occurs during initialization, before we can get a reference to the instance.
78
+ # our plugin_class is generated per-spec and not reused.
79
+ allow_any_instance_of(plugin_class).to receive(:ecs_compatibility).and_return(ecs_effective_mode)
80
+ end
81
+
82
+ subject(:ecs_select) { plugin_instance.ecs_select }
83
+
84
+ it { is_expected.to be_a_kind_of described_class::State }
85
+ it { is_expected.to respond_to :[] }
86
+
87
+ context 'when effective ecs_compatibility is not supported' do
88
+ let(:ecs_supported_modes) { [:disabled,:v1,:v2] }
89
+ let(:ecs_effective_mode) { :v3 }
90
+ it 'raises a configuration error' do
91
+ expect { plugin_instance.ecs_select }.to raise_error(LogStash::ConfigurationError)
92
+ end
93
+ end
94
+
95
+ context '#[]' do
96
+ it 'rejects empty options' do
97
+ expect { ecs_select[{}] }.to raise_error(ArgumentError, /empty/)
98
+ end
99
+ it 'rejects unknown options' do
100
+ expect { ecs_select[disabled: "nope", v1: "no", bananas: "monkey"] }.to raise_error(ArgumentError, /unknown/)
101
+ end
102
+ it 'rejects missing options' do
103
+ expect { ecs_select[disabled: "nope"] }.to raise_error(ArgumentError, /missing/)
104
+ end
105
+ it 'rejects non-hash options' do
106
+ expect { ecs_select["bananas"] }.to raise_error(ArgumentError, /Hash/)
107
+ end
108
+ it 'requires symbol keys' do
109
+ expect { ecs_select["bananas"=>"apes"] }.to raise_error(ArgumentError, /Symbol keys/)
110
+ end
111
+ it 'selects the correct effective value' do
112
+ expect(ecs_select[disabled: "nope", v1: "winner"]).to eq("winner")
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/its'
4
+
5
+ require "logstash/plugin_mixins/ecs_compatibility_support/spec_helper"
6
+
7
+ describe LogStash::PluginMixins::ECSCompatibilitySupport::SpecHelper, :ecs_compatibility_support do
8
+ context '::ecs_compatibility_matrix(*modes)' do
9
+ ecs_compatibility_matrix(:disabled,:v1) do |ecs_select|
10
+ it("sets `ecs_compatibility` with the current active mode `#{ecs_select.active_mode}`") do
11
+ expect(ecs_compatibility).to eq(ecs_select.active_mode)
12
+ end
13
+ context 'the yielded value' do
14
+ subject { ecs_select }
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) }
17
+ its(:active_mode) { is_expected.to be ecs_compatibility }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -142,3 +142,18 @@ describe LogStash::PluginMixins::ECSCompatibilitySupport do
142
142
  end
143
143
  end
144
144
 
145
+ describe 'LogStash::PluginMixins::ECSCompatibilitySupport()' do
146
+ context 'with no arguments' do
147
+ it 'returns LogStash::PluginMixins::ECSCompatibilitySupport' do
148
+ expect(LogStash::PluginMixins::ECSCompatibilitySupport()).to eq(LogStash::PluginMixins::ECSCompatibilitySupport)
149
+ end
150
+ end
151
+ context 'with symbol arguments' do
152
+ it 'returns a properly-configured LogStash::PluginMixins::ECSCompatibilitySupport::Selector' do
153
+ selector_module = LogStash::PluginMixins::ECSCompatibilitySupport(:disabled,:v1)
154
+ expect(selector_module).to be_a_kind_of(LogStash::PluginMixins::ECSCompatibilitySupport::Selector)
155
+ expect(selector_module.ecs_modes_supported).to contain_exactly(:disabled,:v1)
156
+ end
157
+ end
158
+ end
159
+
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-mixin-ecs_compatibility_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2021-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 5.0.0
18
+ version: 6.0.0
19
19
  name: logstash-core
20
20
  prerelease: false
21
21
  type: :runtime
@@ -23,7 +23,21 @@ dependencies:
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 5.0.0
26
+ version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ name: logstash-devutils
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  requirement: !ruby/object:Gem::Requirement
29
43
  requirements:
@@ -80,6 +94,10 @@ files:
80
94
  - LICENSE
81
95
  - README.md
82
96
  - lib/logstash/plugin_mixins/ecs_compatibility_support.rb
97
+ - lib/logstash/plugin_mixins/ecs_compatibility_support/selector.rb
98
+ - lib/logstash/plugin_mixins/ecs_compatibility_support/spec_helper.rb
99
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/selector_spec.rb
100
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/spec_helper_spec.rb
83
101
  - spec/logstash/plugin_mixins/ecs_compatibility_support_spec.rb
84
102
  homepage: https://github.com/logstash-plugins/logstash-mixin-ecs_compatibility_support
85
103
  licenses:
@@ -101,10 +119,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
119
  version: '0'
102
120
  requirements: []
103
121
  rubyforge_project:
104
- rubygems_version: 2.6.11
122
+ rubygems_version: 2.6.13
105
123
  signing_key:
106
124
  specification_version: 4
107
125
  summary: Support for the ECS-Compatibility mode introduced in Logstash 7.x, for plugins
108
126
  wishing to use this API on older Logstashes
109
127
  test_files:
128
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/selector_spec.rb
129
+ - spec/logstash/plugin_mixins/ecs_compatibility_support/spec_helper_spec.rb
110
130
  - spec/logstash/plugin_mixins/ecs_compatibility_support_spec.rb