-
Notifications
You must be signed in to change notification settings - Fork 495
(maint) Avoid deadlock of Facter::Core::Execution.execute #2114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| test_name "Facter::Core::Execution doesn't kill process with long stderr message" do | ||
| tag 'risk:high' | ||
|
|
||
| confine :except, :platform => /windows/ | ||
|
|
||
| long_output = "This is a very long error message. " * 4096 | ||
| file_content = <<-EOM | ||
| #!/bin/sh | ||
| echo 'newfact=value_of_fact' | ||
| 1>&2 echo #{long_output} | ||
| exit 1 | ||
| EOM | ||
|
|
||
|
|
||
| agents.each do |agent| | ||
|
|
||
| external_dir = agent.tmpdir('external_dir') | ||
| fact_file = File.join(external_dir, 'test.sh') | ||
| create_remote_file(agent, fact_file, file_content) | ||
| agent.chmod('+x', fact_file) | ||
|
|
||
| teardown do | ||
| agent.rm_rf(external_dir) | ||
| end | ||
|
|
||
| step "Facter: should resolve the external fact and print as warning script's stderr message" do | ||
| on agent, facter('--external-dir', external_dir, 'newfact') do |facter_output| | ||
| assert_match(/value_of_fact/, facter_output.stdout.chomp) | ||
| assert_match(/WARN test.sh .*test.sh resulted with the following stderr message: This is a very long error message./, facter_output.stderr.chomp) | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -90,7 +90,7 @@ def builtin_command?(command) | |
| end | ||
|
|
||
| def execute_command(command, on_fail, logger = nil, time_limit = nil) | ||
| time_limit ||= 1.5 | ||
| time_limit ||= 300 | ||
| begin | ||
| # Set LC_ALL and LANG to force i18n to C for the duration of this exec; | ||
| # this ensures that any code that parses the | ||
|
|
@@ -100,18 +100,24 @@ def execute_command(command, on_fail, logger = nil, time_limit = nil) | |
| @log.debug("Executing command: #{command}") | ||
| out, stderr = Open3.popen3(opts, command.to_s) do |_, stdout, stderr, wait_thr| | ||
| pid = wait_thr.pid | ||
| output = +'' | ||
| err = +'' | ||
| stdout_messages = +'' | ||
| stderr_messages = +'' | ||
|
Comment on lines
+103
to
+104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not use a simple initialize? stdout_messages = ''
stderr_messages = ''
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. they will be treated as frozen strings and this will generate an error later when we try to append the output of the command to these strings
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've started using
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately i get the following error when i try to use |
||
| out_reader = Thread.new { stdout.read } | ||
| err_reader = Thread.new { stderr.read } | ||
| begin | ||
| Timeout.timeout(time_limit) do | ||
| output << stdout.read | ||
| err << stderr.read | ||
| stdout_messages << out_reader.value | ||
| stderr_messages << err_reader.value | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
| end | ||
| rescue Timeout::Error | ||
| @log.debug("Timeout encounter after #{time_limit}s, killing process with pid: #{pid}") | ||
| message = "Timeout encounter after #{time_limit}s, killing process with pid: #{pid}" | ||
| Process.kill('KILL', pid) | ||
| on_fail == :raise ? (raise StandardError, message) : @log.debug(message) | ||
| ensure | ||
| out_reader.kill | ||
| err_reader.kill | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i wrapped the threads kill in an |
||
| end | ||
| [output, err] | ||
| [stdout_messages, stderr_messages] | ||
| end | ||
| log_stderr(stderr, command, logger) | ||
| rescue StandardError => e | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make use of ruby here, to generate the needed text, eg:
And play with the
lengthto achieve the expected output.Also i think would be useful to add some description to this scenario and what is this test doing