Add a transient_settings concept to the settings handling

When we load a yml file in logstash if a key isn't not found in the
settings, we move that key and the corresponding value to a
`transient_settings` hash. This give the time to the plugin to register
new settings. When we call #validate_all we merge the
`transient_settings` hash and do the validation, if a key is not found
at that stage an excepton will be throw.

Fixes #6109
This commit is contained in:
Pier-Hugues Pellerin 2016-11-09 16:23:26 -05:00
parent 413dc350d2
commit a732d0cdea
2 changed files with 57 additions and 4 deletions

View file

@ -9,6 +9,11 @@ module LogStash
def initialize
@settings = {}
# Theses settings were loaded from the yaml file
# but we didn't find any settings to validate them,
# lets keep them around until we do `validate_all` at that
# time universal plugins could have added new settings.
@transient_settings = {}
end
def register(setting)
@ -52,8 +57,14 @@ module LogStash
end
alias_method :get, :get_value
def set_value(setting_name, value)
def set_value(setting_name, value, graceful = false)
get_setting(setting_name).set(value)
rescue ArgumentError => e
if graceful
@transient_settings[setting_name] = value
else
raise e
end
end
alias_method :set, :set_value
@ -65,8 +76,8 @@ module LogStash
hash
end
def merge(hash)
hash.each {|key, value| set_value(key, value) }
def merge(hash, graceful = false)
hash.each {|key, value| set_value(key, value, graceful) }
self
end
@ -96,10 +107,13 @@ module LogStash
def from_yaml(yaml_path)
settings = read_yaml(::File.join(yaml_path, "logstash.yml"))
self.merge(flatten_hash(settings))
self.merge(flatten_hash(settings), true)
end
def validate_all
# lets merge the transient_settings again to see if new setting were added.
self.merge(@transient_settings)
@settings.each do |name, setting|
setting.validate_value
end

View file

@ -1,6 +1,7 @@
# encoding: utf-8
require "spec_helper"
require "logstash/settings"
require "fileutils"
describe LogStash::Settings do
let(:numeric_setting_name) { "number" }
@ -86,4 +87,42 @@ describe LogStash::Settings do
end
end
end
context "transient settings" do
subject do
settings = described_class.new
settings.register(LogStash::Setting::String.new("exist", "bonsoir"))
settings
end
let(:values) { { "do.not.exist.on.boot" => true, "exist" => "bonjour" } }
let(:yaml_path) do
p = Stud::Temporary.pathname
FileUtils.mkdir_p(p)
::File.open(::File.join(p, "logstash.yml"), "w+") do |f|
f.write(YAML.dump(values))
end
p
end
it "allow to read yml file that contains unknown settings" do
expect { subject.from_yaml(yaml_path) }.not_to raise_error
end
context "when running #validate_all" do
it "merge and validate all the registered setting" do
subject.from_yaml(yaml_path)
subject.register(LogStash::Setting::Boolean.new("do.not.exist.on.boot", false))
expect { subject.validate_all }.not_to raise_error
expect(subject.get("do.not.exist.on.boot")).to be_truthy
end
it "raise an error when the settings doesn't exist" do
subject.from_yaml(yaml_path)
expect { subject.validate_all }.to raise_error(ArgumentError)
end
end
end
end