class Chef::Provider::Service::Macosx
Constants
- PLIST_DIRS
Public Class Methods
Source
# File lib/chef/provider/service/macosx.rb, line 35 def self.gather_plist_dirs locations = %w{/Library/LaunchAgents /Library/LaunchDaemons /System/Library/LaunchAgents /System/Library/LaunchDaemons } Chef::Util::PathHelper.home("Library", "LaunchAgents") { |p| locations << p } locations end
Public Instance Methods
Source
# File lib/chef/provider/service/macosx.rb, line 73 def define_resource_requirements requirements.assert(:reload) do |a| a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload" end requirements.assert(:all_actions) do |a| a.assertion { @plist_size < 2 } a.failure_message Chef::Exceptions::Service, "Several plist files match service name. Please use full service name." end requirements.assert(:all_actions) do |a| a.assertion { ::File.exist?(@plist.to_s) } a.failure_message Chef::Exceptions::Service, "Could not find plist for #{@new_resource}" end requirements.assert(:enable, :disable) 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 failure here in original code - so we also will not # fail. Instead warn that the service is potentially missing a.whyrun "Assuming that the service would have been previously installed and is currently disabled." do @current_resource.enabled(false) @current_resource.running(false) end end end
Source
# File lib/chef/provider/service/macosx.rb, line 162 def disable_service unless @current_resource.enabled logger.debug("#{@new_resource} not enabled, not disabling") else unload_service end end
Source
# File lib/chef/provider/service/macosx.rb, line 154 def enable_service if @current_resource.enabled logger.debug("#{@new_resource} already enabled, not enabling") else load_service end end
On macOS, 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 macOS since launchctl is an “init”-style supervisor that will restart daemons that are crashing, etc.
FIXME: Does this make any sense at all? The difference between enabled and running as state would seem to only be useful for completely broken services (enabled, not restarting, but not running => totally broken?).
It seems like otherwise :enable is equivalent to :start, and :disable is equivalent to :stop? But just with strangely different behavior in the face of a broken service?
Source
# File lib/chef/provider/service/macosx.rb, line 46 def load_current_resource @current_resource = Chef::Resource::MacosxService.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) @plist_size = 0 @plist = @new_resource.plist || find_service_plist @service_label = find_service_label # LaunchAgents should be loaded as the console user. @console_user = @plist ? @plist.include?("LaunchAgents") : false @session_type = @new_resource.session_type if @console_user @console_user = Etc.getpwuid(::File.stat("/dev/console").uid).name logger.trace("#{new_resource} console_user: '#{@console_user}'") @base_user_cmd = "su -l #{@console_user} -c" logger.trace("#{new_resource} base_user_cmd: '#{@base_user_cmd}'") # Default LaunchAgent session should be Aqua @session_type = "Aqua" if @session_type.nil? end logger.trace("#{new_resource} Plist: '#{@plist}' service_label: '#{@service_label}'") set_service_status @current_resource end
Source
# File lib/chef/provider/service/macosx.rb, line 170 def load_service session = @session_type ? "-S #{@session_type} " : "" cmd = "/bin/launchctl load -w " + session + @plist shell_out_as_user(cmd) end
Source
# File lib/chef/provider/service/macosx.rb, line 130 def restart_service if @new_resource.restart_command super else unload_service sleep 1 load_service end end
Calls superclass method
Chef::Provider::Service::Simple#restart_service
Source
# File lib/chef/provider/service/macosx.rb, line 190 def set_service_status return if @plist.nil? || @service_label.to_s.empty? cmd = "/bin/launchctl list #{@service_label}" res = shell_out_as_user(cmd) if res.exitstatus == 0 @current_resource.enabled(true) else @current_resource.enabled(false) end if @current_resource.enabled res.stdout.each_line do |line| case line.downcase when /\s+\"pid\"\s+=\s+(\d+).*/ pid = $1 @current_resource.running(pid.to_i != 0) logger.trace("Current PID for #{@service_label} is #{pid}") end end else @current_resource.running(false) end end
Source
# File lib/chef/provider/service/macosx.rb, line 181 def shell_out_as_user(cmd) if @console_user shell_out("#{@base_user_cmd} '#{cmd}'", default_env: false) else shell_out(cmd, default_env: false) end end
Source
# File lib/chef/provider/service/macosx.rb, line 106 def start_service if @current_resource.running logger.debug("#{@new_resource} already running, not starting") else if @new_resource.start_command super else load_service end end end
Calls superclass method
Chef::Provider::Service::Simple#start_service
Source
# File lib/chef/provider/service/macosx.rb, line 118 def stop_service unless @current_resource.running logger.debug("#{@new_resource} not running, not stopping") else if @new_resource.stop_command super else unload_service end end end
Calls superclass method
Chef::Provider::Service::Simple#stop_service
Source
# File lib/chef/provider/service/macosx.rb, line 176 def unload_service cmd = "/bin/launchctl unload -w " + @plist shell_out_as_user(cmd) end
Private Instance Methods
Source
# File lib/chef/provider/service/macosx.rb, line 218 def find_service_label # CHEF-5223 "you can't glob for a file that hasn't been converged # onto the node yet." return nil if @plist.nil? # Plist must exist by this point raise Chef::Exceptions::FileNotFound, "Cannot find #{@plist}!" unless ::File.exist?(@plist) # 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}", default_env: false ).stdout plist_doc = REXML::Document.new(plist_xml) plist_doc.elements[ "/plist/dict/key[text()='Label']/following::string[1]/text()"] end
Source
# File lib/chef/provider/service/macosx.rb, line 243 def find_service_plist plists = PLIST_DIRS.inject([]) do |results, dir| edir = ::File.expand_path(dir) entries = Dir.glob( "#{edir}/*#{Chef::Util::PathHelper.escape_glob_dir(@current_resource.service_name)}*.plist" ) entries.any? ? results << entries : results end plists.flatten! @plist_size = plists.size plists.first end