mirror of
https://github.com/elastic/logstash.git
synced 2025-04-23 22:27:21 -04:00
Modules cloud id auth (#8059)
* add newlines to generated json * Implement cloud.id and cloud.auth settings merge to module settings * Fixes from review plus convert to using Password for any Module Setting * Review changes * update modules.asciidoc to include a section on Cloud * Capitalize Id * remove unnecessesary require lines
This commit is contained in:
parent
fec6288a41
commit
c5f56e84d8
16 changed files with 515 additions and 13 deletions
|
@ -109,6 +109,19 @@
|
|||
#
|
||||
# modules:
|
||||
#
|
||||
# ------------ Cloud Settings ---------------
|
||||
# Define Elastic Cloud settings here.
|
||||
# Format of cloud.id is a base64 value e.g. dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy
|
||||
# and it may have an label prefix e.g. staging:dXMtZ...
|
||||
# This will overwrite 'var.elasticsearch.hosts' and 'var.kibana.host'
|
||||
# cloud.id: <identifier>
|
||||
#
|
||||
# Format of cloud.auth is: <user>:<pass>
|
||||
# This is optional
|
||||
# If supplied this will overwrite 'var.elasticsearch.username' and 'var.elasticsearch.password'
|
||||
# If supplied this will overwrite 'var.kibana.username' and 'var.kibana.password'
|
||||
# cloud.auth: elastic:<password>
|
||||
#
|
||||
# ------------ Queuing Settings --------------
|
||||
#
|
||||
# Internal queuing model, "memory" for legacy in-memory based queuing and
|
||||
|
|
62
docs/static/modules.asciidoc
vendored
62
docs/static/modules.asciidoc
vendored
|
@ -107,7 +107,7 @@ Elasticsearch `host` setting and the `udp.port` setting:
|
|||
|
||||
[source,shell]
|
||||
----
|
||||
bin/logstash --modules netflow -M "netflow.var.input.udp.port=3555" -M "netflow.var.elasticseach.host=my-es-cloud"
|
||||
bin/logstash --modules netflow -M "netflow.var.input.udp.port=3555" -M "netflow.var.elasticsearch.hosts=my-es-cloud"
|
||||
----
|
||||
|
||||
Any settings defined in the command line are ephemeral and will not persist across
|
||||
|
@ -118,4 +118,64 @@ Settings that you specify at the command line are merged with any settings
|
|||
specified in the `logstash.yml` file. If an option is set in both
|
||||
places, the value specified at the command line takes precedence.
|
||||
|
||||
[[connecting-to-cloud]]
|
||||
=== Using Elastic Cloud
|
||||
|
||||
Logstash comes with two settings that simplify using modules with https://cloud.elastic.co/[Elastic Cloud].
|
||||
The Elasticsearch and Kibana hostnames in Elastic Cloud may be hard to set
|
||||
in the Logstash config or on the commandline, so a Cloud ID can be used instead.
|
||||
|
||||
==== Cloud ID
|
||||
|
||||
The Cloud ID, which can be found in the Elastic Cloud web console, is used by
|
||||
Logstash to build the Elasticsearch and Kibana hosts settings.
|
||||
It is a base64 encoded text value of about 120 characters made up of upper and
|
||||
lower case letters and numbers.
|
||||
If you have several Cloud IDs, you can add a label, which is ignored
|
||||
internally, to help you tell them apart. To add a label you should prefix your
|
||||
Cloud ID with a label and a `:` separator in this format "<label>:<cloud-id>"
|
||||
|
||||
`cloud.id` will overwrite these settings:
|
||||
----
|
||||
var.elasticsearch.hosts
|
||||
var.kibana.host
|
||||
----
|
||||
|
||||
==== Cloud Auth
|
||||
This is optional. Construct this value by following this format "<username>:<password>".
|
||||
Use your Cloud username for the first part. Use your Cloud password for the second part,
|
||||
which is given once in the Cloud UI when you create a cluster.
|
||||
As your Cloud password is changeable, if you change it in the Cloud UI remember to change it here too.
|
||||
|
||||
`cloud.auth` when specified will overwrite these settings:
|
||||
----
|
||||
var.elasticsearch.username
|
||||
var.elasticsearch.password
|
||||
var.kibana.username
|
||||
var.kibana.password
|
||||
----
|
||||
|
||||
Example:
|
||||
|
||||
These settings can be specified in the `logstash.yml` <<logstash-settings-file,settings file>>.
|
||||
They should be added separately from any module configuration settings you may have added before.
|
||||
[source,yaml]
|
||||
----
|
||||
# example with a label
|
||||
cloud.id: "staging:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy"
|
||||
cloud.auth: "elastic:changeme"
|
||||
----
|
||||
----
|
||||
# example without a label
|
||||
cloud.id: "dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy"
|
||||
cloud.auth: "elastic:changeme"
|
||||
----
|
||||
|
||||
These settings can be also specified at the command line, like this:
|
||||
|
||||
["source","sh",subs="attributes,callouts"]
|
||||
----
|
||||
bin/logstash --modules netflow -M "netflow.var.input.udp.port=3555" --cloud.id <cloud-id> --cloud.auth <cloud.auth>
|
||||
----
|
||||
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ module LogStash module Config
|
|||
alt_name = "module-#{module_name}"
|
||||
pipeline_id = alt_name
|
||||
module_settings.set("pipeline.id", pipeline_id)
|
||||
LogStash::Modules::SettingsMerger.merge_cloud_settings(module_hash, module_settings)
|
||||
current_module.with_settings(module_hash)
|
||||
config_test = settings.get("config.test_and_exit")
|
||||
modul_setup = settings.get("modules_setup")
|
||||
|
|
|
@ -39,8 +39,11 @@ module LogStash class ElasticsearchClient
|
|||
@client_args[:ssl] = ssl_options
|
||||
|
||||
username = @settings["var.elasticsearch.username"]
|
||||
password = @settings["var.elasticsearch.password"]
|
||||
if username
|
||||
password = @settings["var.elasticsearch.password"]
|
||||
if password.is_a?(LogStash::Util::Password)
|
||||
password = password.value
|
||||
end
|
||||
@client_args[:transport_options] = { :headers => { "Authorization" => 'Basic ' + Base64.encode64( "#{username}:#{password}" ).chomp } }
|
||||
end
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ require "logstash/errors"
|
|||
require "logstash/java_integration"
|
||||
require "logstash/config/cpu_core_strategy"
|
||||
require "logstash/settings"
|
||||
require "logstash/util/cloud_setting_id"
|
||||
require "logstash/util/cloud_setting_auth"
|
||||
require "logstash/util/modules_setting_array"
|
||||
require "socket"
|
||||
require "stud/temporary"
|
||||
|
||||
|
@ -20,8 +23,10 @@ module LogStash
|
|||
Setting::NullableString.new("path.config", nil, false),
|
||||
Setting::WritableDirectory.new("path.data", ::File.join(LogStash::Environment::LOGSTASH_HOME, "data")),
|
||||
Setting::NullableString.new("config.string", nil, false),
|
||||
Setting.new("modules.cli", Array, []),
|
||||
Setting.new("modules", Array, []),
|
||||
Setting::Modules.new("modules.cli", LogStash::Util::ModulesSettingArray, []),
|
||||
Setting::Modules.new("modules", LogStash::Util::ModulesSettingArray, []),
|
||||
Setting::Modules.new("cloud.id", LogStash::Util::CloudSettingId),
|
||||
Setting::Modules.new("cloud.auth",LogStash::Util::CloudSettingAuth),
|
||||
Setting::Boolean.new("modules_setup", false),
|
||||
Setting::Boolean.new("config.test_and_exit", false),
|
||||
Setting::Boolean.new("config.reload.automatic", false),
|
||||
|
|
|
@ -50,12 +50,14 @@ module LogStash module Modules class KibanaClient
|
|||
|
||||
@client = Manticore::Client.new(client_options)
|
||||
@host = @settings.fetch("var.kibana.host", "localhost:5601")
|
||||
username = @settings["var.kibana.username"]
|
||||
password = @settings["var.kibana.password"]
|
||||
|
||||
@scheme = @settings.fetch("var.kibana.scheme", "http")
|
||||
@http_options = {:headers => {'Content-Type' => 'application/json'}}
|
||||
username = @settings["var.kibana.username"]
|
||||
if username
|
||||
password = @settings["var.kibana.password"]
|
||||
if password.is_a?(LogStash::Util::Password)
|
||||
password = password.value
|
||||
end
|
||||
@http_options[:headers]['Authorization'] = 'Basic ' + Base64.encode64( "#{username}:#{password}" ).chomp
|
||||
end
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
# encoding: utf-8
|
||||
require "logstash/namespace"
|
||||
require "logstash/util"
|
||||
require "logstash/util/loggable"
|
||||
|
||||
module LogStash module Modules class SettingsMerger
|
||||
def self.merge(cli_settings, yml_settings)
|
||||
module LogStash module Modules module SettingsMerger
|
||||
include LogStash::Util::Loggable
|
||||
extend self
|
||||
|
||||
def merge(cli_settings, yml_settings)
|
||||
# both args are arrays of hashes, e.g.
|
||||
# [{"name"=>"mod1", "var.input.tcp.port"=>"3333"}, {"name"=>"mod2"}]
|
||||
# [{"name"=>"mod1", "var.input.tcp.port"=>2222, "var.kibana.username"=>"rupert", "var.kibana.password"=>"fotherington"}, {"name"=>"mod3", "var.input.tcp.port"=>4445}]
|
||||
|
@ -11,13 +16,56 @@ module LogStash module Modules class SettingsMerger
|
|||
# union will also coalesce identical hashes
|
||||
union_of_settings = (cli_settings | yml_settings)
|
||||
grouped_by_name = union_of_settings.group_by{|e| e["name"]}
|
||||
grouped_by_name.each do |name, array|
|
||||
grouped_by_name.each do |_, array|
|
||||
if array.size == 2
|
||||
merged << array.first.merge(array.last)
|
||||
merged << array.last.merge(array.first)
|
||||
else
|
||||
merged.concat(array)
|
||||
end
|
||||
end
|
||||
merged
|
||||
end
|
||||
|
||||
def merge_cloud_settings(module_settings, logstash_settings)
|
||||
cloud_id = logstash_settings.get("cloud.id")
|
||||
cloud_auth = logstash_settings.get("cloud.auth")
|
||||
if cloud_id.nil?
|
||||
if cloud_auth.nil?
|
||||
return # user did not specify cloud settings
|
||||
else
|
||||
raise ArgumentError.new("Cloud Auth without Cloud Id")
|
||||
end
|
||||
end
|
||||
if logger.debug?
|
||||
settings_copy = LogStash::Util.deep_clone(module_settings)
|
||||
end
|
||||
|
||||
module_settings["var.kibana.scheme"] = "https"
|
||||
module_settings["var.kibana.host"] = cloud_id.kibana_host
|
||||
module_settings["var.elasticsearch.hosts"] = cloud_id.elasticsearch_host
|
||||
unless cloud_auth.nil?
|
||||
module_settings["var.elasticsearch.username"] = cloud_auth.username
|
||||
module_settings["var.elasticsearch.password"] = cloud_auth.password
|
||||
module_settings["var.kibana.username"] = cloud_auth.username
|
||||
module_settings["var.kibana.password"] = cloud_auth.password
|
||||
end
|
||||
if logger.debug?
|
||||
format_module_settings(settings_copy, module_settings).each {|line| logger.debug(line)}
|
||||
end
|
||||
end
|
||||
|
||||
def format_module_settings(settings_before, settings_after)
|
||||
output = []
|
||||
output << "-------- Module Settings ---------"
|
||||
settings_after.each do |setting_name, setting|
|
||||
setting_before = settings_before.fetch(setting_name, "")
|
||||
line = "#{setting_name}: '#{setting}'"
|
||||
if setting_before != setting
|
||||
line.concat(", was: '#{setting_before}'")
|
||||
end
|
||||
output << line
|
||||
end
|
||||
output << "-------- Module Settings ---------"
|
||||
output
|
||||
end
|
||||
end end end
|
||||
|
|
|
@ -79,6 +79,14 @@ class LogStash::Runner < Clamp::StrictCommand
|
|||
:default => LogStash::SETTINGS.get_default("modules_setup"),
|
||||
:attribute_name => "modules_setup"
|
||||
|
||||
option ["--cloud.id"], "CLOUD_ID",
|
||||
I18n.t("logstash.runner.flag.cloud_id"),
|
||||
:attribute_name => "cloud.id"
|
||||
|
||||
option ["--cloud.auth"], "CLOUD_AUTH",
|
||||
I18n.t("logstash.runner.flag.cloud_auth"),
|
||||
:attribute_name => "cloud.auth"
|
||||
|
||||
# Pipeline settings
|
||||
option ["-w", "--pipeline.workers"], "COUNT",
|
||||
I18n.t("logstash.runner.flag.pipeline-workers"),
|
||||
|
|
|
@ -255,6 +255,7 @@ module LogStash
|
|||
@default = default
|
||||
end
|
||||
end
|
||||
|
||||
def set(value)
|
||||
coerced_value = coerce(value)
|
||||
validate(coerced_value)
|
||||
|
@ -557,7 +558,32 @@ module LogStash
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Modules < Coercible
|
||||
def initialize(name, klass, default = nil)
|
||||
super(name, klass, default, false)
|
||||
end
|
||||
|
||||
def set(value)
|
||||
@value = coerce(value)
|
||||
@value_is_set = true
|
||||
@value
|
||||
end
|
||||
|
||||
def coerce(value)
|
||||
if value.is_a?(@klass)
|
||||
return value
|
||||
end
|
||||
@klass.new(value)
|
||||
end
|
||||
|
||||
protected
|
||||
def validate(value)
|
||||
coerce(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
SETTINGS = Settings.new
|
||||
end
|
||||
|
|
29
logstash-core/lib/logstash/util/cloud_setting_auth.rb
Normal file
29
logstash-core/lib/logstash/util/cloud_setting_auth.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# encoding: utf-8
|
||||
require "logstash/namespace"
|
||||
require "logstash/util/password"
|
||||
|
||||
module LogStash module Util class CloudSettingAuth
|
||||
attr_reader :original, :username, :password
|
||||
|
||||
def initialize(value)
|
||||
return if value.nil?
|
||||
|
||||
unless value.is_a?(String)
|
||||
raise ArgumentError.new("Cloud Auth must be String. Received: #{value.class}")
|
||||
end
|
||||
@original = value
|
||||
@username, sep, password = @original.partition(":")
|
||||
if @username.empty? || sep.empty? || password.empty?
|
||||
raise ArgumentError.new("Cloud Auth username and password format should be \"<username>:<password>\".")
|
||||
end
|
||||
@password = LogStash::Util::Password.new(password)
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{@username}:#{@password}"
|
||||
end
|
||||
|
||||
def inspect
|
||||
to_s
|
||||
end
|
||||
end end end
|
41
logstash-core/lib/logstash/util/cloud_setting_id.rb
Normal file
41
logstash-core/lib/logstash/util/cloud_setting_id.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
# encoding: utf-8
|
||||
require "logstash/namespace"
|
||||
require "base64"
|
||||
|
||||
module LogStash module Util class CloudSettingId
|
||||
attr_reader :original, :decoded, :label, :elasticsearch_host, :kibana_host
|
||||
|
||||
def initialize(value)
|
||||
return if value.nil?
|
||||
|
||||
unless value.is_a?(String)
|
||||
raise ArgumentError.new("Cloud Id must be String. Received: #{value.class}")
|
||||
end
|
||||
@original = value
|
||||
@label, sep, last = value.partition(":")
|
||||
if last.empty?
|
||||
@decoded = Base64.urlsafe_decode64(@label) rescue ""
|
||||
@label = ""
|
||||
else
|
||||
@decoded = Base64.urlsafe_decode64(last) rescue ""
|
||||
end
|
||||
unless @decoded.count("$") == 2
|
||||
raise ArgumentError.new("Cloud Id does not decode. Received: \"#{@original}\".")
|
||||
end
|
||||
parts = @decoded.split("$")
|
||||
if parts.any?(&:empty?)
|
||||
raise ArgumentError.new("Cloud Id, after decoding, is invalid. Format: '<part1>$<part2>$<part3>'. Received: \"#{@decoded}\".")
|
||||
end
|
||||
cloud_host, es_server, kb_server = parts
|
||||
@elasticsearch_host = sprintf("%s.%s:443", es_server, cloud_host)
|
||||
@kibana_host = sprintf("%s.%s:443", kb_server, cloud_host)
|
||||
end
|
||||
|
||||
def to_s
|
||||
@original.to_s
|
||||
end
|
||||
|
||||
def inspect
|
||||
to_s
|
||||
end
|
||||
end end end
|
28
logstash-core/lib/logstash/util/modules_setting_array.rb
Normal file
28
logstash-core/lib/logstash/util/modules_setting_array.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# encoding: utf-8
|
||||
require "logstash/namespace"
|
||||
require "logstash/util/password"
|
||||
|
||||
module LogStash module Util class ModulesSettingArray
|
||||
extend Forwardable
|
||||
DELEGATED_METHODS = [].public_methods.reject{|symbol| symbol.to_s.end_with?('__')}
|
||||
|
||||
def_delegators :@original, *DELEGATED_METHODS
|
||||
|
||||
attr_reader :original
|
||||
def initialize(value)
|
||||
unless value.is_a?(Array)
|
||||
raise ArgumentError.new("Module Settings must be an Array. Received: #{value.class}")
|
||||
end
|
||||
@original = value
|
||||
# wrap passwords
|
||||
@original.each do |hash|
|
||||
hash.keys.select{|key| key.to_s.end_with?('password')}.each do |key|
|
||||
hash[key] = LogStash::Util::Password.new(hash[key])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def __class__
|
||||
LogStash::Util::ModulesSettingArray
|
||||
end
|
||||
end end end
|
|
@ -246,6 +246,18 @@ en:
|
|||
Load index template into Elasticsearch, and saved searches,
|
||||
index-pattern, visualizations, and dashboards into Kibana when
|
||||
running modules.
|
||||
cloud_id: |+
|
||||
Sets the elasticsearch and kibana host settings for
|
||||
module connections in Elastic Cloud.
|
||||
Your Elastic Cloud User interface or the Cloud support
|
||||
team should provide this.
|
||||
Add an optional label prefix '<label>:' to help you
|
||||
identify multiple cloud.ids.
|
||||
e.g. 'staging:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy'
|
||||
cloud_auth: |+
|
||||
Sets the elasticsearch and kibana username and password
|
||||
for module connections in Elastic Cloud
|
||||
e.g. 'username:<password>'
|
||||
configtest: |+
|
||||
Check configuration for valid syntax and then exit.
|
||||
http_host: Web API binding host
|
||||
|
|
111
logstash-core/spec/logstash/modules/settings_merger_spec.rb
Normal file
111
logstash-core/spec/logstash/modules/settings_merger_spec.rb
Normal file
|
@ -0,0 +1,111 @@
|
|||
# encoding: utf-8
|
||||
require "spec_helper"
|
||||
require "logstash/util/cloud_setting_id"
|
||||
require "logstash/util/cloud_setting_auth"
|
||||
require "logstash/modules/settings_merger"
|
||||
require "logstash/util/password"
|
||||
|
||||
class SubstituteSettingsForRSpec
|
||||
def initialize(hash = {}) @hash = hash; end
|
||||
def put(key, value) @hash[key] = value; end
|
||||
def get(key) @hash[key]; end
|
||||
end
|
||||
|
||||
describe LogStash::Modules::SettingsMerger do
|
||||
describe "#merge" do
|
||||
let(:cli) {[{"name"=>"mod1", "var.input.tcp.port"=>"3333"}, {"name"=>"mod2"}]}
|
||||
let(:yml) {[{"name"=>"mod1", "var.input.tcp.port"=>2222, "var.kibana.username"=>"rupert", "var.kibana.password"=>"fotherington"}, {"name"=>"mod3", "var.input.tcp.port"=>4445}]}
|
||||
subject(:results) { described_class.merge(cli, yml) }
|
||||
it "merges cli overwriting any common fields in yml" do
|
||||
expect(results).to be_a(Array)
|
||||
expect(results.size).to eq(3)
|
||||
expect(results[0]["name"]).to eq("mod1")
|
||||
expect(results[0]["var.input.tcp.port"]).to eq("3333")
|
||||
expect(results[0]["var.kibana.username"]).to eq("rupert")
|
||||
expect(results[1]["name"]).to eq("mod2")
|
||||
expect(results[2]["name"]).to eq("mod3")
|
||||
expect(results[2]["var.input.tcp.port"]).to eq(4445)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#merge_cloud_settings" do
|
||||
let(:cloud_id) { LogStash::Util::CloudSettingId.new("label:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy") }
|
||||
let(:cloud_auth) { LogStash::Util::CloudSettingAuth.new("elastix:bigwhoppingfairytail") }
|
||||
let(:mod_settings) { {} }
|
||||
|
||||
context "when both are supplied" do
|
||||
let(:expected_table) do
|
||||
{
|
||||
"var.kibana.scheme" => "https",
|
||||
"var.kibana.host" => "identifier.us-east-1.aws.found.io:443",
|
||||
"var.elasticsearch.hosts" => "notareal.us-east-1.aws.found.io:443",
|
||||
"var.elasticsearch.username" => "elastix",
|
||||
"var.kibana.username" => "elastix"
|
||||
}
|
||||
end
|
||||
let(:ls_settings) { SubstituteSettingsForRSpec.new({"cloud.id" => cloud_id, "cloud.auth" => cloud_auth}) }
|
||||
|
||||
before do
|
||||
described_class.merge_cloud_settings(mod_settings, ls_settings)
|
||||
end
|
||||
|
||||
it "adds entries to module settings" do
|
||||
expected_table.each do |key, expected|
|
||||
expect(mod_settings[key]).to eq(expected)
|
||||
end
|
||||
expect(mod_settings["var.elasticsearch.password"].value).to eq("bigwhoppingfairytail")
|
||||
expect(mod_settings["var.kibana.password"].value).to eq("bigwhoppingfairytail")
|
||||
end
|
||||
end
|
||||
|
||||
context "when cloud.id is supplied" do
|
||||
let(:expected_table) do
|
||||
{
|
||||
"var.kibana.scheme" => "https",
|
||||
"var.kibana.host" => "identifier.us-east-1.aws.found.io:443",
|
||||
"var.elasticsearch.hosts" => "notareal.us-east-1.aws.found.io:443",
|
||||
}
|
||||
end
|
||||
let(:ls_settings) { SubstituteSettingsForRSpec.new({"cloud.id" => cloud_id}) }
|
||||
|
||||
before do
|
||||
described_class.merge_cloud_settings(mod_settings, ls_settings)
|
||||
end
|
||||
|
||||
it "adds entries to module settings" do
|
||||
expected_table.each do |key, expected|
|
||||
expect(mod_settings[key]).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when only cloud.auth is supplied" do
|
||||
let(:ls_settings) { SubstituteSettingsForRSpec.new({"cloud.auth" => cloud_auth}) }
|
||||
it "should raise an error" do
|
||||
expect{ described_class.merge_cloud_settings(mod_settings, ls_settings) }.to raise_exception(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when neither cloud.id nor cloud.auth is supplied" do
|
||||
let(:ls_settings) { SubstituteSettingsForRSpec.new() }
|
||||
it "should do nothing" do
|
||||
expect(mod_settings).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#format_module_settings" do
|
||||
let(:before_hash) { {"foo" => "red", "bar" => "blue", "qux" => "pink"} }
|
||||
let(:after_hash) { {"foo" => "red", "bar" => "steel-blue", "baz" => LogStash::Util::Password.new("cyan"), "qux" => nil} }
|
||||
subject(:results) { described_class.format_module_settings(before_hash, after_hash) }
|
||||
it "yields an array of formatted lines for ease of logging" do
|
||||
expect(results.size).to eq(after_hash.size + 2)
|
||||
expect(results.first).to eq("-------- Module Settings ---------")
|
||||
expect(results.last).to eq("-------- Module Settings ---------")
|
||||
expect(results[1]).to eq("foo: 'red'")
|
||||
expect(results[2]).to eq("bar: 'steel-blue', was: 'blue'")
|
||||
expect(results[3]).to eq("baz: '<password>', was: ''")
|
||||
expect(results[4]).to eq("qux: '', was: 'pink'")
|
||||
end
|
||||
end
|
||||
end
|
115
logstash-core/spec/logstash/settings/modules_spec.rb
Normal file
115
logstash-core/spec/logstash/settings/modules_spec.rb
Normal file
|
@ -0,0 +1,115 @@
|
|||
# encoding: utf-8
|
||||
require "spec_helper"
|
||||
require "logstash/settings"
|
||||
require "logstash/util/cloud_setting_id"
|
||||
require "logstash/util/cloud_setting_auth"
|
||||
require "logstash/util/modules_setting_array"
|
||||
|
||||
describe LogStash::Setting::Modules do
|
||||
describe "Modules.Cli" do
|
||||
subject { described_class.new("mycloudid", LogStash::Util::ModulesSettingArray, []) }
|
||||
context "when given an array of hashes that contains a password key" do
|
||||
it "should convert password Strings to Password" do
|
||||
source = [{"var.kibana.password" => "some_secret"}]
|
||||
setting = subject.set(source)
|
||||
expect(setting).to be_a(Array)
|
||||
expect(setting.__class__).to eq(LogStash::Util::ModulesSettingArray)
|
||||
expect(setting.first.fetch("var.kibana.password")).to be_a(LogStash::Util::Password)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Cloud.Id" do
|
||||
subject { described_class.new("mycloudid", LogStash::Util::CloudSettingId) }
|
||||
context "when given a string which is not a cloud id" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set("foobarbaz") }.to raise_error(ArgumentError, /Cloud Id does not decode/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string which is empty" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set("") }.to raise_error(ArgumentError, /Cloud Id does not decode/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string which is has environment prefix only" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set("testing:") }.to raise_error(ArgumentError, /Cloud Id does not decode/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a badly formatted encoded id" do
|
||||
it "should not raise an error" do
|
||||
encoded = Base64.urlsafe_encode64("foo$$bal")
|
||||
expect { subject.set(encoded) }.to raise_error(ArgumentError, /Cloud Id, after decoding, is invalid. Format: '<part1>\$<part2>\$<part3>'/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a nil" do
|
||||
it "should not raise an error" do
|
||||
expect { subject.set(nil) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string which is an unlabelled cloud id" do
|
||||
it "should set a LogStash::Util::CloudId instance" do
|
||||
expect { subject.set("dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy") }.to_not raise_error
|
||||
expect(subject.value.elasticsearch_host).to eq("notareal.us-east-1.aws.found.io:443")
|
||||
expect(subject.value.kibana_host).to eq("identifier.us-east-1.aws.found.io:443")
|
||||
expect(subject.value.label).to eq("")
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string which is a labelled cloud id" do
|
||||
it "should set a LogStash::Util::CloudId instance" do
|
||||
expect { subject.set("staging:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRub3RhcmVhbCRpZGVudGlmaWVy") }.to_not raise_error
|
||||
expect(subject.value.elasticsearch_host).to eq("notareal.us-east-1.aws.found.io:443")
|
||||
expect(subject.value.kibana_host).to eq("identifier.us-east-1.aws.found.io:443")
|
||||
expect(subject.value.label).to eq("staging")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Cloud.Auth" do
|
||||
subject { described_class.new("mycloudauth", LogStash::Util::CloudSettingAuth) }
|
||||
context "when given a string without a separator or a password" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set("foobarbaz") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string without a password" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set("foo:") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string without a username" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set(":bar") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string which is empty" do
|
||||
it "should raise an exception" do
|
||||
expect { subject.set("") }.to raise_error(ArgumentError, /Cloud Auth username and password format should be/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a nil" do
|
||||
it "should not raise an error" do
|
||||
expect { subject.set(nil) }.to_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a string which is a cloud auth" do
|
||||
it "should set the string" do
|
||||
expect { subject.set("frodo:baggins") }.to_not raise_error
|
||||
expect(subject.value.username).to eq("frodo")
|
||||
expect(subject.value.password.value).to eq("baggins")
|
||||
expect(subject.value.to_s).to eq("frodo:<password>")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -23,7 +23,7 @@ namespace "modules" do
|
|||
full_path = ::File.join(partial_path, filename)
|
||||
FileUtils.rm_f(full_path)
|
||||
|
||||
content = JSON.pretty_generate(source)
|
||||
content = JSON.pretty_generate(source) + "\n"
|
||||
puts "Writing #{full_path}"
|
||||
IO.write(full_path, content)
|
||||
end
|
||||
|
@ -42,7 +42,7 @@ namespace "modules" do
|
|||
full_path = ::File.join(dashboard_dir, "#{module_name}.json")
|
||||
FileUtils.rm_f(full_path)
|
||||
|
||||
content = JSON.pretty_generate(filenames)
|
||||
content = JSON.pretty_generate(filenames) + "\n"
|
||||
puts "Writing #{full_path}"
|
||||
IO.write(full_path, content)
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue