summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider
diff options
context:
space:
mode:
authorMax Martin <max@puppetlabs.com>2011-03-23 14:43:29 -0700
committerMax Martin <max@puppetlabs.com>2011-03-23 14:43:29 -0700
commit4196699f5fbb90ceecbb709c8502622eaad39062 (patch)
treeadb06f307051368e9fe9a23c3338fe7511eb8adf /lib/puppet/provider
parent7e71840e29cb09c772668a51ada3cab1e319e50f (diff)
parent66d0b16c8a0a55dd79b1b0f0e639f107e552d9ab (diff)
downloadpuppet-4196699f5fbb90ceecbb709c8502622eaad39062.tar.gz
puppet-4196699f5fbb90ceecbb709c8502622eaad39062.tar.xz
puppet-4196699f5fbb90ceecbb709c8502622eaad39062.zip
Merge branch 'next'
* next: (34 commits) (#6820) Fix File class lookup in the file type for Ruby 1.9 (#6820) Fix nagios parser to use proper hash syntax for Ruby 1.9 (#6820) Fix Invalid multibyte character (#6820) Fix RDOC parser to work with Ruby 1.9 (#6820) Fix invalid next that should be a return (#2782) Fix constant_defined? (#6527) Fix pip tests (#6527) Fix uninstall problem and refactor (#6527) Added pip package provider. maint: Change code for finding spec_helper to work with Ruby 1.9 Fix error "invalid multibyte char (US-ASCII)" under Ruby 1.9 Fixed #6562 - Minor kick documentation fix (#6566) Replace tabs with spaces (#6566) Fix ruby 1.9 incompatible case statement Fixed #6566 Replace ftools with filetuils in rake gem task (#6555) Fix another ruby 1.9 incompatible case statement Fixed #6555 - Fixed two more when then colon issues Fixed #6555 - Ruby 1.9.x returning Invalid next (SyntaxError) Fixed #6555 - Ruby 1.9.x warning: class variable access from toplevel (#6658) Propagate ENC connection errors to the agent ...
Diffstat (limited to 'lib/puppet/provider')
-rw-r--r--lib/puppet/provider/exec/posix.rb112
-rw-r--r--lib/puppet/provider/exec/shell.rb17
-rw-r--r--lib/puppet/provider/package/pip.rb109
-rw-r--r--lib/puppet/provider/service/daemontools.rb2
-rw-r--r--lib/puppet/provider/service/launchd.rb2
5 files changed, 240 insertions, 2 deletions
diff --git a/lib/puppet/provider/exec/posix.rb b/lib/puppet/provider/exec/posix.rb
new file mode 100644
index 000000000..92dbd8c98
--- /dev/null
+++ b/lib/puppet/provider/exec/posix.rb
@@ -0,0 +1,112 @@
+Puppet::Type.type(:exec).provide :posix do
+ include Puppet::Util::Execution
+
+ confine :feature => :posix
+ defaultfor :feature => :posix
+
+ desc "Execute external binaries directly, on POSIX systems.
+This does not pass through a shell, or perform any interpolation, but
+only directly calls the command with the arguments given."
+
+ def run(command, check = false)
+ output = nil
+ status = nil
+ dir = nil
+
+ checkexe(command)
+
+ if dir = resource[:cwd]
+ unless File.directory?(dir)
+ if check
+ dir = nil
+ else
+ self.fail "Working directory '#{dir}' does not exist"
+ end
+ end
+ end
+
+ dir ||= Dir.pwd
+
+ debug "Executing#{check ? " check": ""} '#{command}'"
+ begin
+ # Do our chdir
+ Dir.chdir(dir) do
+ environment = {}
+
+ environment[:PATH] = resource[:path].join(":") if resource[:path]
+
+ if envlist = resource[:environment]
+ envlist = [envlist] unless envlist.is_a? Array
+ envlist.each do |setting|
+ if setting =~ /^(\w+)=((.|\n)+)$/
+ env_name = $1
+ value = $2
+ if environment.include?(env_name) || environment.include?(env_name.to_sym)
+ warning "Overriding environment setting '#{env_name}' with '#{value}'"
+ end
+ environment[env_name] = value
+ else
+ warning "Cannot understand environment setting #{setting.inspect}"
+ end
+ end
+ end
+
+ withenv environment do
+ Timeout::timeout(resource[:timeout]) do
+ output, status = Puppet::Util::SUIDManager.
+ run_and_capture([command], resource[:user], resource[:group])
+ end
+ # The shell returns 127 if the command is missing.
+ if status.exitstatus == 127
+ raise ArgumentError, output
+ end
+ end
+ end
+ rescue Errno::ENOENT => detail
+ self.fail detail.to_s
+ end
+
+ return output, status
+ end
+
+ # Verify that we have the executable
+ def checkexe(command)
+ exe = extractexe(command)
+
+ if resource[:path]
+ if Puppet.features.posix? and !File.exists?(exe)
+ withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do
+ exe = which(exe) || raise(ArgumentError,"Could not find command '#{exe}'")
+ end
+ elsif Puppet.features.microsoft_windows? and !File.exists?(exe)
+ resource[:path].each do |path|
+ [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
+ file = File.join(path, exe+extension)
+ return if File.exists?(file)
+ end
+ end
+ end
+ end
+
+ raise ArgumentError, "Could not find command '#{exe}'" unless File.exists?(exe)
+ unless File.executable?(exe)
+ raise ArgumentError,
+ "'#{exe}' is not executable"
+ end
+ end
+
+ def extractexe(command)
+ # easy case: command was quoted
+ if command =~ /^"([^"]+)"/
+ $1
+ else
+ command.split(/ /)[0]
+ end
+ end
+
+ def validatecmd(command)
+ exe = extractexe(command)
+ # if we're not fully qualified, require a path
+ self.fail "'#{command}' is not qualified and no path was specified. Please qualify the command or specify a path." if File.expand_path(exe) != exe and resource[:path].nil?
+ end
+end
diff --git a/lib/puppet/provider/exec/shell.rb b/lib/puppet/provider/exec/shell.rb
new file mode 100644
index 000000000..98f309e8f
--- /dev/null
+++ b/lib/puppet/provider/exec/shell.rb
@@ -0,0 +1,17 @@
+Puppet::Type.type(:exec).provide :shell, :parent => :posix do
+ include Puppet::Util::Execution
+
+ confine :feature => :posix
+
+ desc "Execute external binaries directly, on POSIX systems.
+passing through a shell so that shell built ins are available."
+
+ def run(command, check = false)
+ command = %Q{/bin/sh -c "#{command.gsub(/"/,'\"')}"}
+ super(command, check)
+ end
+
+ def validatecmd(command)
+ true
+ end
+end
diff --git a/lib/puppet/provider/package/pip.rb b/lib/puppet/provider/package/pip.rb
new file mode 100644
index 000000000..5abbc135a
--- /dev/null
+++ b/lib/puppet/provider/package/pip.rb
@@ -0,0 +1,109 @@
+# Puppet package provider for Python's `pip` package management frontend.
+# <http://pip.openplans.org/>
+
+require 'puppet/provider/package'
+require 'xmlrpc/client'
+
+Puppet::Type.type(:package).provide :pip,
+ :parent => ::Puppet::Provider::Package do
+
+ desc "Python packages via `pip`."
+
+ has_feature :installable, :uninstallable, :upgradeable, :versionable
+
+ # Parse lines of output from `pip freeze`, which are structured as
+ # _package_==_version_.
+ def self.parse(line)
+ if line.chomp =~ /^([^=]+)==([^=]+)$/
+ {:ensure => $2, :name => $1, :provider => name}
+ else
+ nil
+ end
+ end
+
+ # Return an array of structured information about every installed package
+ # that's managed by `pip` or an empty array if `pip` is not available.
+ def self.instances
+ packages = []
+ pip_cmd = which('pip') or return []
+ execpipe "#{pip_cmd} freeze" do |process|
+ process.collect do |line|
+ next unless options = parse(line)
+ packages << new(options)
+ end
+ end
+ packages
+ end
+
+ # Return structured information about a particular package or `nil` if
+ # it is not installed or `pip` itself is not available.
+ def query
+ self.class.instances.each do |provider_pip|
+ return provider_pip.properties if @resource[:name] == provider_pip.name
+ end
+ return nil
+ end
+
+ # Ask the PyPI API for the latest version number. There is no local
+ # cache of PyPI's package list so this operation will always have to
+ # ask the web service.
+ def latest
+ client = XMLRPC::Client.new2("http://pypi.python.org/pypi")
+ client.http_header_extra = {"Content-Type" => "text/xml"}
+ result = client.call("package_releases", @resource[:name])
+ result.first
+ end
+
+ # Install a package. The ensure parameter may specify installed,
+ # latest, a version number, or, in conjunction with the source
+ # parameter, an SCM revision. In that case, the source parameter
+ # gives the fully-qualified URL to the repository.
+ def install
+ args = %w{install -q}
+ if @resource[:source]
+ args << "-e"
+ if String === @resource[:ensure]
+ args << "#{@resource[:source]}@#{@resource[:ensure]}#egg=#{
+ @resource[:name]}"
+ else
+ args << "#{@resource[:source]}#egg=#{@resource[:name]}"
+ end
+ else
+ case @resource[:ensure]
+ when String
+ args << "#{@resource[:name]}==#{@resource[:ensure]}"
+ when :latest
+ args << "--upgrade" << @resource[:name]
+ else
+ args << @resource[:name]
+ end
+ end
+ lazy_pip *args
+ end
+
+ # Uninstall a package. Uninstall won't work reliably on Debian/Ubuntu
+ # unless this issue gets fixed.
+ # <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562544>
+ def uninstall
+ lazy_pip "uninstall", "-y", "-q", @resource[:name]
+ end
+
+ def update
+ install
+ end
+
+ # Execute a `pip` command. If Puppet doesn't yet know how to do so,
+ # try to teach it and if even that fails, raise the error.
+ private
+ def lazy_pip(*args)
+ pip *args
+ rescue NoMethodError => e
+ if pathname = which('pip')
+ self.class.commands :pip => pathname
+ pip *args
+ else
+ raise e
+ end
+ end
+
+end
diff --git a/lib/puppet/provider/service/daemontools.rb b/lib/puppet/provider/service/daemontools.rb
index bbb962a71..f5a073329 100644
--- a/lib/puppet/provider/service/daemontools.rb
+++ b/lib/puppet/provider/service/daemontools.rb
@@ -67,7 +67,7 @@ Puppet::Type.type(:service).provide :daemontools, :parent => :base do
path = self.defpath
unless FileTest.directory?(path)
Puppet.notice "Service path #{path} does not exist"
- next
+ return
end
# reject entries that aren't either a directory
diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb
index 07c549a8b..9d813bd5a 100644
--- a/lib/puppet/provider/service/launchd.rb
+++ b/lib/puppet/provider/service/launchd.rb
@@ -211,7 +211,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
job_path, job_plist = plist_from_label(resource[:name])
job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled")
- if self.class.get_macosx_version_major == "10.6":
+ if self.class.get_macosx_version_major == "10.6"
if FileTest.file?(Launchd_Overrides) and overrides = self.class.read_plist(Launchd_Overrides)
if overrides.has_key?(resource[:name])
overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")