diff options
Diffstat (limited to 'lib/puppet')
-rwxr-xr-x | lib/puppet/external/nagios/base.rb | 25 | ||||
-rw-r--r-- | lib/puppet/indirector/facts/facter.rb | 8 | ||||
-rw-r--r-- | lib/puppet/network/xmlrpc/client.rb | 166 | ||||
-rw-r--r-- | lib/puppet/parser/functions/regsubst.rb | 93 | ||||
-rw-r--r-- | lib/puppet/parser/functions/sprintf.rb | 17 | ||||
-rw-r--r-- | lib/puppet/provider/augeas/augeas.rb | 36 | ||||
-rw-r--r-- | lib/puppet/provider/naginator.rb | 5 | ||||
-rw-r--r-- | lib/puppet/provider/package/up2date.rb | 6 | ||||
-rwxr-xr-x | lib/puppet/provider/parsedfile.rb | 14 | ||||
-rwxr-xr-x | lib/puppet/provider/service/redhat.rb | 2 | ||||
-rw-r--r-- | lib/puppet/rails/database/003_add_environment_to_host.rb | 8 | ||||
-rw-r--r-- | lib/puppet/type/augeas.rb | 8 | ||||
-rw-r--r-- | lib/puppet/util/autoload.rb | 4 | ||||
-rwxr-xr-x | lib/puppet/util/filetype.rb | 98 |
14 files changed, 310 insertions, 180 deletions
diff --git a/lib/puppet/external/nagios/base.rb b/lib/puppet/external/nagios/base.rb index d95b808dd..6a0c1831c 100755 --- a/lib/puppet/external/nagios/base.rb +++ b/lib/puppet/external/nagios/base.rb @@ -416,18 +416,20 @@ class Nagios::Base :dependent_service_description, :host_name, :hostgroup_name, :service_description, :inherits_parent, :execution_failure_criteria, :notification_failure_criteria, :dependency_period, - :register, :use + :register, :use, + :_naginator_name - setnamevar :service_description + setnamevar :_naginator_name end newtype :serviceescalation do setparameters :host_name, :hostgroup_name, :service_description, :contacts, :contact_groups, :first_notification, :last_notification, :notification_interval, :escalation_period, :escalation_options, - :register, :use + :register, :use, + :_naginator_name - setnamevar :service_description + setnamevar :_naginator_name end newtype :hostdependency do @@ -435,18 +437,20 @@ class Nagios::Base setparameters :dependent_host_name, :dependent_hostgroup_name, :host_name, :hostgroup_name, :inherits_parent, :execution_failure_criteria, :notification_failure_criteria, :dependency_period, - :register, :use + :register, :use, + :_naginator_name - setnamevar :host_name + setnamevar :_naginator_name end newtype :hostescalation do setparameters :host_name, :hostgroup_name, :contacts, :contact_groups, :first_notification, :last_notification, :notification_interval, :escalation_period, :escalation_options, - :register, :use + :register, :use, + :_naginator_name - setnamevar :host_name + setnamevar :_naginator_name end newtype :hostextinfo do @@ -463,9 +467,10 @@ class Nagios::Base setparameters :host_name, :service_description, :notes, :notes_url, :action_url, :icon_image, :icon_image_alt, - :register, :use + :register, :use, + :_naginator_name - setnamevar :service_description + setnamevar :_naginator_name end end diff --git a/lib/puppet/indirector/facts/facter.rb b/lib/puppet/indirector/facts/facter.rb index 6376b71ca..e664e17c7 100644 --- a/lib/puppet/indirector/facts/facter.rb +++ b/lib/puppet/indirector/facts/facter.rb @@ -8,8 +8,12 @@ class Puppet::Node::Facts::Facter < Puppet::Indirector::Code def self.load_fact_plugins - # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] - x = Puppet[:factpath].split(":").each do |dir| + # Add any per-module fact directories to the factpath + module_fact_dirs = Puppet[:modulepath].split(":").collect do |d| + Dir.glob("%s/*/plugins/facter" % d) + end.flatten + dirs = module_fact_dirs + Puppet[:factpath].split(":") + x = dirs.each do |dir| load_facts_in_dir(dir) end end diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb index 37ace2101..678ab6c00 100644 --- a/lib/puppet/network/xmlrpc/client.rb +++ b/lib/puppet/network/xmlrpc/client.rb @@ -36,57 +36,7 @@ module Puppet::Network interface.methods.each { |ary| method = ary[0] newclient.send(:define_method,method) { |*args| - Puppet.debug "Calling %s.%s" % [namespace, method] - begin - call("%s.%s" % [namespace, method.to_s],*args) - rescue OpenSSL::SSL::SSLError => detail - if detail.message =~ /bad write retry/ - Puppet.warning "Transient SSL write error; restarting connection and retrying" - self.recycle_connection - retry - end - ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str| - if detail.message.include?(str) - Puppet.warning "Certificate validation failed; consider using the certname configuration option" - end - end - raise XMLRPCClientError, - "Certificates were not trusted: %s" % detail - rescue ::XMLRPC::FaultException => detail - raise XMLRPCClientError, detail.faultString - rescue Errno::ECONNREFUSED => detail - msg = "Could not connect to %s on port %s" % - [@host, @port] - raise XMLRPCClientError, msg - rescue SocketError => detail - Puppet.err "Could not find server %s: %s" % - [@host, detail.to_s] - error = XMLRPCClientError.new( - "Could not find server %s" % @host - ) - error.set_backtrace detail.backtrace - raise error - rescue Errno::EPIPE, EOFError - Puppet.warning "Other end went away; restarting connection and retrying" - self.recycle_connection - retry - rescue Timeout::Error => detail - Puppet.err "Connection timeout calling %s.%s: %s" % - [namespace, method, detail.to_s] - error = XMLRPCClientError.new("Connection Timeout") - error.set_backtrace(detail.backtrace) - raise error - rescue => detail - if detail.message =~ /^Wrong size\. Was \d+, should be \d+$/ - Puppet.warning "XMLRPC returned wrong size. Retrying." - retry - end - Puppet.err "Could not call %s.%s: %s" % - [namespace, method, detail.inspect] - error = XMLRPCClientError.new(detail.to_s) - error.set_backtrace detail.backtrace - raise error - end + make_rpc_call(namespace, method, *args) } } @@ -97,13 +47,119 @@ module Puppet::Network @clients[handler] || self.mkclient(handler) end + class ErrorHandler + def initialize(&block) + metaclass.define_method(:execute, &block) + end + end + + # Use a class variable so all subclasses have access to it. + @@error_handlers = {} + + def self.error_handler(exception) + if handler = @@error_handlers[exception.class] + return handler + else + return @@error_handlers[:default] + end + end + + def self.handle_error(*exceptions, &block) + handler = ErrorHandler.new(&block) + + exceptions.each do |exception| + @@error_handlers[exception] = handler + end + end + + handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method| + if detail.message =~ /bad write retry/ + Puppet.warning "Transient SSL write error; restarting connection and retrying" + client.recycle_connection + return :retry + end + ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str| + if detail.message.include?(str) + Puppet.warning "Certificate validation failed; consider using the certname configuration option" + end + end + raise XMLRPCClientError, "Certificates were not trusted: %s" % detail + end + + handle_error(:default) do |client, detail, namespace, method| + if detail.message.to_s =~ /^Wrong size\. Was \d+, should be \d+$/ + Puppet.warning "XMLRPC returned wrong size. Retrying." + return :retry + end + Puppet.err "Could not call %s.%s: %s" % [namespace, method, detail.inspect] + error = XMLRPCClientError.new(detail.to_s) + error.set_backtrace detail.backtrace + raise error + end + + handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method| + if detail.message =~ /bad write retry/ + Puppet.warning "Transient SSL write error; restarting connection and retrying" + client.recycle_connection + return :retry + end + ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str| + if detail.message.include?(str) + Puppet.warning "Certificate validation failed; consider using the certname configuration option" + end + end + raise XMLRPCClientError, "Certificates were not trusted: %s" % detail + end + + handle_error(::XMLRPC::FaultException) do |client, detail, namespace, method| + raise XMLRPCClientError, detail.faultString + end + + handle_error(Errno::ECONNREFUSED) do |client, detail, namespace, method| + msg = "Could not connect to %s on port %s" % [client.host, client.port] + raise XMLRPCClientError, msg + end + + handle_error(SocketError) do |client, detail, namespace, method| + Puppet.err "Could not find server %s: %s" % [@host, detail.to_s] + error = XMLRPCClientError.new("Could not find server %s" % client.host) + error.set_backtrace detail.backtrace + raise error + end + + handle_error(Errno::EPIPE, EOFError) do |client, detail, namespace, method| + Puppet.info "Other end went away; restarting connection and retrying" + client.recycle_connection + return :retry + end + + handle_error(Timeout::Error) do |client, detail, namespace, method| + Puppet.err "Connection timeout calling %s.%s: %s" % [namespace, method, detail.to_s] + error = XMLRPCClientError.new("Connection Timeout") + error.set_backtrace(detail.backtrace) + raise error + end + + def make_rpc_call(namespace, method, *args) + Puppet.debug "Calling %s.%s" % [namespace, method] + begin + call("%s.%s" % [namespace, method.to_s],*args) + rescue Exception => detail + retry if self.class.error_handler(detail).execute(self, detail, namespace, method) == :retry + end + ensure + http.finish if http.started? + end + def http unless @http - @http = Puppet::Network::HttpPool.http_instance(@host, @port, true) + @http = Puppet::Network::HttpPool.http_instance(host, port, true) end @http end + attr_reader :host, :port + def initialize(hash = {}) hash[:Path] ||= "/RPC2" hash[:Server] ||= Puppet[:server] @@ -135,7 +191,11 @@ module Puppet::Network # or we've just downloaded certs and we need to create new http instances # with the certs added. def recycle_connection - @http = Puppet::Network::HttpPool.http_instance(@host, @port, true) # reset the instance + if http.started? + http.finish + end + @http = nil + self.http # force a new one end def start diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb new file mode 100644 index 000000000..067d75c51 --- /dev/null +++ b/lib/puppet/parser/functions/regsubst.rb @@ -0,0 +1,93 @@ +module Puppet::Parser::Functions + newfunction(:regsubst, :type => :rvalue, + :doc => "\ + Perform regexp replacement on a string. + + Parameters (in order): + + :str: + The string to operate on. + + :regexp: + The regular expression matching the string. If you want it + anchored at the start and/or end of the string, you must do + that with ^ and $ yourself. + + :replacement: + Replacement string. Can contain back references to what was + matched using \\0, \\1, and so on. + + :flags: + Optional. String of single letter flags for how the regexp + is interpreted: + + - **E** + Extended regexps + - **I** + Ignore case in regexps + - **M** + Multiline regexps + - **G** + Global replacement; all occurances of the regexp in + the string will be replaced. Without this, only the + first occurance will be replaced. + + :lang: + Optional. How to handle multibyte characters. A + single-character string with the following values: + + - **N** + None + - **E** + EUC + - **S** + SJIS + - **U** + UTF-8 + + **Examples** + + Get the third octet from the node's IP address: :: + + $i3 = regsubst($ipaddress, + '^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$', + '\\\\3') + + Put angle brackets around each octet in the node's IP address: :: + + $x = regsubst($ipaddress, '([0-9]+)', '<\\\\1>', 'G') + ") \ + do |args| + flag_mapping = { + "E" => Regexp::EXTENDED, + "I" => Regexp::IGNORECASE, + "M" => Regexp::MULTILINE, + } + if args.length < 3 or args.length > 5 + raise Puppet::ParseError, ("regsub(): wrong number of arguments" + + " (#{args.length}; min 3, max 5)") + end + str, regexp, replacement, flags, lang = args + reflags = 0 + global = false + (flags or "").each_byte do |f| + f = f.chr + if f == "G" + global = true + else + fvalue = flag_mapping[f] + if !fvalue + raise Puppet::ParseError, "regsub(): bad flag `#{f}'" + end + reflags |= fvalue + end + end + re = Regexp.compile(regexp, reflags, lang) + if global + result = str.gsub(re, replacement) + else + result = str.sub(re, replacement) + end + return result + end +end diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb new file mode 100644 index 000000000..79744104d --- /dev/null +++ b/lib/puppet/parser/functions/sprintf.rb @@ -0,0 +1,17 @@ +module Puppet::Parser::Functions + newfunction(:sprintf, :type => :rvalue, + :doc => "\ + Perform printf-style formatting of text. + + The first parameter is format string describing how the rest of the + parameters should be formatted. See the documentation for the + ``Kernel::sprintf()`` function in Ruby for all the details. + ") \ + do |args| + if args.length < 1 + raise Puppet::ParseError, 'sprintf() needs at least one argument' + end + fmt = args.shift() + return sprintf(fmt, *args) + end +end diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb index 919b377e7..2457840d1 100644 --- a/lib/puppet/provider/augeas/augeas.rb +++ b/lib/puppet/provider/augeas/augeas.rb @@ -69,7 +69,6 @@ Puppet::Type.type(:augeas).provide(:augeas) do commands.concat(parse_commands(datum)) end end - return commands end @@ -181,15 +180,36 @@ Puppet::Type.type(:augeas).provide(:augeas) do fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2 command = cmd_array[0] cmd_array.shift() - loc = cmd_array[0] - cmd_array[0]=File.join(context, loc) - debug("sending command '#{command}' with params #{cmd_array.inspect}") begin case command - when "set": aug.set(cmd_array[0], cmd_array[1]) - when "rm", "remove": aug.rm(cmd_array[0]) - when "clear": aug.clear(cmd_array[0]) - when "insert", "ins": aug.insert(cmd_array[0]) + when "set": + cmd_array[0]=File.join(context, cmd_array[0]) + debug("sending command '#{command}' with params #{cmd_array.inspect}") + aug.set(cmd_array[0], cmd_array[1]) + when "rm", "remove": + cmd_array[0]=File.join(context, cmd_array[0]) + debug("sending command '#{command}' with params #{cmd_array.inspect}") + aug.rm(cmd_array[0]) + when "clear": + cmd_array[0]=File.join(context, cmd_array[0]) + debug("sending command '#{command}' with params #{cmd_array.inspect}") + aug.clear(cmd_array[0]) + when "insert", "ins" + + ext_array = cmd_array[1].split(" ") ; + if cmd_array.size < 2 or ext_array.size < 2 + fail("ins requires 3 parameters") + end + label = cmd_array[0] + where = ext_array[0] + path = File.join(context, ext_array[1]) + case where + when "before": before = true + when "after": before = false + else fail("Invalid value '#{where}' for where param") + end + debug("sending command '#{command}' with params #{[label, where, path].inspect()}") + aug.insert(path, label, before) else fail("Command '#{command}' is not supported") end rescue Exception => e diff --git a/lib/puppet/provider/naginator.rb b/lib/puppet/provider/naginator.rb index 233d82eb6..5510eb9c8 100644 --- a/lib/puppet/provider/naginator.rb +++ b/lib/puppet/provider/naginator.rb @@ -7,6 +7,7 @@ require 'puppet/external/nagios' # The base class for all Naginator providers. class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile + NAME_STRING = "## --PUPPET_NAME-- (called '_naginator_name' in the manifest)" # Retrieve the associated class from Nagios::Base. def self.nagios_type unless defined?(@nagios_type) and @nagios_type @@ -24,14 +25,14 @@ class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile def self.parse(text) begin - Nagios::Parser.new.parse(text) + Nagios::Parser.new.parse(text.gsub(NAME_STRING, "_naginator_name")) rescue => detail raise Puppet::Error, "Could not parse configuration for %s: %s" % [resource_type.name, detail] end end def self.to_file(records) - header + records.collect { |record| record.to_s }.join("\n") + header + records.collect { |record| record.to_s }.join("\n").gsub("_naginator_name", NAME_STRING) end def self.skip_record?(record) diff --git a/lib/puppet/provider/package/up2date.rb b/lib/puppet/provider/package/up2date.rb index aa7c9eaf0..5708905cc 100644 --- a/lib/puppet/provider/package/up2date.rb +++ b/lib/puppet/provider/package/up2date.rb @@ -3,9 +3,11 @@ Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm d mechanism." commands :up2date => "/usr/sbin/up2date-nox" - defaultfor :operatingsystem => :redhat, + + defaultfor :operatingsystem => [:redhat, :oel, :ovm] :lsbdistrelease => ["2.1", "3", "4"] - confine :operatingsystem => :redhat + + confine :operatingsystem => [:redhat, :oel, :ovm] # Install a package using 'up2date'. def install diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb index a4c4bc87c..45eae57ff 100755 --- a/lib/puppet/provider/parsedfile.rb +++ b/lib/puppet/provider/parsedfile.rb @@ -78,8 +78,22 @@ class Puppet::Provider::ParsedFile < Puppet::Provider @modified.reject! { |t| flushed.include?(t) } end + # Make sure our file is backed up, but only back it up once per transaction. + # We cheat and rely on the fact that @records is created on each prefetch. + def self.backup_target(target) + unless defined?(@backup_stats) + @backup_stats = {} + end + return nil if @backup_stats[target] == @records.object_id + + target_object(target).backup + @backup_stats[target] = @records.object_id + end + # Flush all of the records relating to a specific target. def self.flush_target(target) + backup_target(target) + records = target_records(target).reject { |r| r[:ensure] == :absent } diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb index c6c3540f5..031db46c1 100755 --- a/lib/puppet/provider/service/redhat.rb +++ b/lib/puppet/provider/service/redhat.rb @@ -9,7 +9,7 @@ Puppet::Type.type(:service).provide :redhat, :parent => :init do commands :chkconfig => "/sbin/chkconfig", :service => "/sbin/service" - defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles] + defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles, :oel, :ovm] def self.defpath superclass.defpath diff --git a/lib/puppet/rails/database/003_add_environment_to_host.rb b/lib/puppet/rails/database/003_add_environment_to_host.rb index 4593a06f7..3ed10e946 100644 --- a/lib/puppet/rails/database/003_add_environment_to_host.rb +++ b/lib/puppet/rails/database/003_add_environment_to_host.rb @@ -1,9 +1,13 @@ class AddEnvironmentToHost < ActiveRecord::Migration def self.up - add_column :hosts, :environment, :string + unless ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment") + add_column :hosts, :environment, :string + end end def self.down - remove_column :hosts, :environment + if ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment") + remove_column :hosts, :environment + end end end diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb index 67b62e886..c89400b5e 100644 --- a/lib/puppet/type/augeas.rb +++ b/lib/puppet/type/augeas.rb @@ -92,10 +92,12 @@ Puppet::Type.newtype(:augeas) do rm [PATH] Removes the node at location PATH remove [PATH] Synonym for rm clear [PATH] Keeps the node at PATH, but removes the value. - ins [PATH] Inserts an empty node at PATH. - insert [PATH] Synonym for ins + ins [LABEL] [WHERE] [PATH] + Inserts an empty node LABEL either [WHERE={before|after}] PATH. + insert [LABEL] [WHERE] [PATH] + Synonym for ins - If the parameter 'context' is set that that value is prepended to PATH" + If the parameter 'context' is set that value is prepended to PATH" munge do |value| provider.parse_commands(value) diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index 535d9ef2e..0c80f8b06 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -78,7 +78,7 @@ class Puppet::Util::Autoload name = symbolize(name) loaded name, file return true - rescue LoadError => detail + rescue Exception => detail # I have no idea what's going on here, but different versions # of ruby are raising different errors on missing files. unless detail.to_s =~ /^no such file/i @@ -115,7 +115,7 @@ class Puppet::Util::Autoload begin Kernel.require file loaded(name, file) - rescue => detail + rescue Exception => detail if Puppet[:trace] puts detail.backtrace end diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb index a58b9a23b..0f184d5c2 100755 --- a/lib/puppet/util/filetype.rb +++ b/lib/puppet/util/filetype.rb @@ -74,7 +74,7 @@ class Puppet::Util::FileType # Back the file up before replacing it. def backup - bucket.backup(@path) if FileTest.exists?(@path) + bucket.backup(@path) if File.exists?(@path) end # Pick or create a filebucket to use. @@ -94,7 +94,7 @@ class Puppet::Util::FileType newfiletype(:flat) do # Read the file. def read - if File.exists?(@path) + if File.exist?(@path) File.read(@path) else return nil @@ -103,17 +103,13 @@ class Puppet::Util::FileType # Remove the file. def remove - if File.exists?(@path) + if File.exist?(@path) File.unlink(@path) end end # Overwrite the file. def write(text) - backup() - - raise("Cannot create file %s in absent directory" % @path) unless FileTest.exist?(File.dirname(@path)) - require "tempfile" tf = Tempfile.new("puppet") tf.print text; tf.flush @@ -255,92 +251,4 @@ class Puppet::Util::FileType output_file.delete end end - - # Treat netinfo tables as a single file, just for simplicity of certain - # types - newfiletype(:netinfo) do - class << self - attr_accessor :format - end - def read - %x{nidump -r /#{@path} /} - end - - # This really only makes sense for cron tabs. - def remove - %x{nireport / /#{@path} name}.split("\n").each do |name| - newname = name.gsub(/\//, '\/').sub(/\s+$/, '') - output = %x{niutil -destroy / '/#{@path}/#{newname}'} - - unless $? == 0 - raise Puppet::Error, "Could not remove %s from %s" % - [name, @path] - end - end - end - - # Convert our table to an array of hashes. This only works for - # handling one table at a time. - def to_array(text = nil) - unless text - text = read - end - - hash = nil - - # Initialize it with the first record - records = [] - text.split("\n").each do |line| - next if line =~ /^[{}]$/ # Skip the wrapping lines - next if line =~ /"name" = \( "#{@path}" \)/ # Skip the table name - next if line =~ /CHILDREN = \(/ # Skip this header - next if line =~ /^ \)/ # and its closer - - # Now we should have nothing but records, wrapped in braces - - case line - when /^\s+\{/: hash = {} - when /^\s+\}/: records << hash - when /\s+"(\w+)" = \( (.+) \)/ - field = $1 - values = $2 - - # Always use an array - hash[field] = [] - - values.split(/, /).each do |value| - if value =~ /^"(.*)"$/ - hash[field] << $1 - else - raise ArgumentError, "Could not match value %s" % value - end - end - else - raise ArgumentError, "Could not match line %s" % line - end - end - - records - end - - def write(text) - text.gsub!(/^#.*\n/,'') - text.gsub!(/^$/,'') - if text == "" or text == "\n" - self.remove - return - end - unless format = self.class.format - raise Puppe::DevError, "You must define the NetInfo format to inport" - end - IO.popen("niload -d #{format} . 1>/dev/null 2>/dev/null", "w") { |p| - p.print text - } - - unless $? == 0 - raise ArgumentError, "Failed to write %s" % @path - end - end - end end - |