Skip to content

Commit b46ea96

Browse files
mashhurslogstashmachine
authored andcommitted
Exclude substitution refinement on pipelines.yml (#16375)
* Exclude substitution refinement on pipelines.yml (applies on ENV vars and logstash.yml where env2yaml saves vars) * Safety integration test for pipeline config.string contains ENV . (cherry picked from commit e104704)
1 parent f0fe4ce commit b46ea96

4 files changed

Lines changed: 23 additions & 11 deletions

File tree

logstash-core/lib/logstash/config/mixin.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def config_init(params)
9393

9494
# Resolve environment variables references
9595
params.each do |name, value|
96-
params[name.to_s] = deep_replace(value)
96+
params[name.to_s] = deep_replace(value, true)
9797
end
9898

9999
# Intercept codecs that have not been instantiated

logstash-core/lib/logstash/settings.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def reset
187187

188188
def from_yaml(yaml_path, file_name = "logstash.yml")
189189
settings = read_yaml(::File.join(yaml_path, file_name))
190-
self.merge(deep_replace(flatten_hash(settings)), true)
190+
self.merge(deep_replace(flatten_hash(settings), true), true)
191191
self
192192
end
193193

logstash-core/lib/logstash/util/substitution_variables.rb

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ module ::LogStash::Util::SubstitutionVariables
2828
SECRET_STORE = ::LogStash::Util::LazySingleton.new { load_secret_store }
2929
private_constant :SECRET_STORE
3030

31-
# Recursive method to replace substitution variable references in parameters
32-
def deep_replace(value)
31+
# Recursive method to replace substitution variable references in parameters and refine if required
32+
def deep_replace(value, refine = false)
3333
if value.is_a?(Hash)
3434
value.each do |valueHashKey, valueHashValue|
35-
value[valueHashKey.to_s] = deep_replace(valueHashValue)
35+
value[valueHashKey.to_s] = deep_replace(valueHashValue, refine)
3636
end
3737
else
3838
if value.is_a?(Array)
3939
value.each_with_index do |single_value, i|
40-
value[i] = deep_replace(single_value)
40+
value[i] = deep_replace(single_value, refine)
4141
end
4242
else
43-
return replace_placeholders(value)
43+
return replace_placeholders(value, refine)
4444
end
4545
end
4646
end
@@ -49,9 +49,11 @@ def deep_replace(value)
4949
# Process following patterns : ${VAR}, ${VAR:defaultValue}
5050
# If value matches the pattern, returns the following precedence : Secret store value, Environment entry value, default value as provided in the pattern
5151
# If the value does not match the pattern, the 'value' param returns as-is
52-
def replace_placeholders(value)
52+
# When setting refine to true, substituted value will be cleaned against escaped single/double quotes
53+
# and generates array if resolved substituted value is array string
54+
def replace_placeholders(value, refine)
5355
if value.kind_of?(::LogStash::Util::Password)
54-
interpolated = replace_placeholders(value.value)
56+
interpolated = replace_placeholders(value.value, refine)
5557
return ::LogStash::Util::Password.new(interpolated)
5658
end
5759
return value unless value.is_a?(String)
@@ -80,8 +82,8 @@ def replace_placeholders(value)
8082
replacement.to_s
8183
end
8284

83-
# no further action need if substitution didn't happen
84-
return placeholder_value unless is_placeholder_found
85+
# no further action need if substitution didn't happen or refine isn't required
86+
return placeholder_value unless is_placeholder_found && refine
8587

8688
# ENV ${var} value may carry single quote or escaped double quote
8789
# or single/double quoted entries in array string, needs to be refined

qa/integration/specs/multiple_pipeline_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
let(:temporary_out_file_1) { Stud::Temporary.pathname }
3636
let(:temporary_out_file_2) { Stud::Temporary.pathname }
37+
let(:temporary_out_file_3) { Stud::Temporary.pathname }
3738

3839
let(:pipelines) {[
3940
{
@@ -47,6 +48,12 @@
4748
"pipeline.workers" => 1,
4849
"pipeline.batch.size" => 1,
4950
"config.string" => "input { generator { count => 1 } } output { file { path => \"#{temporary_out_file_2}\" } }"
51+
},
52+
{
53+
"pipeline.id" => "config-string-with-env-var-pipeline",
54+
"pipeline.workers" => 1,
55+
"pipeline.batch.size" => 1,
56+
"config.string" => "input { generator { count => 1 } } output { file { path => \"${TEMP_FILE_PATH}\" } }"
5057
}
5158
]}
5259

@@ -65,6 +72,7 @@
6572

6673
it "executes the multiple pipelines" do
6774
logstash_service = @fixture.get_service("logstash")
75+
logstash_service.env_variables = {'TEMP_FILE_PATH' => temporary_out_file_3}
6876
logstash_service.spawn_logstash("--path.settings", settings_dir, "--log.level=debug")
6977
try(retry_attempts) do
7078
expect(logstash_service.exited?).to be(true)
@@ -74,6 +82,8 @@
7482
expect(IO.readlines(temporary_out_file_1).size).to eq(1)
7583
expect(File.exist?(temporary_out_file_2)).to be(true)
7684
expect(IO.readlines(temporary_out_file_2).size).to eq(1)
85+
expect(File.exist?(temporary_out_file_3)).to be(true)
86+
expect(IO.readlines(temporary_out_file_3).size).to eq(1)
7787
end
7888

7989
context 'effectively-empty pipelines.yml file' do

0 commit comments

Comments
 (0)