From 15af762bfdbac0c8dd345698b34ea4c2fe93dedc Mon Sep 17 00:00:00 2001 From: Matt Wrock Date: Thu, 24 Sep 2015 17:23:38 -0700 Subject: kill all windows child processes when the command times out --- lib/mixlib/shellout/windows.rb | 15 +++++++++++++++ mixlib-shellout.gemspec | 1 + spec/mixlib/shellout_spec.rb | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/lib/mixlib/shellout/windows.rb b/lib/mixlib/shellout/windows.rb index 6003ae8..3661640 100644 --- a/lib/mixlib/shellout/windows.rb +++ b/lib/mixlib/shellout/windows.rb @@ -107,6 +107,9 @@ module Mixlib # Kill the process if (Time.now - start_wait) > timeout begin + require 'wmi-lite/wmi' + wmi = WmiLite::Wmi.new + Utils.kill_process_tree(process.process_id, wmi) Process.kill(:KILL, process.process_id) rescue Errno::EIO logger.warn("Failed to kill timed out process #{process.process_id}") if logger @@ -313,6 +316,18 @@ module Mixlib def self.executable?(path) File.executable?(path) && !File.directory?(path) end + + def self.kill_process_tree(pid, wmi) + wmi.query("select ProcessID, Name from Win32_Process where ParentProcessID=#{pid}").each do |instance| + child_pid = instance.wmi_ole_object.processid + kill_process_tree(child_pid, wmi) + begin + Process.kill(:kill, child_pid) + rescue Errno::EIO + logger.warn("Failed to kill child process #{child_pid}::#{instance.wmi_ole_object.Name} of parent #{pid}") if logger + end + end + end end end # class end diff --git a/mixlib-shellout.gemspec b/mixlib-shellout.gemspec index b35fe08..ed23fd1 100644 --- a/mixlib-shellout.gemspec +++ b/mixlib-shellout.gemspec @@ -14,6 +14,7 @@ Gem::Specification.new do |s| s.required_ruby_version = ">= 1.9.3" + s.add_dependency "wmi-lite", "~> 1.0" s.add_development_dependency "rspec", "~> 3.0" s.bindir = "bin" diff --git a/spec/mixlib/shellout_spec.rb b/spec/mixlib/shellout_spec.rb index 2acdc3b..6b57619 100644 --- a/spec/mixlib/shellout_spec.rb +++ b/spec/mixlib/shellout_spec.rb @@ -1116,11 +1116,24 @@ describe Mixlib::ShellOut do 'powershell -c "sleep 10"' end + before do + require "wmi-lite/wmi" + allow(WmiLite::Wmi).to receive(:new) + allow(Mixlib::ShellOut::Windows::Utils).to receive(:kill_process_tree) + end + it "should raise CommandTimeout" do Timeout::timeout(5) do expect { executed_cmd }.to raise_error(Mixlib::ShellOut::CommandTimeout) end end + + context 'and child processes should be killed' do + it 'kills the child processes' do + expect(Mixlib::ShellOut::Windows::Utils).to receive(:kill_process_tree) + expect { executed_cmd }.to raise_error(Mixlib::ShellOut::CommandTimeout) + end + end end context 'on unix', :unix_only do -- cgit v1.2.1