mixlib-shellout 3.2.6 → 3.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mixlib/shellout/helper.rb +39 -4
- data/lib/mixlib/shellout/unix.rb +23 -14
- data/lib/mixlib/shellout/version.rb +1 -1
- data/lib/mixlib/shellout/windows.rb +6 -0
- data/lib/mixlib/shellout.rb +8 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a9ab082811bde7ebba65cb6d326ff71d9f55e6a9a8d966a9294a173c56cf35b
|
4
|
+
data.tar.gz: 8eb25e4d17a30d1d1fc1e8a3f9e6fa0434dc6c692f4e461980d7cd670cbceb2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0ae915100dd53a40c78f3c6dc7439d99de2684b9a057cdbbc724cf8c41997c5a279912af76f4e3b00b9b732c207f98ca9d2e3f5225b30e5aea3941c21c65646
|
7
|
+
data.tar.gz: 9a4d490d87c8f9d2297c84ef7e81e844769d581b59b1bca36c8ed2a50a8a41e7909d5c788e36207b8f224002ecc7a1ad263d09b272598fce6ae16a45fe47d52f
|
@@ -141,9 +141,43 @@ module Mixlib
|
|
141
141
|
args.flatten.compact.map(&:to_s)
|
142
142
|
end
|
143
143
|
|
144
|
+
# Join arguments into a string.
|
145
|
+
#
|
146
|
+
# Strips leading/trailing spaces from each argument. If an argument contains
|
147
|
+
# a space, it is quoted. Join into a single string with spaces between each argument.
|
148
|
+
#
|
149
|
+
# @param args [String] variable number of string arguments
|
150
|
+
# @return [String] merged string
|
151
|
+
#
|
152
|
+
def __join_whitespace(*args, quote: false)
|
153
|
+
args.map do |arg|
|
154
|
+
if arg.is_a?(Array)
|
155
|
+
__join_whitespace(*arg, quote: arg.count > 1)
|
156
|
+
else
|
157
|
+
arg = arg.include?(" ") ? sprintf('"%s"', arg) : arg if quote
|
158
|
+
arg.strip
|
159
|
+
end
|
160
|
+
end.join(" ")
|
161
|
+
end
|
162
|
+
|
144
163
|
def __shell_out_command(*args, **options)
|
145
164
|
if __transport_connection
|
146
|
-
|
165
|
+
command = __join_whitespace(args)
|
166
|
+
unless ChefUtils.windows?
|
167
|
+
if options[:cwd]
|
168
|
+
# as `timeout` is used, commands need to be executed in a subshell
|
169
|
+
command = "sh -c 'cd #{options[:cwd]}; #{command}'"
|
170
|
+
end
|
171
|
+
|
172
|
+
if options[:input]
|
173
|
+
command.concat "<<'COMMANDINPUT'\n"
|
174
|
+
command.concat __join_whitespace(options[:input])
|
175
|
+
command.concat "\nCOMMANDINPUT\n"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# FIXME: train should accept run_command(*args)
|
180
|
+
FakeShellOut.new(args, options, __transport_connection.run_command(command, options))
|
147
181
|
else
|
148
182
|
cmd = if options.empty?
|
149
183
|
Mixlib::ShellOut.new(*args)
|
@@ -181,15 +215,16 @@ module Mixlib
|
|
181
215
|
@stdout = result.stdout
|
182
216
|
@stderr = result.stderr
|
183
217
|
@exitstatus = result.exit_status
|
184
|
-
@
|
218
|
+
@valid_exit_codes = Array(options[:returns] || 0)
|
219
|
+
@status = OpenStruct.new(success?: (@valid_exit_codes.include? exitstatus))
|
185
220
|
end
|
186
221
|
|
187
222
|
def error?
|
188
|
-
exitstatus
|
223
|
+
@valid_exit_codes.none?(exitstatus)
|
189
224
|
end
|
190
225
|
|
191
226
|
def error!
|
192
|
-
raise Mixlib::ShellOut::ShellCommandFailed, "Unexpected exit status of #{exitstatus} running #{@args}" if error?
|
227
|
+
raise Mixlib::ShellOut::ShellCommandFailed, "Unexpected exit status of #{exitstatus} running #{@args}: #{stderr}" if error?
|
193
228
|
end
|
194
229
|
end
|
195
230
|
end
|
data/lib/mixlib/shellout/unix.rb
CHANGED
@@ -16,15 +16,12 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
+
require "fileutils" unless defined?(FileUtils)
|
20
|
+
|
19
21
|
module Mixlib
|
20
22
|
class ShellOut
|
21
23
|
module Unix
|
22
24
|
|
23
|
-
# "1.8.7" as a frozen string. We use this with a hack that disables GC to
|
24
|
-
# avoid segfaults on Ruby 1.8.7, so we need to allocate the fewest
|
25
|
-
# objects we possibly can.
|
26
|
-
ONE_DOT_EIGHT_DOT_SEVEN = "1.8.7".freeze
|
27
|
-
|
28
25
|
# Option validation that is unix specific
|
29
26
|
def validate_options(opts)
|
30
27
|
if opts[:elevated]
|
@@ -99,12 +96,6 @@ module Mixlib
|
|
99
96
|
|
100
97
|
configure_parent_process_file_descriptors
|
101
98
|
|
102
|
-
# Ruby 1.8.7 and 1.8.6 from mid 2009 try to allocate objects during GC
|
103
|
-
# when calling IO.select and IO#read. Disabling GC works around the
|
104
|
-
# segfault, but obviously it's a bad workaround. We no longer support
|
105
|
-
# 1.8.6 so we only need this hack for 1.8.7.
|
106
|
-
GC.disable if RUBY_VERSION == ONE_DOT_EIGHT_DOT_SEVEN
|
107
|
-
|
108
99
|
# CHEF-3390: Marshall.load on Ruby < 1.8.7p369 also has a GC bug related
|
109
100
|
# to Marshall.load, so try disabling GC first.
|
110
101
|
propagate_pre_exec_failure
|
@@ -142,7 +133,7 @@ module Mixlib
|
|
142
133
|
reap_errant_child if should_reap?
|
143
134
|
# make one more pass to get the last of the output after the
|
144
135
|
# child process dies
|
145
|
-
attempt_buffer_read
|
136
|
+
attempt_buffer_read(0)
|
146
137
|
# no matter what happens, turn the GC back on, and hope whatever busted
|
147
138
|
# version of ruby we're on doesn't allocate some objects during the next
|
148
139
|
# GC run.
|
@@ -187,6 +178,16 @@ module Mixlib
|
|
187
178
|
Dir.chdir(cwd) if cwd
|
188
179
|
end
|
189
180
|
|
181
|
+
def set_cgroup
|
182
|
+
new_cgroup_path = "/sys/fs/cgroup/#{cgroup}"
|
183
|
+
# Create cgroup if missing
|
184
|
+
unless Dir.exist?(new_cgroup_path)
|
185
|
+
FileUtils.mkdir_p new_cgroup_path
|
186
|
+
end
|
187
|
+
# Migrate current process to newly cgroup, any subprocesses will run inside new cgroup
|
188
|
+
File.write("#{new_cgroup_path}/cgroup.procs", Process.pid.to_s)
|
189
|
+
end
|
190
|
+
|
190
191
|
# Since we call setsid the child_pgid will be the child_pid, set to negative here
|
191
192
|
# so it can be directly used in arguments to kill, wait, etc.
|
192
193
|
def child_pgid
|
@@ -276,8 +277,8 @@ module Mixlib
|
|
276
277
|
child_stdin.close # Kick things off
|
277
278
|
end
|
278
279
|
|
279
|
-
def attempt_buffer_read
|
280
|
-
ready = IO.select(open_pipes, nil, nil,
|
280
|
+
def attempt_buffer_read(timeout = READ_WAIT_TIME)
|
281
|
+
ready = IO.select(open_pipes, nil, nil, timeout)
|
281
282
|
if ready
|
282
283
|
read_stdout_to_buffer if ready.first.include?(child_stdout)
|
283
284
|
read_stderr_to_buffer if ready.first.include?(child_stderr)
|
@@ -315,6 +316,10 @@ module Mixlib
|
|
315
316
|
open_pipes.delete(child_process_status)
|
316
317
|
end
|
317
318
|
|
319
|
+
def cgroupv2_available?
|
320
|
+
File.read("/proc/mounts").match?(%r{^cgroup2 /sys/fs/cgroup})
|
321
|
+
end
|
322
|
+
|
318
323
|
def fork_subprocess
|
319
324
|
initialize_ipc
|
320
325
|
|
@@ -332,6 +337,10 @@ module Mixlib
|
|
332
337
|
|
333
338
|
configure_subprocess_file_descriptors
|
334
339
|
|
340
|
+
if cgroup && cgroupv2_available?
|
341
|
+
set_cgroup
|
342
|
+
end
|
343
|
+
|
335
344
|
set_secondarygroups
|
336
345
|
set_group
|
337
346
|
set_user
|
@@ -60,6 +60,7 @@ module Mixlib
|
|
60
60
|
stderr_read, stderr_write = IO.pipe
|
61
61
|
stdin_read, stdin_write = IO.pipe
|
62
62
|
open_streams = [ stdout_read, stderr_read ]
|
63
|
+
@execution_time = 0
|
63
64
|
|
64
65
|
begin
|
65
66
|
|
@@ -105,6 +106,8 @@ module Mixlib
|
|
105
106
|
wait_status = WaitForSingleObject(process.process_handle, 0)
|
106
107
|
case wait_status
|
107
108
|
when WAIT_OBJECT_0
|
109
|
+
# Save the execution time
|
110
|
+
@execution_time = Time.now - start_wait
|
108
111
|
# Get process exit code
|
109
112
|
exit_code = [0].pack("l")
|
110
113
|
unless GetExitCodeProcess(process.process_handle, exit_code)
|
@@ -127,6 +130,9 @@ module Mixlib
|
|
127
130
|
logger&.warn("Failed to kill timed out process #{process.process_id}")
|
128
131
|
end
|
129
132
|
|
133
|
+
# Save the execution time
|
134
|
+
@execution_time = Time.now - start_wait
|
135
|
+
|
130
136
|
raise Mixlib::ShellOut::CommandTimeout, [
|
131
137
|
"command timed out:",
|
132
138
|
format_for_exception,
|
data/lib/mixlib/shellout.rb
CHANGED
@@ -114,6 +114,9 @@ module Mixlib
|
|
114
114
|
|
115
115
|
attr_accessor :sensitive
|
116
116
|
|
117
|
+
# Path to cgroupv2 that the process should run on
|
118
|
+
attr_accessor :cgroup
|
119
|
+
|
117
120
|
# === Arguments:
|
118
121
|
# Takes a single command, or a list of command fragments. These are used
|
119
122
|
# as arguments to Kernel.exec. See the Kernel.exec documentation for more
|
@@ -179,6 +182,7 @@ module Mixlib
|
|
179
182
|
@timeout = nil
|
180
183
|
@elevated = false
|
181
184
|
@sensitive = false
|
185
|
+
@cgroup = nil
|
182
186
|
|
183
187
|
if command_args.last.is_a?(Hash)
|
184
188
|
parse_options(command_args.pop)
|
@@ -303,7 +307,8 @@ module Mixlib
|
|
303
307
|
def inspect
|
304
308
|
"<#{self.class.name}##{object_id}: command: '#{@command}' process_status: #{@status.inspect} " +
|
305
309
|
"stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " +
|
306
|
-
"environment: #{@environment.inspect} timeout: #{timeout} user: #{@user} group: #{@group} working_dir: #{@cwd}
|
310
|
+
"environment: #{@environment.inspect} timeout: #{timeout} user: #{@user} group: #{@group} working_dir: #{@cwd} " +
|
311
|
+
"cgroup: #{@cgroup} >"
|
307
312
|
end
|
308
313
|
|
309
314
|
private
|
@@ -354,6 +359,8 @@ module Mixlib
|
|
354
359
|
self.elevated = setting
|
355
360
|
when "sensitive"
|
356
361
|
self.sensitive = setting
|
362
|
+
when "cgroup"
|
363
|
+
self.cgroup = setting
|
357
364
|
else
|
358
365
|
raise InvalidCommandOption, "option '#{option.inspect}' is not a valid option for #{self.class.name}"
|
359
366
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixlib-shellout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef Software Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-utils
|
@@ -50,14 +50,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
53
|
+
version: '3.0'
|
54
54
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
55
|
requirements:
|
56
56
|
- - ">="
|
57
57
|
- !ruby/object:Gem::Version
|
58
58
|
version: '0'
|
59
59
|
requirements: []
|
60
|
-
rubygems_version: 3.
|
60
|
+
rubygems_version: 3.2.3
|
61
61
|
signing_key:
|
62
62
|
specification_version: 4
|
63
63
|
summary: Run external commands on Unix or Windows
|