diff options
Diffstat (limited to 'lib/chef/provider/service/macosx.rb')
-rw-r--r-- | lib/chef/provider/service/macosx.rb | 82 |
1 files changed, 68 insertions, 14 deletions
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb index 4f2de2ccbf..ca78c2eaee 100644 --- a/lib/chef/provider/service/macosx.rb +++ b/lib/chef/provider/service/macosx.rb @@ -17,6 +17,7 @@ # require 'chef/provider/service' +require 'rexml/document' class Chef class Provider @@ -41,6 +42,7 @@ class Chef @current_resource.service_name(@new_resource.service_name) @plist_size = 0 @plist = find_service_plist + @service_label = find_service_label set_service_status @current_resource @@ -48,14 +50,6 @@ class Chef def define_resource_requirements #super - requirements.assert(:enable) do |a| - a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable" - end - - requirements.assert(:disable) do |a| - a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable" - end - requirements.assert(:reload) do |a| a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload" end @@ -66,6 +60,12 @@ class Chef end requirements.assert(:all_actions) do |a| + a.assertion { !@service_label.to_s.empty? } + a.failure_message Chef::Exceptions::Service, + "Could not find service's label in plist file '#{@plist}'!" + end + + requirements.assert(:all_actions) do |a| a.assertion { @plist_size > 0 } # No failrue here in original code - so we also will not # fail. Instead warn that the service is potentially missing @@ -74,7 +74,6 @@ class Chef @current_resource.running(false) end end - end def start_service @@ -111,19 +110,56 @@ class Chef end end + # On OS/X, enabling a service has the side-effect of starting it, + # and disabling a service has the side-effect of stopping it. + # + # This makes some sense on OS/X since launchctl is an "init"-style + # supervisor that will restart daemons that are crashing, etc. + def enable_service + if @current_resource.enabled + Chef::Log.debug("#{@new_resource} already enabled, not enabling") + else + shell_out!( + "launchctl load -w '#{@plist}'", + :user => @owner_uid, :group => @owner_gid + ) + end + end + + def disable_service + unless @current_resource.enabled + Chef::Log.debug("#{@new_resource} not enabled, not disabling") + else + shell_out!( + "launchctl unload -w '#{@plist}'", + :user => @owner_uid, :group => @owner_gid + ) + end + end def set_service_status - return if @plist == nil + return if @plist == nil or @service_label.to_s.empty? - @current_resource.enabled(!@plist.nil?) + cmd = shell_out( + "launchctl list #{@service_label}", + :user => @owner_uid, :group => @owner_gid + ) + + if cmd.exitstatus == 0 + @current_resource.enabled(true) + else + @current_resource.enabled(false) + end if @current_resource.enabled @owner_uid = ::File.stat(@plist).uid @owner_gid = ::File.stat(@plist).gid - shell_out!("launchctl list", :user => @owner_uid, :group => @owner_gid).stdout.each_line do |line| + shell_out!( + "launchctl list", :user => @owner_uid, :group => @owner_gid + ).stdout.each_line do |line| case line - when /(\d+|-)\s+(?:\d+|-)\s+(.*\.?)#{@current_resource.service_name}/ + when /(\d+|-)\s+(?:\d+|-)\s+(.*\.?)#{@service_label}/ pid = $1 @current_resource.running(!pid.to_i.zero?) end @@ -135,9 +171,27 @@ class Chef private + def find_service_label + # Most services have the same internal label as the name of the + # plist file. However, there is no rule saying that *has* to be + # the case, and some core services (notably, ssh) do not follow + # this rule. + + # plist files can come in XML or Binary formats. this command + # will make sure we get XML every time. + plist_xml = shell_out!("plutil -convert xml1 -o - #{@plist}").stdout + + plist_doc = REXML::Document.new(plist_xml) + plist_doc.elements[ + "/plist/dict/key[text()='Label']/following::string[1]/text()"] + end + def find_service_plist plists = PLIST_DIRS.inject([]) do |results, dir| - entries = Dir.glob("#{::File.expand_path(dir)}/*#{@current_resource.service_name}*.plist") + edir = ::File.expand_path(dir) + entries = Dir.glob( + "#{edir}/*#{@current_resource.service_name}*.plist" + ) entries.any? ? results << entries : results end plists.flatten! |