summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/service/launchd.rb
diff options
context:
space:
mode:
authorNigel Kersten <nigelk@google.com>2008-11-25 07:37:23 -0800
committerJames Turnbull <james@lovedthanlost.net>2008-11-26 13:01:44 +1100
commit86ce934270992d192a1163d211761a505d5b2812 (patch)
treea13d2b625960c7e15e74c6b4f394c0d39fc85c2b /lib/puppet/provider/service/launchd.rb
parent97a817706f7993044b69f148fe2ba74bbcb5d4a3 (diff)
downloadpuppet-86ce934270992d192a1163d211761a505d5b2812.tar.gz
puppet-86ce934270992d192a1163d211761a505d5b2812.tar.xz
puppet-86ce934270992d192a1163d211761a505d5b2812.zip
launchd service provider
Diffstat (limited to 'lib/puppet/provider/service/launchd.rb')
-rw-r--r--lib/puppet/provider/service/launchd.rb188
1 files changed, 188 insertions, 0 deletions
diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb
new file mode 100644
index 000000000..e51451cac
--- /dev/null
+++ b/lib/puppet/provider/service/launchd.rb
@@ -0,0 +1,188 @@
+require 'facter/util/plist'
+
+Puppet::Type.type(:service).provide :launchd, :parent => :base do
+ desc "launchd service management framework.
+
+ This provider manages launchd jobs, the default service framework for
+ Mac OS X, that has also been open sourced by Apple for possible use on
+ other platforms.
+
+ See:
+ * http://developer.apple.com/macosx/launchd.html
+ * http://launchd.macosforge.org/
+
+ This provider reads plists out of the following directories:
+ * /System/Library/LaunchDaemons
+ * /System/Library/LaunchAgents
+ * /Library/LaunchDaemons
+ * /Library/LaunchAgents
+
+ and builds up a list of services based upon each plists \"Label\" entry.
+
+ This provider supports:
+ * ensure => running/stopped,
+ * enable => true/false
+ * status
+ * restart
+
+ Here is how the Puppet states correspond to launchd states:
+ * stopped => job unloaded
+ * started => job loaded
+ * enabled => 'Disable' removed from job plist file
+ * disabled => 'Disable' added to job plist file
+
+ Note that this allows you to do something launchctl can't do, which is to
+ be in a state of \"stopped/enabled\ or \"running/disabled\".
+ "
+
+ commands :launchctl => "/bin/launchctl"
+
+ defaultfor :operatingsystem => :darwin
+ confine :operatingsystem => :darwin
+
+ has_feature :enableable
+
+ Launchd_Paths = ["/Library/LaunchAgents",
+ "/Library/LaunchDaemons",
+ "/System/Library/LaunchAgents",
+ "/System/Library/LaunchDaemons",]
+
+
+ # returns a label => path map for either all jobs, or just a single
+ # job if the label is specified
+ def self.jobsearch(label=nil)
+ label_to_path_map = {}
+ Launchd_Paths.each do |path|
+ if FileTest.exists?(path)
+ Dir.entries(path).each do |f|
+ next if f =~ /^\..*$/
+ next if FileTest.directory?(f)
+ fullpath = File.join(path, f)
+ job = Plist::parse_xml(fullpath)
+ if job and job.has_key?("Label")
+ if job["Label"] == label
+ return { label => fullpath }
+ else
+ label_to_path_map[job["Label"]] = fullpath
+ end
+ end
+ end
+ end
+ end
+
+ # if we didn't find the job above and we should have, error.
+ if label
+ raise Puppet::Error.new("Unable to find launchd plist for job: #{label}")
+ end
+ # if returning all jobs
+ label_to_path_map
+ end
+
+
+ def self.instances
+ jobs = self.jobsearch
+ jobs.keys.collect do |job|
+ new(:name => job, :provider => :launchd, :path => jobs[job])
+ end
+ end
+
+
+ # finds the path for a given label and returns the path and parsed plist
+ # as an array of [path, plist]. Note plist is really a Hash here.
+ def self.plist_from_label(label)
+ job = self.jobsearch(label)
+ job_path = job[label]
+ job_plist = Plist::parse_xml(job_path)
+ if not job_plist
+ raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}")
+ end
+ [job_path, job_plist]
+ end
+
+
+ def status
+ # launchctl list <jobname> exits zero if the job is loaded
+ # and non-zero if it isn't. Simple way to check...
+ cmds = []
+ cmds << :launchctl << "list" << @resource[:name]
+ begin
+ execute(cmds)
+ return :running
+ rescue Puppet::ExecutionFailure
+ return :stopped
+ end
+ end
+
+
+ # start the service. To get to a state of running/enabled, we need to
+ # conditionally enable at load, then disable by modifying the plist file
+ # directly.
+ def start
+ job = self.class.jobsearch(@resource[:name])
+ job_path = job[@resource[:name]]
+ did_enable_job = false
+ cmds = []
+ cmds << :launchctl << "load"
+ if self.enabled? == :false # launchctl won't load disabled jobs
+ cmds << "-w"
+ did_enable_job = true
+ end
+ cmds << job_path
+ begin
+ execute(cmds)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new("Unable to start service: %s at path: %s" % [@resource[:name], job_path])
+ end
+ # As load -w clears the Disabled flag, we need to add it in after
+ if did_enable_job and @resource[:enable] == :false
+ self.disable
+ end
+ end
+
+
+ def stop
+ job = self.class.jobsearch(@resource[:name])
+ job_path = job[@resource[:name]]
+ cmds = []
+ cmds << :launchctl << "unload" << job_path
+ begin
+ execute(cmds)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new("Unable to stop service: %s at path: %s" % [@resource[:name], job_path])
+ end
+ end
+
+
+ # launchd jobs are enabled by default. They are only disabled if the key
+ # "Disabled" is set to true, but it can also be set to false to enable it.
+ def enabled?
+ job_path, job_plist = self.class.plist_from_label(@resource[:name])
+ if job_plist.has_key?("Disabled")
+ if job_plist["Disabled"] # inverse of disabled is enabled
+ return :false
+ end
+ end
+ return :true
+ end
+
+
+ # enable and disable are a bit hacky. We write out the plist with the appropriate value
+ # rather than dealing with launchctl as it is unable to change the Disabled flag
+ # without actually loading/unloading the job.
+ def enable
+ job_path, job_plist = self.class.plist_from_label(@resource[:name])
+ if not self.enabled?
+ job_plist.delete("Disabled")
+ Plist::Emit.save_plist(job_plist, job_path)
+ end
+ end
+
+
+ def disable
+ job_path, job_plist = self.class.plist_from_label(@resource[:name])
+ job_plist["Disabled"] = true
+ Plist::Emit.save_plist(job_plist, job_path)
+ end
+
+
+end