diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2017-04-01 14:46:39 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-01 14:46:39 -0700 |
commit | 311d6263eed507dbd235b13916d4dd61adad7efe (patch) | |
tree | f3b18814f6faca4098ab6483d5133858637c49aa | |
parent | 5dacd74ce5cccc4dbb651a45f9e591dd1921cc6e (diff) | |
parent | 7630520f8ff4fc30ff02a35dd79e32ea7d8e42a8 (diff) | |
download | chef-311d6263eed507dbd235b13916d4dd61adad7efe.tar.gz |
Merge pull request #5985 from chef/lcg/remove-run-command
Chef-13: remove deprecated run_command API entirely
42 files changed, 118 insertions, 887 deletions
diff --git a/lib/chef/mixin/command.rb b/lib/chef/mixin/command.rb deleted file mode 100644 index b1fa7ebd89..0000000000 --- a/lib/chef/mixin/command.rb +++ /dev/null @@ -1,194 +0,0 @@ -# -# Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "chef/log" -require "chef/exceptions" -require "tmpdir" -require "fcntl" -require "etc" - -class Chef - module Mixin - - #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # NOTE: - # The popen4 method upon which all the code here is based has a race - # condition where it may fail to read all of the data written to stdout and - # stderr after the child process exits. The tests for the code here - # occasionally fail because of this race condition, so they have been - # tagged "volatile". - # - # This code is considered deprecated, so it should not need to be modified - # frequently, if at all. HOWEVER, if you do modify the code here, you must - # explicitly enable volatile tests: - # - # bundle exec rspec spec/unit/mixin/command_spec.rb -t volatile - # - # In addition, you should make a note that tests need to be run with - # volatile tests enabled on any pull request or bug report you submit with - # your patch. - #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - module Command - extend self - - # NOTE: run_command is deprecated in favor of using Chef::Shellout which now comes from the mixlib-shellout gem. NOTE # - - if RUBY_PLATFORM =~ /mswin|mingw32|windows/ - require "chef/mixin/command/windows" - include ::Chef::Mixin::Command::Windows - extend ::Chef::Mixin::Command::Windows - else - require "chef/mixin/command/unix" - include ::Chef::Mixin::Command::Unix - extend ::Chef::Mixin::Command::Unix - end - - # === Parameters - # args<Hash>: A number of required and optional arguments - # command<String>, <Array>: A complete command with options to execute or a command and options as an Array - # creates<String>: The absolute path to a file that prevents the command from running if it exists - # cwd<String>: Working directory to execute command in, defaults to Dir.tmpdir - # timeout<String>: How many seconds to wait for the command to execute before timing out - # returns<String>: The single exit value command is expected to return, otherwise causes an exception - # ignore_failure<Boolean>: Whether to raise an exception on failure, or just return the status - # output_on_failure<Boolean>: Return output in raised exception regardless of Log.level - # - # user<String>: The UID or user name of the user to execute the command as - # group<String>: The GID or group name of the group to execute the command as - # environment<Hash>: Pairs of environment variable names and their values to set before execution - # - # === Returns - # Returns the exit status of args[:command] - def run_command(args = {}) - status, stdout, stderr = run_command_and_return_stdout_stderr(args) - - status - end - - # works same as above, except that it returns stdout and stderr - # requirement => platforms like solaris 9,10 has weird issues where - # even in command failure the exit code is zero, so we need to lookup stderr. - def run_command_and_return_stdout_stderr(args = {}) - command_output = "" - - args[:ignore_failure] ||= false - args[:output_on_failure] ||= false - - # TODO: This is the wrong place for this responsibility. - if args.has_key?(:creates) - if File.exists?(args[:creates]) - Chef::Log.debug("Skipping #{args[:command]} - creates #{args[:creates]} exists.") - return false - end - end - - status, stdout, stderr = output_of_command(args[:command], args) - command_output << "STDOUT: #{stdout}" - command_output << "STDERR: #{stderr}" - handle_command_failures(status, command_output, args) - - [status, stdout, stderr] - end - - def output_of_command(command, args) - Chef.deprecated(:run_command, "Chef::Mixin::Command.run_command is deprecated, please use shell_out") - Chef::Log.debug("Executing #{command}") - stderr_string, stdout_string, status = "", "", nil - - exec_processing_block = lambda do |pid, stdin, stdout, stderr| - stdout_string, stderr_string = stdout.string.chomp, stderr.string.chomp - end - - args[:cwd] ||= Dir.tmpdir - unless ::File.directory?(args[:cwd]) - raise Chef::Exceptions::Exec, "#{args[:cwd]} does not exist or is not a directory" - end - - Dir.chdir(args[:cwd]) do - if args[:timeout] - begin - Timeout.timeout(args[:timeout]) do - status = popen4(command, args, &exec_processing_block) - end - rescue Timeout::Error => e - Chef::Log.error("#{command} exceeded timeout #{args[:timeout]}") - raise(e) - end - else - status = popen4(command, args, &exec_processing_block) - end - - Chef::Log.debug("---- Begin output of #{command} ----") - Chef::Log.debug("STDOUT: #{stdout_string}") - Chef::Log.debug("STDERR: #{stderr_string}") - Chef::Log.debug("---- End output of #{command} ----") - Chef::Log.debug("Ran #{command} returned #{status.exitstatus}") - end - - [status, stdout_string, stderr_string] - end - - def handle_command_failures(status, command_output, opts = {}) - return if opts[:ignore_failure] - opts[:returns] ||= 0 - return if Array(opts[:returns]).include?(status.exitstatus) - - # if the log level is not debug, through output of command when we fail - output = "" - if Chef::Log.level == :debug || opts[:output_on_failure] - output << "\n---- Begin output of #{opts[:command]} ----\n" - output << command_output.to_s - output << "\n---- End output of #{opts[:command]} ----\n" - end - raise Chef::Exceptions::Exec, "#{opts[:command]} returned #{status.exitstatus}, expected #{opts[:returns]}#{output}" - end - - # Call #run_command but set LC_ALL to the system's current environment so it doesn't get changed to C. - # - # === Parameters - # args<Hash>: A number of required and optional arguments that will be handed out to #run_command - # - # === Returns - # Returns the result of #run_command - def run_command_with_systems_locale(args = {}) - args[:environment] ||= {} - args[:environment]["LC_ALL"] = ENV["LC_ALL"] - run_command args - end - - # def popen4(cmd, args={}, &b) - # @@os_handler.popen4(cmd, args, &b) - # end - - # module_function :popen4 - - # FIXME: yard with @yield - def chdir_or_tmpdir(dir) - dir ||= Dir.tmpdir - unless File.directory?(dir) - raise Chef::Exceptions::Exec, "#{dir} does not exist or is not a directory" - end - Dir.chdir(dir) do - yield - end - end - - end - end -end diff --git a/lib/chef/mixin/command/unix.rb b/lib/chef/mixin/command/unix.rb deleted file mode 100644 index aa541c3637..0000000000 --- a/lib/chef/mixin/command/unix.rb +++ /dev/null @@ -1,220 +0,0 @@ -# -# Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -class Chef - module Mixin - module Command - module Unix - # This is taken directly from Ara T Howard's Open4 library, and then - # modified to suit the needs of Chef. Any bugs here are most likely - # my own, and not Ara's. - # - # The original appears in external/open4.rb in its unmodified form. - # - # Thanks Ara! - def popen4(cmd, args = {}, &b) - # Ruby 1.8 suffers from intermittent segfaults believed to be due to GC while IO.select - # See CHEF-2916 / CHEF-1305 - GC.disable - - # Waitlast - this is magic. - # - # Do we wait for the child process to die before we yield - # to the block, or after? That is the magic of waitlast. - # - # By default, we are waiting before we yield the block. - args[:waitlast] ||= false - - args[:user] ||= nil - unless args[:user].kind_of?(Integer) - args[:user] = Etc.getpwnam(args[:user]).uid if args[:user] - end - args[:group] ||= nil - unless args[:group].kind_of?(Integer) - args[:group] = Etc.getgrnam(args[:group]).gid if args[:group] - end - args[:environment] ||= {} - - # Default on C locale so parsing commands output can be done - # independently of the node's default locale. - # "LC_ALL" could be set to nil, in which case we also must ignore it. - unless args[:environment].has_key?("LC_ALL") - args[:environment]["LC_ALL"] = "C" - end - - pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe - - verbose = $VERBOSE - begin - $VERBOSE = nil - ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) - - cid = fork do - pw.last.close - STDIN.reopen pw.first - pw.first.close - - pr.first.close - STDOUT.reopen pr.last - pr.last.close - - pe.first.close - STDERR.reopen pe.last - pe.last.close - - STDOUT.sync = STDERR.sync = true - - if args[:group] - Process.egid = args[:group] - Process.gid = args[:group] - end - - if args[:user] - Process.euid = args[:user] - Process.uid = args[:user] - end - - args[:environment].each do |key, value| - ENV[key] = value - end - - if args[:umask] - umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777) - File.umask(umask) - end - - begin - if cmd.kind_of?(Array) - Kernel.exec(*cmd) - else - Kernel.exec(cmd) - end - raise "forty-two" - rescue Exception => e - Marshal.dump(e, ps.last) - ps.last.flush - end - ps.last.close unless ps.last.closed? - exit! - end - ensure - $VERBOSE = verbose - end - - [pw.first, pr.last, pe.last, ps.last].each { |fd| fd.close } - - begin - e = Marshal.load ps.first - raise(Exception === e ? e : "unknown failure!") - rescue EOFError # If we get an EOF error, then the exec was successful - 42 - ensure - ps.first.close - end - - pw.last.sync = true - - pi = [pw.last, pr.first, pe.first] - - if b - begin - if args[:waitlast] - b[cid, *pi] - # send EOF so that if the child process is reading from STDIN - # it will actually finish up and exit - pi[0].close_write - Process.waitpid2(cid).last - else - # This took some doing. - # The trick here is to close STDIN - # Then set our end of the childs pipes to be O_NONBLOCK - # Then wait for the child to die, which means any IO it - # wants to do must be done - it's dead. If it isn't, - # it's because something totally skanky is happening, - # and we don't care. - o = StringIO.new - e = StringIO.new - - pi[0].close - - stdout = pi[1] - stderr = pi[2] - - stdout.sync = true - stderr.sync = true - - stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) - stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) - - stdout_finished = false - stderr_finished = false - - results = nil - - while !stdout_finished || !stderr_finished - begin - channels_to_watch = [] - channels_to_watch << stdout if !stdout_finished - channels_to_watch << stderr if !stderr_finished - ready = IO.select(channels_to_watch, nil, nil, 1.0) - rescue Errno::EAGAIN - ensure - results = Process.waitpid2(cid, Process::WNOHANG) - if results - stdout_finished = true - stderr_finished = true - end - end - - if ready && ready.first.include?(stdout) - line = results ? stdout.gets(nil) : stdout.gets - if line - o.write(line) - else - stdout_finished = true - end - end - if ready && ready.first.include?(stderr) - line = results ? stderr.gets(nil) : stderr.gets - if line - e.write(line) - else - stderr_finished = true - end - end - end - results = Process.waitpid2(cid) unless results - o.rewind - e.rewind - b[cid, pi[0], o, e] - results.last - end - ensure - pi.each { |fd| fd.close unless fd.closed? } - end - else - [cid, pw.last, pr.first, pe.first] - end - ensure - GC.enable - end - - end - end - end -end diff --git a/lib/chef/mixin/command/windows.rb b/lib/chef/mixin/command/windows.rb deleted file mode 100644 index fd45ab0467..0000000000 --- a/lib/chef/mixin/command/windows.rb +++ /dev/null @@ -1,71 +0,0 @@ -# -# Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. -# Author:: Doug MacEachern (<dougm@vmware.com>) -# Copyright:: Copyright 2010-2016, VMware, Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "open3" - -class Chef - module Mixin - module Command - module Windows - def popen4(cmd, args = {}, &b) - # By default, we are waiting before we yield the block. - args[:waitlast] ||= false - - #XXX :user, :group, :environment support? - - Open3.popen3(cmd) do |stdin, stdout, stderr, cid| - if b - if args[:waitlast] - b[cid, stdin, stdout, stderr] - # send EOF so that if the child process is reading from STDIN - # it will actually finish up and exit - stdin.close_write - else - o = StringIO.new - e = StringIO.new - - stdin.close - - stdout.sync = true - stderr.sync = true - - line = stdout.gets(nil) - if line - o.write(line) - end - line = stderr.gets(nil) - if line - e.write(line) - end - o.rewind - e.rewind - b[cid, stdin, o, e] - end - else - [cid, stdin, stdout, stderr] - end - end - $? - end - - end - end - end -end diff --git a/lib/chef/mixins.rb b/lib/chef/mixins.rb index b980e81287..2306fb9e89 100644 --- a/lib/chef/mixins.rb +++ b/lib/chef/mixins.rb @@ -1,6 +1,5 @@ require "chef/mixin/shell_out" require "chef/mixin/checksum" -require "chef/mixin/command" require "chef/mixin/convert_to_class_name" require "chef/mixin/create_path" require "chef/mixin/deep_merge" diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb index a45e889bcc..c232585c18 100644 --- a/lib/chef/provider/cron.rb +++ b/lib/chef/provider/cron.rb @@ -17,13 +17,11 @@ # require "chef/log" -require "chef/mixin/command" require "chef/provider" class Chef class Provider class Cron < Chef::Provider - include Chef::Mixin::Command provides :cron, os: ["!aix", "!solaris2"] @@ -202,30 +200,18 @@ class Chef end def read_crontab - crontab = nil - status = popen4("crontab -l -u #{new_resource.user}") do |pid, stdin, stdout, stderr| - crontab = stdout.read - end - if status.exitstatus > 1 - raise Chef::Exceptions::Cron, "Error determining state of #{new_resource.name}, exit: #{status.exitstatus}" - end - crontab + so = shell_out!("crontab -l -u #{new_resource.user}", returns: [0, 1]) + return nil if so.exitstatus == 1 + so.stdout + rescue => e + raise Chef::Exceptions::Cron, "Error determining state of #{new_resource.name}, error: #{e}" end def write_crontab(crontab) write_exception = false - status = popen4("crontab -u #{new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr| - begin - stdin.write crontab - rescue Errno::EPIPE => e - # popen4 could yield while child has already died. - write_exception = true - Chef::Log.debug("#{e.message}") - end - end - if status.exitstatus > 0 || write_exception - raise Chef::Exceptions::Cron, "Error updating state of #{new_resource.name}, exit: #{status.exitstatus}" - end + so = shell_out!("crontab -u #{new_resource.user} -", input: crontab) + rescue => e + raise Chef::Exceptions::Cron, "Error updating state of #{new_resource.name}, error: #{e}" end def get_crontab_entry diff --git a/lib/chef/provider/deploy.rb b/lib/chef/provider/deploy.rb index 172705ac71..c4229d2441 100644 --- a/lib/chef/provider/deploy.rb +++ b/lib/chef/provider/deploy.rb @@ -16,7 +16,6 @@ # limitations under the License. # -require "chef/mixin/command" require "chef/mixin/from_file" require "chef/provider/git" require "chef/provider/subversion" @@ -29,7 +28,6 @@ class Chef include Chef::DSL::Recipe include Chef::Mixin::FromFile - include Chef::Mixin::Command attr_reader :scm_provider, :release_path, :shared_path, :previous_release_path diff --git a/lib/chef/provider/env.rb b/lib/chef/provider/env.rb index 7777da183d..490fa31146 100644 --- a/lib/chef/provider/env.rb +++ b/lib/chef/provider/env.rb @@ -17,13 +17,11 @@ # require "chef/provider" -require "chef/mixin/command" require "chef/resource/env" class Chef class Provider class Env < Chef::Provider - include Chef::Mixin::Command attr_accessor :key_exists provides :env, os: "!windows" diff --git a/lib/chef/provider/erl_call.rb b/lib/chef/provider/erl_call.rb index 26ac19d03b..b73341bb16 100644 --- a/lib/chef/provider/erl_call.rb +++ b/lib/chef/provider/erl_call.rb @@ -17,13 +17,11 @@ # require "chef/log" -require "chef/mixin/command" require "chef/provider" class Chef class Provider class ErlCall < Chef::Provider - include Chef::Mixin::Command provides :erl_call @@ -58,44 +56,18 @@ class Chef command = "erl_call -e #{distributed} #{node} #{cookie}" converge_by("run erlang block") do - begin - pid, stdin, stdout, stderr = popen4(command, :waitlast => true) + so = shell_out!(command, input: new_resource.code) - Chef::Log.debug("#{new_resource} running") - Chef::Log.debug("#{new_resource} command: #{command}") - Chef::Log.debug("#{new_resource} code: #{new_resource.code}") - - new_resource.code.each_line { |line| stdin.puts(line.chomp) } - - stdin.close - - Chef::Log.debug("#{new_resource} output: ") - - stdout_output = "" - stdout.each_line { |line| stdout_output << line } - stdout.close - - stderr_output = "" - stderr.each_line { |line| stderr_output << line } - stderr.close - - # fail if stderr contains anything - if stderr_output.length > 0 - raise Chef::Exceptions::ErlCall, stderr_output - end - - # fail if the first 4 characters aren't "{ok," - unless stdout_output[0..3].include?("{ok,") - raise Chef::Exceptions::ErlCall, stdout_output - end - - new_resource.updated_by_last_action(true) + # fail if stderr contains anything + if so.stderr.length > 0 + raise Chef::Exceptions::ErlCall, so.stderr + end - Chef::Log.debug("#{new_resource} #{stdout_output}") - Chef::Log.info("#{@new_resouce} ran successfully") - ensure - Process.wait(pid) if pid + # fail if the first 4 characters aren't "{ok," + unless so.stdout[0..3].include?("{ok,") + raise Chef::Exceptions::ErlCall, so.stdout end + end end diff --git a/lib/chef/provider/group.rb b/lib/chef/provider/group.rb index 82196c72f3..ce20a2b5e5 100644 --- a/lib/chef/provider/group.rb +++ b/lib/chef/provider/group.rb @@ -18,14 +18,12 @@ require "chef/provider" require "chef/mixin/shell_out" -require "chef/mixin/command" require "etc" class Chef class Provider class Group < Chef::Provider include Chef::Mixin::ShellOut - include Chef::Mixin::Command attr_accessor :group_exists attr_accessor :change_desc diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb index 003cc3b0e0..16bbe8124b 100644 --- a/lib/chef/provider/ifconfig.rb +++ b/lib/chef/provider/ifconfig.rb @@ -17,7 +17,6 @@ # require "chef/log" -require "chef/mixin/command" require "chef/mixin/shell_out" require "chef/provider" require "chef/resource/file" @@ -42,7 +41,6 @@ class Chef provides :ifconfig include Chef::Mixin::ShellOut - include Chef::Mixin::Command attr_accessor :config_template attr_accessor :config_path diff --git a/lib/chef/provider/mdadm.rb b/lib/chef/provider/mdadm.rb index 5c972462bc..7d7b26acfa 100644 --- a/lib/chef/provider/mdadm.rb +++ b/lib/chef/provider/mdadm.rb @@ -25,10 +25,6 @@ class Chef provides :mdadm - def popen4 - raise Exception, "deprecated" - end - def load_current_resource @current_resource = Chef::Resource::Mdadm.new(new_resource.name) current_resource.raid_device(new_resource.raid_device) diff --git a/lib/chef/provider/osx_profile.rb b/lib/chef/provider/osx_profile.rb index 8ecde54ce0..1d87f29eb2 100644 --- a/lib/chef/provider/osx_profile.rb +++ b/lib/chef/provider/osx_profile.rb @@ -25,7 +25,6 @@ require "uuidtools" class Chef class Provider class OsxProfile < Chef::Provider - include Chef::Mixin::Command provides :osx_profile, os: "darwin" provides :osx_config_profile, os: "darwin" diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index 36df048741..6d4535fff5 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -17,7 +17,6 @@ # require "chef/mixin/shell_out" -require "chef/mixin/command" require "chef/mixin/subclass_directive" require "chef/log" require "chef/file_cache" @@ -28,7 +27,6 @@ require "shellwords" class Chef class Provider class Package < Chef::Provider - include Chef::Mixin::Command include Chef::Mixin::ShellOut extend Chef::Mixin::SubclassDirective diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb index 5af5f5afad..b013b3d8ce 100644 --- a/lib/chef/provider/package/aix.rb +++ b/lib/chef/provider/package/aix.rb @@ -17,7 +17,6 @@ # # require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" require "chef/mixin/get_source_from_package" diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb index 9666013cc3..d0c8bed175 100644 --- a/lib/chef/provider/package/ips.rb +++ b/lib/chef/provider/package/ips.rb @@ -19,7 +19,6 @@ require "open3" require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" class Chef diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb index 25683687b2..d1830bdefa 100644 --- a/lib/chef/provider/package/pacman.rb +++ b/lib/chef/provider/package/pacman.rb @@ -17,7 +17,6 @@ # require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" class Chef diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb index fd96dfa47f..05a5df370e 100644 --- a/lib/chef/provider/package/portage.rb +++ b/lib/chef/provider/package/portage.rb @@ -17,7 +17,6 @@ # require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" require "chef/util/path_helper" diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb index 1701886191..7ec24f8c24 100644 --- a/lib/chef/provider/package/rpm.rb +++ b/lib/chef/provider/package/rpm.rb @@ -16,7 +16,6 @@ # limitations under the License. # require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" require "chef/mixin/get_source_from_package" diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb index 1019b8d3fa..9bf8fb5fbc 100644 --- a/lib/chef/provider/package/rubygems.rb +++ b/lib/chef/provider/package/rubygems.rb @@ -19,7 +19,6 @@ require "uri" require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" require "chef/mixin/get_source_from_package" diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb index 5537127310..f6e66c050a 100644 --- a/lib/chef/provider/package/solaris.rb +++ b/lib/chef/provider/package/solaris.rb @@ -16,7 +16,6 @@ # limitations under the License. # require "chef/provider/package" -require "chef/mixin/command" require "chef/resource/package" require "chef/mixin/get_source_from_package" diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb index 2e2a1266b4..59d516be6a 100644 --- a/lib/chef/provider/route.rb +++ b/lib/chef/provider/route.rb @@ -17,14 +17,12 @@ # require "chef/log" -require "chef/mixin/command" require "chef/provider" require "ipaddr" class Chef class Provider class Route < Chef::Provider - include Chef::Mixin::Command provides :route diff --git a/lib/chef/provider/service.rb b/lib/chef/provider/service.rb index 11d04eaca2..9f06e2eb25 100644 --- a/lib/chef/provider/service.rb +++ b/lib/chef/provider/service.rb @@ -17,15 +17,12 @@ # limitations under the License. # -require "chef/mixin/command" require "chef/provider" class Chef class Provider class Service < Chef::Provider - include Chef::Mixin::Command - def supports @supports ||= new_resource.supports.dup end diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb index 9d11032055..58a43d27f8 100644 --- a/lib/chef/provider/service/debian.rb +++ b/lib/chef/provider/service/debian.rb @@ -1,6 +1,6 @@ # # Author:: AJ Christensen (<aj@hjksolutions.com>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,8 +35,6 @@ class Chef def load_current_resource super - @priority_success = true - @rcd_status = nil current_resource.priority(get_priority) current_resource.enabled(service_currently_enabled?(current_resource.priority)) current_resource @@ -54,8 +52,8 @@ class Chef end requirements.assert(:all_actions) do |a| - a.assertion { @priority_success } - a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}" + a.assertion { @so_priority.exitstatus == 0 } + a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@so_priority.inspect}" # This can happen if the service is not yet installed,so we'll fake it. a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.", "Assigning temporary priorities to continue.", @@ -75,19 +73,18 @@ class Chef def get_priority priority = {} - @rcd_status = popen4("/usr/sbin/update-rc.d -n -f #{current_resource.service_name} remove") do |pid, stdin, stdout, stderr| - - [stdout, stderr].each do |iop| - iop.each_line do |line| - if UPDATE_RC_D_PRIORITIES =~ line - # priority[runlevel] = [ S|K, priority ] - # S = Start, K = Kill - # debian runlevels: 0 Halt, 1 Singleuser, 2 Multiuser, 3-5 == 2, 6 Reboot - priority[$1] = [($2 == "S" ? :start : :stop), $3] - end - if line =~ UPDATE_RC_D_ENABLED_MATCHES - enabled = true - end + @so_priority = shell_out!("/usr/sbin/update-rc.d -n -f #{current_resource.service_name} remove") + + [@so_priority.stdout, @so_priority.stderr].each do |iop| + iop.each_line do |line| + if UPDATE_RC_D_PRIORITIES =~ line + # priority[runlevel] = [ S|K, priority ] + # S = Start, K = Kill + # debian runlevels: 0 Halt, 1 Singleuser, 2 Multiuser, 3-5 == 2, 6 Reboot + priority[$1] = [($2 == "S" ? :start : :stop), $3] + end + if line =~ UPDATE_RC_D_ENABLED_MATCHES + enabled = true end end end @@ -98,9 +95,6 @@ class Chef priority = priority[2].last end - unless @rcd_status.exitstatus == 0 - @priority_success = false - end priority end diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb index 9746dfdef0..c1e315afee 100644 --- a/lib/chef/provider/service/freebsd.rb +++ b/lib/chef/provider/service/freebsd.rb @@ -18,7 +18,6 @@ require "chef/resource/service" require "chef/provider/service/init" -require "chef/mixin/command" class Chef class Provider diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb index 7bb57113ac..0ac74649b6 100644 --- a/lib/chef/provider/service/gentoo.rb +++ b/lib/chef/provider/service/gentoo.rb @@ -18,7 +18,6 @@ # require "chef/provider/service/init" -require "chef/mixin/command" require "chef/util/path_helper" class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb index dff627d016..c6c582f8b8 100644 --- a/lib/chef/provider/service/init.rb +++ b/lib/chef/provider/service/init.rb @@ -17,7 +17,6 @@ # require "chef/provider/service/simple" -require "chef/mixin/command" require "chef/platform/service_helpers" class Chef diff --git a/lib/chef/provider/service/openbsd.rb b/lib/chef/provider/service/openbsd.rb index 780337e1b6..f839d54780 100644 --- a/lib/chef/provider/service/openbsd.rb +++ b/lib/chef/provider/service/openbsd.rb @@ -16,7 +16,6 @@ # limitations under the License. # -require "chef/mixin/command" require "chef/mixin/shell_out" require "chef/provider/service/init" require "chef/resource/service" diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb index 84ced52071..81ac970b87 100644 --- a/lib/chef/provider/service/simple.rb +++ b/lib/chef/provider/service/simple.rb @@ -18,7 +18,6 @@ require "chef/provider/service" require "chef/resource/service" -require "chef/mixin/command" class Chef class Provider diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb index c560bed011..9c85fda05f 100644 --- a/lib/chef/provider/service/solaris.rb +++ b/lib/chef/provider/service/solaris.rb @@ -18,7 +18,6 @@ require "chef/provider/service" require "chef/resource/service" -require "chef/mixin/command" class Chef class Provider diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb index 9c0d97d376..9783b3b3a5 100644 --- a/lib/chef/provider/service/upstart.rb +++ b/lib/chef/provider/service/upstart.rb @@ -18,7 +18,6 @@ require "chef/resource/service" require "chef/provider/service/simple" -require "chef/mixin/command" require "chef/util/file_edit" class Chef @@ -241,17 +240,16 @@ class Chef def upstart_goal_state command = "/sbin/status #{@job}" - status = popen4(command) do |pid, stdin, stdout, stderr| - stdout.each_line do |line| - # service goal/state - # OR - # service (instance) goal/state - # OR - # service (goal) state - line =~ UPSTART_STATE_FORMAT - data = Regexp.last_match - return data[1] - end + so = shell_out(command) + so.stdout.each_line do |line| + # service goal/state + # OR + # service (instance) goal/state + # OR + # service (goal) state + line =~ UPSTART_STATE_FORMAT + data = Regexp.last_match + return data[1] end end diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb index d7e26f3968..4fece0ae40 100644 --- a/lib/chef/provider/subversion.rb +++ b/lib/chef/provider/subversion.rb @@ -20,7 +20,6 @@ require "chef/log" require "chef/provider" -require "chef/mixin/command" require "chef-config/mixin/fuzzy_hostname_matcher" require "fileutils" @@ -32,7 +31,6 @@ class Chef SVN_INFO_PATTERN = /^([\w\s]+): (.+)$/ - include Chef::Mixin::Command include ChefConfig::Mixin::FuzzyHostnameMatcher def load_current_resource diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb index dcfee22c31..abdff441a5 100644 --- a/lib/chef/provider/user.rb +++ b/lib/chef/provider/user.rb @@ -17,13 +17,11 @@ # require "chef/provider" -require "chef/mixin/command" require "etc" class Chef class Provider class User < Chef::Provider - include Chef::Mixin::Command attr_accessor :user_exists, :locked diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb index cf47bb7fde..06bd221d26 100644 --- a/lib/chef/provider/user/pw.rb +++ b/lib/chef/provider/user/pw.rb @@ -94,13 +94,7 @@ class Chef if !new_resource.password.nil? && (current_resource.password != new_resource.password) Chef::Log.debug("#{new_resource} updating password") command = "pw usermod #{new_resource.username} -H 0" - status = popen4(command, waitlast: true) do |pid, stdin, stdout, stderr| - stdin.puts new_resource.password.to_s - end - - unless status.exitstatus == 0 - raise Chef::Exceptions::User, "pw failed - #{status.inspect}!" - end + shell_out!(command, input: new_resource.password.to_s) else Chef::Log.debug("#{new_resource} no change needed to password") end diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb index f5948191c5..1bff8bf874 100644 --- a/spec/functional/resource/cron_spec.rb +++ b/spec/functional/resource/cron_spec.rb @@ -1,7 +1,7 @@ # encoding: UTF-8 # # Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>) -# Copyright:: Copyright 2013-2016, Chef Software Inc. +# Copyright:: Copyright 2013-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -161,7 +161,7 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do end def cron_create_should_raise_exception - expect { new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/) + expect { new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron) cron_should_not_exists(new_resource.name) end diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb index 8c8d7ba482..08c791f2d2 100644 --- a/spec/functional/shell_spec.rb +++ b/spec/functional/shell_spec.rb @@ -1,6 +1,6 @@ # # Author:: Daniel DeLeo (<dan@chef.io>) -# Copyright:: Copyright 2012-2016, Chef Software, Inc. +# Copyright:: Copyright 2012-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,6 @@ require "spec_helper" require "functional/resource/base" require "chef/version" require "chef/shell" -require "chef/mixin/command/unix" describe Shell do @@ -28,7 +27,6 @@ describe Shell do # not catch cases where chef-shell fails to boot because of changes in # chef/client.rb describe "smoke tests", :unix_only => true do - include Chef::Mixin::Command::Unix TIMEOUT = 300 @@ -79,44 +77,26 @@ describe Shell do end def run_chef_shell_with(options) - case ohai[:platform] - when "aix" - config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA) - path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__) - output = "" - status = popen4("#{path_to_chef_shell} -c #{config} #{options}", :waitlast => true) do |pid, stdin, stdout, stderr| - read_until(stdout, "chef (#{Chef::VERSION})>") - yield stdout, stdin if block_given? - stdin.write("'done'\n") - output = read_until(stdout, '=> "done"') - stdin.print("exit\n") - flush_output(stdout) - end - - [output, status.exitstatus] - else - # Windows ruby installs don't (always?) have PTY, - # so hide the require here - begin - require "pty" - config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA) - path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__) - reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}") - read_until(reader, "chef (#{Chef::VERSION})>") - yield reader, writer if block_given? - writer.puts('"done"') - output = read_until(reader, '=> "done"') - writer.print("exit\n") - flush_output(reader) - writer.close - - exitstatus = wait_or_die(pid) - - [output, exitstatus] - rescue PTY::ChildExited => e - [output, e.status] - end - end + # Windows ruby installs don't (always?) have PTY, + # so hide the require here + + require "pty" + config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA) + path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__) + reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}") + read_until(reader, "chef (#{Chef::VERSION})>") + yield reader, writer if block_given? + writer.puts('"done"') + output = read_until(reader, '=> "done"') + writer.print("exit\n") + flush_output(reader) + writer.close + + exitstatus = wait_or_die(pid) + + [output, exitstatus] + rescue PTY::ChildExited => e + [output, e.status] end it "boots correctly with -lauto" do diff --git a/spec/unit/mixin/command_spec.rb b/spec/unit/mixin/command_spec.rb deleted file mode 100644 index e9f0dacad6..0000000000 --- a/spec/unit/mixin/command_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# -# Author:: Hongli Lai (hongli@phusion.nl) -# Copyright:: Copyright 2009-2016, Phusion -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "spec_helper" - -describe Chef::Mixin::Command, :volatile do - - if windows? - - skip("TODO MOVE: this is a platform specific integration test.") - - else - - describe "popen4" do - include Chef::Mixin::Command - - it "should be possible to read the child process's stdout and stderr" do - popen4("sh -c 'echo hello && echo world >&2'") do |pid, stdin, stdout, stderr| - expect(stdout.read).to eq("hello\n") - expect(stderr.read).to eq("world\n") - end - end - - it "should default all commands to be run in the POSIX standard C locale" do - popen4("echo $LC_ALL") do |pid, stdin, stdout, stderr| - expect(stdout.read.strip).to eq("C") - end - end - - it "should respect locale when specified explicitly" do - popen4("echo $LC_ALL", :environment => { "LC_ALL" => "es" }) do |pid, stdin, stdout, stderr| - expect(stdout.read.strip).to eq("es") - end - end - - it "should end when the child process reads from STDIN and a block is given" do - expect do - Timeout.timeout(10) do - popen4("ruby -e 'while gets; end'", :waitlast => true) do |pid, stdin, stdout, stderr| - (1..5).each { |i| stdin.puts "#{i}" } - end - end - end.not_to raise_error - end - - describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do - - it "returns immediately after the first child process exits" do - expect do - Timeout.timeout(10) do - evil_forker = "exit if fork; 10.times { sleep 1}" - popen4("ruby -e '#{evil_forker}'") do |pid, stdin, stdout, stderr| - end - end end.not_to raise_error - end - - end - - end - - describe "run_command" do - include Chef::Mixin::Command - - it "logs the command's stderr and stdout output if the command failed" do - allow(Chef::Log).to receive(:level).and_return(:debug) - begin - run_command(:command => "sh -c 'echo hello; echo world >&2; false'") - violated "Exception expected, but nothing raised." - rescue => e - expect(e.message).to match(/STDOUT: hello/) - expect(e.message).to match(/STDERR: world/) - end - end - - describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do - it "returns successfully" do - # CHEF-2916 might have added a slight delay here, or our CI - # infrastructure is burdened. Bumping timeout from 2 => 4 -- - # btm - # Serdar - During Solaris tests, we've seen that processes - # are taking a long time to exit. Bumping timeout now to 10. - expect do - Timeout.timeout(10) do - evil_forker = "exit if fork; 10.times { sleep 1}" - run_command(:command => "ruby -e '#{evil_forker}'") - end end.not_to raise_error - end - - end - end - end -end diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb index 64916ef454..ef629ebd52 100644 --- a/spec/unit/provider/cron_spec.rb +++ b/spec/unit/provider/cron_spec.rb @@ -880,8 +880,7 @@ MAILTO=foo@example.com describe "read_crontab" do before :each do - @status = double("Status", :exitstatus => 0) - @stdout = StringIO.new(<<-CRONTAB) + @stdout = <<-CRONTAB 0 2 * * * /some/other/command # Chef Name: something else @@ -889,11 +888,12 @@ MAILTO=foo@example.com # Another comment CRONTAB - allow(@provider).to receive(:popen4).and_yield(1234, StringIO.new, @stdout, StringIO.new).and_return(@status) + @status = double("Status", exitstatus: 0, stdout: @stdout) + allow(@provider).to receive(:shell_out!).and_return(@status) end it "should call crontab -l with the user" do - expect(@provider).to receive(:popen4).with("crontab -l -u #{@new_resource.user}").and_return(@status) + expect(@provider).to receive(:shell_out!).with("crontab -l -u #{@new_resource.user}", returns: [0, 1]).and_return(@status) @provider.send(:read_crontab) end @@ -910,60 +910,36 @@ MAILTO=foo@example.com end it "should return nil if the user has no crontab" do - status = double("Status", :exitstatus => 1) - allow(@provider).to receive(:popen4).and_return(status) + @status = double("Status", exitstatus: 1, stdout: "") + allow(@provider).to receive(:shell_out!).and_return(@status) expect(@provider.send(:read_crontab)).to eq(nil) end it "should raise an exception if another error occurs" do - status = double("Status", :exitstatus => 2) - allow(@provider).to receive(:popen4).and_return(status) - expect do - @provider.send(:read_crontab) - end.to raise_error(Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: 2") + @status = double("Status", exitstatus: 2) + allow(@provider).to receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) + expect { @provider.send(:read_crontab) }.to raise_error(Chef::Exceptions::Cron) end end describe "write_crontab" do before :each do - @status = double("Status", :exitstatus => 0) - @stdin = StringIO.new - allow(@provider).to receive(:popen4).and_yield(1234, @stdin, StringIO.new, StringIO.new).and_return(@status) + @status = double("Status", exitstatus: 0) + allow(@provider).to receive(:shell_out!).and_return(@status) end it "should call crontab for the user" do - expect(@provider).to receive(:popen4).with("crontab -u #{@new_resource.user} -", :waitlast => true).and_return(@status) + expect(@provider).to receive(:shell_out!).with("crontab -u #{@new_resource.user} -", input: "Foo").and_return(@status) @provider.send(:write_crontab, "Foo") end - it "should write the given string to the crontab command" do - @provider.send(:write_crontab, "Foo\n# wibble\n wah!!") - expect(@stdin.string).to eq("Foo\n# wibble\n wah!!") - end - it "should raise an exception if the command returns non-zero" do - allow(@status).to receive(:exitstatus).and_return(1) - expect do - @provider.send(:write_crontab, "Foo") - end.to raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") - end - - it "should raise an exception if the command die's and parent tries to write" do - class WriteErrPipe - def write(str) - raise Errno::EPIPE, "Test" - end - end - allow(@status).to receive(:exitstatus).and_return(1) - allow(@provider).to receive(:popen4).and_yield(1234, WriteErrPipe.new, StringIO.new, StringIO.new).and_return(@status) - - expect(Chef::Log).to receive(:debug).with("Broken pipe - Test") - + @status = double("Status", exitstatus: 1) + allow(@provider).to receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) expect do @provider.send(:write_crontab, "Foo") - end.to raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") + end.to raise_error(Chef::Exceptions::Cron) end - end describe "weekday_in_crontab" do diff --git a/spec/unit/provider/erl_call_spec.rb b/spec/unit/provider/erl_call_spec.rb index f1c229028a..b5d3ae8c07 100644 --- a/spec/unit/provider/erl_call_spec.rb +++ b/spec/unit/provider/erl_call_spec.rb @@ -31,11 +31,8 @@ describe Chef::Provider::ErlCall do @provider = Chef::Provider::ErlCall.new(@new_resource, @run_context) - allow(@provider).to receive(:popen4).and_return(@status) - @stdin = StringIO.new - @stdout = StringIO.new("{ok, woohoo}") - @stderr = StringIO.new - @pid = 2342999 + @status = double("Status", stdout: "{ok, woohoo}", stderr: "") + allow(@provider).to receive(:shell_out!).and_return(@status) end it "should return a Chef::Provider::ErlCall object" do @@ -56,12 +53,9 @@ describe Chef::Provider::ErlCall do it "should write to stdin of the erl_call command" do expected_cmd = "erl_call -e -s -sname chef@localhost -c nomnomnom" - expect(@provider).to receive(:popen4).with(expected_cmd, :waitlast => true).and_return([@pid, @stdin, @stdout, @stderr]) - expect(Process).to receive(:wait).with(@pid) + expect(@provider).to receive(:shell_out!).with(expected_cmd, input: @new_resource.code).and_return(@status) @provider.action_run - - expect(@stdin.string).to eq("#{@new_resource.code}\n") end end @@ -73,12 +67,10 @@ describe Chef::Provider::ErlCall do end it "should write to stdin of the erl_call command" do - expect(@provider).to receive(:popen4).with("erl_call -e -name chef@localhost ", :waitlast => true).and_return([@pid, @stdin, @stdout, @stderr]) - expect(Process).to receive(:wait).with(@pid) + expected_cmd = "erl_call -e -name chef@localhost " + expect(@provider).to receive(:shell_out!).with(expected_cmd, input: @new_resource.code).and_return(@status) @provider.action_run - - expect(@stdin.string).to eq("#{@new_resource.code}\n") end end diff --git a/spec/unit/provider/service/debian_service_spec.rb b/spec/unit/provider/service/debian_service_spec.rb index 799ed991a3..d944192755 100644 --- a/spec/unit/provider/service/debian_service_spec.rb +++ b/spec/unit/provider/service/debian_service_spec.rb @@ -59,11 +59,10 @@ describe Chef::Provider::Service::Debian do /etc/rc6.d/K20chef UPDATE_RC_D_SUCCESS - @stdout = StringIO.new(result) - @stderr = StringIO.new - @status = double("Status", :exitstatus => 0, :stdout => @stdout) + @stdout = result + @stderr = "" + @status = double("Status", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr) allow(@provider).to receive(:shell_out!).and_return(@status) - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is enabled" do @@ -80,13 +79,9 @@ describe Chef::Provider::Service::Debian do context "when update-rc.d shows init isn't linked to rc*.d/" do before do allow(@provider).to receive(:assert_update_rcd_available) - @status = double("Status", :exitstatus => 0) - @stdout = StringIO.new( - " Removing any system startup links for /etc/init.d/chef ...") - @stderr = StringIO.new - @status = double("Status", :exitstatus => 0, :stdout => @stdout) + @stdout = " Removing any system startup links for /etc/init.d/chef ..." + @status = double("Status", :exitstatus => 0, :stdout => @stdout, stderr: "") allow(@provider).to receive(:shell_out!).and_return(@status) - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is disabled" do @@ -102,11 +97,12 @@ describe Chef::Provider::Service::Debian do context "when update-rc.d fails" do before do - @status = double("Status", :exitstatus => -1) - allow(@provider).to receive(:popen4).and_return(@status) + @status = double("Status", exitstatus: -1, stdout: "", stderr: "") + allow(@provider).to receive(:shell_out!).and_return(@status) end it "raises an error" do + @provider.load_current_resource @provider.define_resource_requirements expect do @provider.process_resource_requirements @@ -198,11 +194,10 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop before do allow(@provider).to receive(:assert_update_rcd_available) - @stdout = StringIO.new(expected_results["linked"]["stdout"]) - @stderr = StringIO.new(expected_results["linked"]["stderr"]) - @status = double("Status", :exitstatus => 0, :stdout => @stdout) + @stdout = expected_results["linked"]["stdout"] + @stderr = expected_results["linked"]["stderr"] + @status = double("Status", exitstatus: 0, stdout: @stdout, stderr: @stderr) allow(@provider).to receive(:shell_out!).and_return(@status) - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is enabled" do @@ -224,11 +219,10 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop context "when update-rc.d shows init isn't linked to rc*.d/" do before do allow(@provider).to receive(:assert_update_rcd_available) - @stdout = StringIO.new(expected_results["not linked"]["stdout"]) - @stderr = StringIO.new(expected_results["not linked"]["stderr"]) - @status = double("Status", :exitstatus => 0, :stdout => @stdout) + @stdout = expected_results["not linked"]["stdout"] + @stderr = expected_results["not linked"]["stderr"] + @status = double("Status", exitstatus: 0, stdout: @stdout, stderr: @stderr) allow(@provider).to receive(:shell_out!).and_return(@status) - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is disabled" do diff --git a/spec/unit/provider/service/upstart_service_spec.rb b/spec/unit/provider/service/upstart_service_spec.rb index 0245dd038c..5c47259f52 100644 --- a/spec/unit/provider/service/upstart_service_spec.rb +++ b/spec/unit/provider/service/upstart_service_spec.rb @@ -71,12 +71,8 @@ describe Chef::Provider::Service::Upstart do @current_resource = Chef::Resource::Service.new("rsyslog") allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource) - @status = double("Status", :exitstatus => 0) - allow(@provider).to receive(:popen4).and_return(@status) - @stdin = StringIO.new - @stdout = StringIO.new - @stderr = StringIO.new - @pid = double("PID") + @status = double("Status", exitstatus: 0, stdout: "", stderr: "") + allow(@provider).to receive(:shell_out).and_return(@status) allow(::File).to receive(:exists?).and_return(true) allow(::File).to receive(:open).and_return(true) @@ -100,28 +96,25 @@ describe Chef::Provider::Service::Upstart do end it "should run '/sbin/status rsyslog'" do - expect(@provider).to receive(:popen4).with("/sbin/status rsyslog").and_return(@status) + expect(@provider).to receive(:shell_out).with("/sbin/status rsyslog").and_return(@status) @provider.load_current_resource end describe "when the status command uses the new format" do it "should set running to true if the goal state is 'start'" do - @stdout = StringIO.new("rsyslog start/running") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog start/running") @provider.load_current_resource expect(@current_resource.running).to be_truthy end it "should set running to true if the goal state is 'start' but current state is not 'running'" do - @stdout = StringIO.new("rsyslog start/starting") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog start/starting") @provider.load_current_resource expect(@current_resource.running).to be_truthy end it "should set running to false if the goal state is 'stop'" do - @stdout = StringIO.new("rsyslog stop/waiting") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog stop/waiting") @provider.load_current_resource expect(@current_resource.running).to be_falsey end @@ -129,22 +122,19 @@ describe Chef::Provider::Service::Upstart do describe "when the status command uses the new format with an instance" do it "should set running to true if the goal state is 'start'" do - @stdout = StringIO.new("rsyslog (test) start/running, process 100") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog (test) start/running, process 100") @provider.load_current_resource expect(@current_resource.running).to be_truthy end it "should set running to true if the goal state is 'start' but current state is not 'running'" do - @stdout = StringIO.new("rsyslog (test) start/starting, process 100") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog (test) start/starting, process 100") @provider.load_current_resource expect(@current_resource.running).to be_truthy end it "should set running to false if the goal state is 'stop'" do - @stdout = StringIO.new("rsyslog (test) stop/waiting, process 100") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog (test) stop/waiting, process 100") @provider.load_current_resource expect(@current_resource.running).to be_falsey end @@ -152,22 +142,19 @@ describe Chef::Provider::Service::Upstart do describe "when the status command uses the old format" do it "should set running to true if the goal state is 'start'" do - @stdout = StringIO.new("rsyslog (start) running, process 32225") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog (start) running, process 32225") @provider.load_current_resource expect(@current_resource.running).to be_truthy end it "should set running to true if the goal state is 'start' but current state is not 'running'" do - @stdout = StringIO.new("rsyslog (start) starting, process 32225") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog (start) starting, process 32225") @provider.load_current_resource expect(@current_resource.running).to be_truthy end it "should set running to false if the goal state is 'stop'" do - @stdout = StringIO.new("rsyslog (stop) waiting") - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + expect(@status).to receive(:stdout).and_return("rsyslog (stop) waiting") @provider.load_current_resource expect(@current_resource.running).to be_falsey end diff --git a/spec/unit/provider/subversion_spec.rb b/spec/unit/provider/subversion_spec.rb index a4ab4ae42c..55d6dc5d24 100644 --- a/spec/unit/provider/subversion_spec.rb +++ b/spec/unit/provider/subversion_spec.rb @@ -1,6 +1,6 @@ # # Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2017, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,7 +43,7 @@ describe Chef::Provider::Subversion do ENV.update(@original_env) end - it "converts resource attributes to options for run_command and popen4" do + it "converts resource attributes to options for shell_out" do expect(@provider.run_options).to eq({}) @resource.user "deployninja" expect(@provider.run_options).to eq({ :user => "deployninja" }) diff --git a/spec/unit/provider/user/pw_spec.rb b/spec/unit/provider/user/pw_spec.rb index 3637ce0b95..913b0ae0ab 100644 --- a/spec/unit/provider/user/pw_spec.rb +++ b/spec/unit/provider/user/pw_spec.rb @@ -155,11 +155,7 @@ describe Chef::Provider::User::Pw do describe "when modifying the password" do before(:each) do @status = double("Status", exitstatus: 0) - allow(@provider).to receive(:popen4).and_return(@status) - @pid = nil - @stdin = nil - @stdout = nil - @stderr = nil + allow(@provider).to receive(:shell_out!).and_return(@status) end describe "and the new password has not been specified" do @@ -206,24 +202,16 @@ describe Chef::Provider::User::Pw do end it "should run pw usermod with the username and the option -H 0" do - expect(@provider).to receive(:popen4).with("pw usermod adam -H 0", waitlast: true).and_return(@status) + expect(@provider).to receive(:shell_out!).with("pw usermod adam -H 0", { :input => "abracadabra" }).and_return(@status) @provider.modify_password end - it "should send the new password to the stdin of pw usermod" do - @stdin = StringIO.new - allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.modify_password - expect(@stdin.string).to eq("abracadabra\n") - end - it "should raise an exception if pw usermod fails" do - expect(@status).to receive(:exitstatus).and_return(1) - expect { @provider.modify_password }.to raise_error(Chef::Exceptions::User) + expect(@provider).to receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) + expect { @provider.modify_password }.to raise_error(Mixlib::ShellOut::ShellCommandFailed) end it "should not raise an exception if pw usermod succeeds" do - expect(@status).to receive(:exitstatus).and_return(0) expect { @provider.modify_password }.not_to raise_error end end |