diff options
author | James Turnbull <james@lovedthanlost.net> | 2010-01-13 08:07:30 +1100 |
---|---|---|
committer | James Turnbull <james@lovedthanlost.net> | 2010-01-13 08:07:30 +1100 |
commit | b6f90dfcd96123c245b6f5fd93753790006387c0 (patch) | |
tree | 1668fd8ed480dc0d0cb49c4a3d7f8a13c77dbeb9 /lib/puppet | |
parent | e26e8319186c57a41ea7ca58b0e8e853e9b452e3 (diff) | |
parent | f7e14356ad7781fafa52a459d3c24372fa6c0900 (diff) | |
download | puppet-b6f90dfcd96123c245b6f5fd93753790006387c0.tar.gz puppet-b6f90dfcd96123c245b6f5fd93753790006387c0.tar.xz puppet-b6f90dfcd96123c245b6f5fd93753790006387c0.zip |
Merge branch '0.25.x'
Conflicts:
lib/puppet/ssl/host.rb
spec/spec_helper.rb
Diffstat (limited to 'lib/puppet')
63 files changed, 461 insertions, 485 deletions
diff --git a/lib/puppet/application/puppet.rb b/lib/puppet/application/puppet.rb index b4c06d279..e4baf5d05 100644 --- a/lib/puppet/application/puppet.rb +++ b/lib/puppet/application/puppet.rb @@ -49,7 +49,7 @@ Puppet::Application.new(:puppet) do end begin - catalog = PSON.parse(text) + catalog = Puppet::Resource::Catalog.convert_from(Puppet::Resource::Catalog.default_format,text) unless catalog.is_a?(Puppet::Resource::Catalog) catalog = Puppet::Resource::Catalog.pson_create(catalog) end diff --git a/lib/puppet/application/puppetdoc.rb b/lib/puppet/application/puppetdoc.rb index 0a4e0c3c3..e0033277f 100644 --- a/lib/puppet/application/puppetdoc.rb +++ b/lib/puppet/application/puppetdoc.rb @@ -68,7 +68,7 @@ Puppet::Application.new(:puppetdoc) do unless @manifest env = Puppet::Node::Environment.new files += env.modulepath - files += env.manifestdir + files << File.dirname(env[:manifest]) end files += ARGV Puppet.info "scanning: %s" % files.inspect diff --git a/lib/puppet/application/puppetrun.rb b/lib/puppet/application/puppetrun.rb index 2dbd803fa..4febcf524 100644 --- a/lib/puppet/application/puppetrun.rb +++ b/lib/puppet/application/puppetrun.rb @@ -1,18 +1,9 @@ -begin - require 'rubygems' -rescue LoadError - # Nothing; we were just doing this just in case -end - -begin - require 'ldap' -rescue LoadError - $stderr.puts "Failed to load ruby LDAP library. LDAP functionality will not be available" -end - require 'puppet' require 'puppet/application' +Puppet.warning "RubyGems not installed" unless Puppet.features.rubygems? +Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap? + Puppet::Application.new(:puppetrun) do should_not_parse_config @@ -176,12 +167,12 @@ Puppet::Application.new(:puppetrun) do if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes) if options[:all] - @hosts = Puppet::Node.search("whatever").collect { |node| node.name } + @hosts = Puppet::Node.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name } puts "all: %s" % @hosts.join(", ") else @hosts = [] @classes.each do |klass| - list = Puppet::Node.search("whatever", :class => klass).collect { |node| node.name } + list = Puppet::Node.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name } puts "%s: %s" % [klass, list.join(", ")] @hosts += list diff --git a/lib/puppet/application/ralsh.rb b/lib/puppet/application/ralsh.rb index 6ad520dca..b9f7a587c 100644 --- a/lib/puppet/application/ralsh.rb +++ b/lib/puppet/application/ralsh.rb @@ -38,25 +38,15 @@ Puppet::Application.new(:ralsh) do end command(:main) do - if ARGV.length > 0 - type = ARGV.shift - else - raise "You must specify the type to display" - end - - name = nil + type = ARGV.shift or raise "You must specify the type to display" + typeobj = Puppet::Type.type(type) or raise "Could not find type #{type}" + name = ARGV.shift params = {} - if ARGV.length > 0 - name = ARGV.shift - end - - if ARGV.length > 0 - ARGV.each do |setting| - if setting =~ /^(\w+)=(.+)$/ - params[$1] = $2 - else - raise "Invalid parameter setting %s" % setting - end + ARGV.each do |setting| + if setting =~ /^(\w+)=(.+)$/ + params[$1] = $2 + else + raise "Invalid parameter setting %s" % setting end end @@ -64,12 +54,6 @@ Puppet::Application.new(:ralsh) do raise "You cannot edit a remote host" end - typeobj = nil - - unless typeobj = Puppet::Type.type(type) - raise "Could not find type %s" % type - end - properties = typeobj.properties.collect { |s| s.name } format = proc {|trans| @@ -106,7 +90,7 @@ Puppet::Application.new(:ralsh) do transbucket.sort { |a,b| a.name <=> b.name }.collect(&format) else if name - obj = typeobj.new(:name => name, :check => properties) + obj = typeobj.instances.find { |o| o.name == name } || typeobj.new(:name => name, :check => properties) vals = obj.retrieve unless params.empty? diff --git a/lib/puppet/configurer/fact_handler.rb b/lib/puppet/configurer/fact_handler.rb index cbb627680..40e79b6c6 100644 --- a/lib/puppet/configurer/fact_handler.rb +++ b/lib/puppet/configurer/fact_handler.rb @@ -27,12 +27,15 @@ module Puppet::Configurer::FactHandler facts = find_facts #format = facts.class.default_format - # Hard-code yaml, because I couldn't get marshal to work. - format = :b64_zlib_yaml + if facts.support_format?(:b64_zlib_yaml) + format = :b64_zlib_yaml + else + format = :yaml + end text = facts.render(format) - return {:facts_format => :b64_zlib_yaml, :facts => CGI.escape(text)} + return {:facts_format => format, :facts => CGI.escape(text)} end # Retrieve facts from the central server. diff --git a/lib/puppet/daemon.rb b/lib/puppet/daemon.rb index 16b1f80d2..0f538fe44 100755 --- a/lib/puppet/daemon.rb +++ b/lib/puppet/daemon.rb @@ -31,10 +31,10 @@ class Puppet::Daemon $stderr.reopen $stdout Puppet::Util::Log.reopen rescue => detail - File.open("/tmp/daemonout", "w") { |f| + Puppet.err "Could not start %s: %s" % [Puppet[:name], detail] + Puppet::Util::secure_open("/tmp/daemonout", "w") { |f| f.puts "Could not start %s: %s" % [Puppet[:name], detail] } - Puppet.err "Could not start %s: %s" % [Puppet[:name], detail] exit(12) end end diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 050fcaa7e..ca4b9b8d0 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -160,7 +160,7 @@ module Puppet :http_proxy_port => [3128, "The HTTP proxy port to use for outgoing connections"], :http_enable_post_connection_check => [true, - "Boolean; wheter or not puppetd should validate the server + "Boolean; whether or not puppetd should validate the server SSL certificate against the request hostname."], :filetimeout => [ 15, "The minimum time to wait (in seconds) between checking for updates in @@ -196,7 +196,10 @@ module Puppet :config_version => ["", "How to determine the configuration version. By default, it will be the time that the configuration is parsed, but you can provide a shell script to override how the version is determined. The output of this script will be added to every log message in the - reports, allowing you to correlate changes on your hosts to the source version on the server."] + reports, allowing you to correlate changes on your hosts to the source version on the server."], + :zlib => [true, + "Boolean; whether to use the zlib library", + ] ) hostname = Facter["hostname"].value diff --git a/lib/puppet/external/pson/pure.rb b/lib/puppet/external/pson/pure.rb index 7bb18aa70..53d1ea2a7 100644 --- a/lib/puppet/external/pson/pure.rb +++ b/lib/puppet/external/pson/pure.rb @@ -50,7 +50,7 @@ module PSON UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc: end rescue Errno::EINVAL, Iconv::InvalidEncoding - raise MissingUnicodeSupport, "iconv doesn't seem to support UTF-8/UTF-16 conversions" + Puppet.warning "iconv doesn't seem to support UTF-8/UTF-16 conversions" ensure $VERBOSE = old_verbose end diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb index c3fb9a2f3..aac04f234 100644 --- a/lib/puppet/feature/base.rb +++ b/lib/puppet/feature/base.rb @@ -28,3 +28,6 @@ Puppet.features.add(:augeas, :libs => ["augeas"]) # We have RRD available Puppet.features.add(:rrd, :libs => ["RRDtool"]) + +# We have OpenSSL +Puppet.features.add(:openssl, :libs => ["openssl"]) diff --git a/lib/puppet/feature/selinux.rb b/lib/puppet/feature/selinux.rb new file mode 100644 index 000000000..84be239fc --- /dev/null +++ b/lib/puppet/feature/selinux.rb @@ -0,0 +1,3 @@ +require 'puppet/util/feature' + +Puppet.features.add(:selinux, :libs => ["selinux"]) diff --git a/lib/puppet/feature/zlib.rb b/lib/puppet/feature/zlib.rb new file mode 100644 index 000000000..ddd65b234 --- /dev/null +++ b/lib/puppet/feature/zlib.rb @@ -0,0 +1,6 @@ +require 'puppet/util/feature' + +# We want this to load if possible, but it's not automatically +# required. +Puppet.features.rubygems? +Puppet.features.add(:zlib, :libs => %{zlib}) diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb index 275a090eb..6790c1a78 100644 --- a/lib/puppet/file_serving/metadata.rb +++ b/lib/puppet/file_serving/metadata.rb @@ -22,18 +22,15 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::Base PARAM_ORDER = [:mode, :ftype, :owner, :group] def attributes_with_tabs + raise(ArgumentError, "Cannot manage files of type #{ftype}") unless ['file','directory','link'].include? ftype desc = [] PARAM_ORDER.each { |check| check = :ftype if check == :type desc << send(check) } - case ftype - when "file", "directory"; desc << checksum - when "link"; desc << @destination - else - raise ArgumentError, "Cannot manage files of type %s" % ftype - end + desc << checksum + desc << @destination rescue nil if ftype == 'link' return desc.join("\t") end @@ -66,6 +63,7 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::Base @checksum = ("{%s}" % @checksum_type) + send("%s_file" % @checksum_type, path).to_s when "link" @destination = File.readlink(real_path) + @checksum = ("{%s}" % @checksum_type) + send("%s_file" % @checksum_type, real_path).to_s rescue nil else raise ArgumentError, "Cannot manage files of type %s" % stat.ftype end diff --git a/lib/puppet/file_serving/mount/file.rb b/lib/puppet/file_serving/mount/file.rb index bf7ddda45..4309ef79a 100644 --- a/lib/puppet/file_serving/mount/file.rb +++ b/lib/puppet/file_serving/mount/file.rb @@ -25,7 +25,10 @@ class Puppet::FileServing::Mount::File < Puppet::FileServing::Mount file = ::File.join(full_path, relative_path) - return nil unless FileTest.exist?(file) + if ! FileTest.exist?(file) + Puppet.info("File does not exist or is not accessible: #{file}") + return nil + end return file end diff --git a/lib/puppet/indirector/envelope.rb b/lib/puppet/indirector/envelope.rb index ef7952ef6..5fdea7081 100644 --- a/lib/puppet/indirector/envelope.rb +++ b/lib/puppet/indirector/envelope.rb @@ -6,8 +6,6 @@ module Puppet::Indirector::Envelope attr_accessor :expiration def expired? - return false unless expiration - return false if expiration >= Time.now - return true + expiration and expiration < Time.now end end diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb index dc7e58f36..d762701f5 100644 --- a/lib/puppet/indirector/indirection.rb +++ b/lib/puppet/indirector/indirection.rb @@ -161,22 +161,19 @@ class Puppet::Indirector::Indirection end end - # Expire a cached object, if one is cached. Note that we don't actually - # remove it, we expire it and write it back out to disk. This way people - # can still use the expired object if they want. + # Expire a cached object, if one is cached. Note that we now actually + # remove it if possible, and only mark it as expired if destroy isn't + # supported. def expire(key, *args) - request = request(:expire, key, *args) - - return nil unless cache? - - return nil unless instance = cache.find(request(:find, key, *args)) - - Puppet.info "Expiring the %s cache of %s" % [self.name, instance.name] - - # Set an expiration date in the past - instance.expiration = Time.now - 60 - - cache.save(request(:save, instance, *args)) + if cache? and instance = cache.find(request(:find, key, *args)) + Puppet.info "Expiring the #{name} cache of #{instance.name}" + if cache.respond_to? :destroy + cache.destroy(request(:destroy, instance, *args)) + else + instance.expiration = Time.now - 1 + cache.save(request(:save,instance,*args)) + end + end end # Search for an instance in the appropriate terminus, caching the @@ -216,7 +213,7 @@ class Puppet::Indirector::Indirection return nil end - Puppet.debug "Using cached %s for %s" % [self.name, request.key] + Puppet.debug "Using cached #{name} for #{request.key}, good until #{cached.expiration}" return cached end diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb index dd8cebfac..954bc8d78 100644 --- a/lib/puppet/indirector/node/ldap.rb +++ b/lib/puppet/indirector/node/ldap.rb @@ -55,7 +55,7 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap end infos = [] - ldapsearch(filter) { |entry| infos << entry2hash(entry) } + ldapsearch(filter) { |entry| infos << entry2hash(entry, request.options[:fqdn]) } return infos.collect do |info| info2node(info[:name], info) @@ -78,9 +78,12 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap end # Convert the found entry into a simple hash. - def entry2hash(entry) + def entry2hash(entry, fqdn = false) result = {} - result[:name] = entry.dn.split(',')[0].split("=")[1] + + cn = entry.dn[ /cn\s*=\s*([^,\s]+)/i,1] + dcs = entry.dn.scan(/dc\s*=\s*([^,\s]+)/i) + result[:name] = fqdn ? ([cn]+dcs).join('.') : cn result[:parent] = get_parent_from_entry(entry) if parent_attribute result[:classes] = get_classes_from_entry(entry) result[:stacked] = get_stacked_values_from_entry(entry) diff --git a/lib/puppet/indirector/ssl_file.rb b/lib/puppet/indirector/ssl_file.rb index 67202699d..fc1e65d22 100644 --- a/lib/puppet/indirector/ssl_file.rb +++ b/lib/puppet/indirector/ssl_file.rb @@ -91,7 +91,7 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus def save(request) path = path(request.key) dir = File.dirname(path) - + raise Puppet::Error.new("Cannot save %s; parent directory %s does not exist" % [request.key, dir]) unless FileTest.directory?(dir) raise Puppet::Error.new("Cannot save %s; parent directory %s is not writable" % [request.key, dir]) unless FileTest.writable?(dir) diff --git a/lib/puppet/network/authstore.rb b/lib/puppet/network/authstore.rb index fb3d0145b..a7029a0a0 100755 --- a/lib/puppet/network/authstore.rb +++ b/lib/puppet/network/authstore.rb @@ -49,7 +49,7 @@ module Puppet return decl.result end - self.info "defaulting to no access for %s" % name + info "defaulting to no access for %s" % name return false end @@ -78,11 +78,7 @@ module Puppet end def interpolate(match) - declarations = @declarations.collect do |ace| - ace.interpolate(match) - end - declarations.sort! - Thread.current[:declarations] = declarations + Thread.current[:declarations] = @declarations.collect { |ace| ace.interpolate(match) }.sort end def reset_interpolation @@ -96,8 +92,7 @@ module Puppet # this is used if we want to override the this purely immutable list # by a modified version in a multithread safe way. def declarations - return Thread.current[:declarations] if Thread.current[:declarations] - @declarations + Thread.current[:declarations] || @declarations end # Store the results of a pattern into our hash. Basically just @@ -130,46 +125,21 @@ module Puppet # The length. Only used for iprange and domain. attr_accessor :length - # Sort the declarations specially. + # Sort the declarations most specific first. def <=>(other) - # Sort first based on whether the matches are exact. - if r = compare(exact?, other.exact?) - return r - end - - # Then by type - if r = compare(self.ip?, other.ip?) - return r - end - - # Next sort based on length - unless self.length == other.length - # Longer names/ips should go first, because they're more - # specific. - return other.length <=> self.length - end - - # Then sort deny before allow - if r = compare(self.deny?, other.deny?) - return r - end - - # We've already sorted by name and length, so all that's left - # is the pattern - if ip? - return self.pattern.to_s <=> other.pattern.to_s - else - return self.pattern <=> other.pattern - end + compare(exact?, other.exact?) || + compare(ip?, other.ip?) || + ((length != other.length) && (other.length <=> length)) || + compare(deny?, other.deny?) || + ( ip? ? pattern.to_s <=> other.pattern.to_s : pattern <=> other.pattern) end def deny? - self.type == :deny + type == :deny end - # Are we an exact match? def exact? - self.length.nil? + @exact == :exact end def initialize(type, pattern) @@ -179,16 +149,12 @@ module Puppet # Are we an IP type? def ip? - self.name == :ip + name == :ip end # Does this declaration match the name/ip combo? def match?(name, ip) - if self.ip? - return pattern.include?(IPAddr.new(ip)) - else - return matchname?(name) - end + ip? ? pattern.include?(IPAddr.new(ip)) : matchname?(name) end # Set the pattern appropriately. Also sets the name and length. @@ -199,15 +165,11 @@ module Puppet # Mapping a type of statement into a return value. def result - case @type - when :allow; true - else - false - end + type == :allow end def to_s - "%s: %s" % [self.type, self.pattern] + "#{type}: #{pattern}" end # Set the declaration type. Either :allow or :deny. @@ -238,86 +200,54 @@ module Puppet # -1 if the first is true, and 1 if the second is true. Used # in the <=> operator. def compare(me, them) - unless me and them - if me - return -1 - elsif them - return 1 - else - return false - end - end - return nil + (me and them) ? nil : me ? -1 : them ? 1 : nil end # Does the name match our pattern? def matchname?(name) name = munge_name(name) - return true if self.pattern == name - - # If it's an exact match, then just return false, since the - # exact didn't match. - if exact? - return false - end - - # If every field in the pattern matches, then we consider it - # a match. - pattern.zip(name) do |p,n| - unless p == n - return false - end - end - - return true + (pattern == name) or (not exact? and pattern.zip(name).all? { |p,n| p == n }) end # Convert the name to a common pattern. def munge_name(name) # LAK:NOTE http://snurl.com/21zf8 [groups_google_com] - # Change to x = name.downcase.split(".",-1).reverse for FQDN support - x = name.downcase.split(".").reverse + # Change to name.downcase.split(".",-1).reverse for FQDN support + name.downcase.split(".").reverse end # Parse our input pattern and figure out what kind of allowal # statement it is. The output of this is used for later matching. + Octet = '(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])' + IPv4 = "#{Octet}\.#{Octet}\.#{Octet}\.#{Octet}" + IPv6_full = "_:_:_:_:_:_:_:_|_:_:_:_:_:_::_?|_:_:_:_:_::((_:)?_)?|_:_:_:_::((_:){0,2}_)?|_:_:_::((_:){0,3}_)?|_:_::((_:){0,4}_)?|_::((_:){0,5}_)?|::((_:){0,6}_)?" + IPv6_partial = "_:_:_:_:_:_:|_:_:_:_::(_:)?|_:_::(_:){0,2}|_::(_:){0,3}" + # It should be: + # IP = "#{IPv4}|#{IPv6_full}|(#{IPv6_partial}#{IPv4})".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:') + # but ruby's ipaddr lib doesn't support the hybrid format + IP = "#{IPv4}|#{IPv6_full}".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:') def parse(value) - # Use the IPAddr class to determine if we've got a - # valid IP address. - @length = Integer($1) if value =~ /\/(\d+)$/ - begin - @pattern = IPAddr.new(value) - @name = :ip - rescue ArgumentError => detail - case value - when /^(\d+\.){1,3}\*$/ # an ip address with a '*' at the end - @name = :ip - segments = value.split(".")[0..-2] - @length = 8*segments.length - begin - @pattern = IPAddr.new((segments+[0,0,0])[0,4].join(".") + "/" + @length.to_s) - rescue ArgumentError => detail - raise AuthStoreError, "Invalid IP address pattern %s" % value - end - when /^([a-zA-Z0-9][-\w]*\.)+[-\w]+$/ # a full hostname - # Change to /^([a-zA-Z][-\w]*\.)+[-\w]+\.?$/ for FQDN support - @name = :domain - @pattern = munge_name(value) - when /^\*(\.([a-zA-Z][-\w]*)){1,}$/ # *.domain.com - @name = :domain - @pattern = munge_name(value) - @pattern.pop # take off the '*' - @length = @pattern.length - when /\$\d+/ # a backreference pattern ala $1.reductivelabs.com or 192.168.0.$1 or $1.$2 - @name = :dynamic - @pattern = munge_name(value) - when /^[a-zA-Z0-9][-a-zA-Z0-9_.@]*$/ - @pattern = [value] - @length = nil # force an exact match - @name = :opaque - else - raise AuthStoreError, "Invalid pattern %s" % value - end + @name,@exact,@length,@pattern = *case value + when /^(?:#{IP})\/(\d+)$/ # 12.34.56.78/24, a001:b002::efff/120, c444:1000:2000::9:192.168.0.1/112 + [:ip,:inexact,$1.to_i,IPAddr.new(value)] + when /^(#{IP})$/ # 10.20.30.40, + [:ip,:exact,nil,IPAddr.new(value)] + when /^(#{Octet}\.){1,3}\*$/ # an ip address with a '*' at the end + segments = value.split(".")[0..-2] + bits = 8*segments.length + [:ip,:inexact,bits,IPAddr.new((segments+[0,0,0])[0,4].join(".") + "/#{bits}")] + when /^(\w[-\w]*\.)+[-\w]+$/ # a full hostname + # Change to /^(\w[-\w]*\.)+[-\w]+\.?$/ for FQDN support + [:domain,:exact,nil,munge_name(value)] + when /^\*(\.(\w[-\w]*)){1,}$/ # *.domain.com + host_sans_star = munge_name(value)[0..-2] + [:domain,:inexact,host_sans_star.length,host_sans_star] + when /\$\d+/ # a backreference pattern ala $1.reductivelabs.com or 192.168.0.$1 or $1.$2 + [:dynamic,:exact,nil,munge_name(value)] + when /^\w[-.@\w]*$/ # ? Just like a host name but allow '@'s and ending '.'s + [:opaque,:exact,nil,[value]] + else + raise AuthStoreError, "Invalid pattern %s" % value end end end diff --git a/lib/puppet/network/client/resource.rb b/lib/puppet/network/client/resource.rb index bc4a8e53f..ad3210603 100644 --- a/lib/puppet/network/client/resource.rb +++ b/lib/puppet/network/client/resource.rb @@ -27,25 +27,12 @@ class Puppet::Network::Client::Resource < Puppet::Network::Client def describe(type, name, retrieve = false, ignore = false) Puppet.info "Describing %s[%s]" % [type.to_s.capitalize, name] text = @driver.describe(type, name, retrieve, ignore, "yaml") - - object = nil - if @local - object = text - else - object = YAML::load(Base64.decode64(text)) - end - - return object + @local ? text : YAML::load(Base64.decode64(text)) end def list(type, ignore = false, base = false) bucket = @driver.list(type, ignore, base, "yaml") - - unless @local - bucket = YAML::load(Base64.decode64(bucket)) - end - - return bucket + @local ? bucket : YAML::load(Base64.decode64(bucket)) end end diff --git a/lib/puppet/network/format.rb b/lib/puppet/network/format.rb index a5be3aff8..d78124221 100644 --- a/lib/puppet/network/format.rb +++ b/lib/puppet/network/format.rb @@ -107,17 +107,7 @@ class Puppet::Network::Format method = send(name) - if type == :class - has_method = klass.respond_to?(method) - message = "has not implemented method '%s'" % method - else - has_method = klass.instance_methods.include?(method) - message = "has not implemented instance method '%s'" % method - end - - return true if has_method - - Puppet.debug "Format %s not supported for %s; %s" % [self.name, klass, message] - return false + return klass.respond_to?(method) if type == :class + return klass.instance_methods.include?(method) end end diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb index e508a0283..ea8cf35de 100644 --- a/lib/puppet/network/format_handler.rb +++ b/lib/puppet/network/format_handler.rb @@ -119,18 +119,30 @@ module Puppet::Network::FormatHandler format_handler.format(b).weight <=> format_handler.format(a).weight end - put_preferred_format_first(result) + result = put_preferred_format_first(result) + + Puppet.debug "#{friendly_name} supports formats: #{result.map{ |f| f.to_s }.sort.join(' ')}; using #{result.first}" + + result end private + def friendly_name + if self.respond_to? :indirection + indirection.name + else + self + end + end + def put_preferred_format_first(list) preferred_format = Puppet.settings[:preferred_serialization_format].to_sym if list.include?(preferred_format) list.delete(preferred_format) list.unshift(preferred_format) else - Puppet.warning "Value of 'preferred_serialization_format' ('#{preferred_format}') is invalid, using default ('#{list.first}')" + Puppet.warning "Value of 'preferred_serialization_format' (#{preferred_format}) is invalid for #{friendly_name}, using default (#{list.first})" end list end diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb index 010c23521..a98dcbcc5 100644 --- a/lib/puppet/network/formats.rb +++ b/lib/puppet/network/formats.rb @@ -44,7 +44,18 @@ end # This format combines a yaml serialization, then zlib compression and base64 encoding. Puppet::Network::FormatHandler.create(:b64_zlib_yaml, :mime => "text/b64_zlib_yaml") do require 'base64' - require 'zlib' + + def use_zlib? + Puppet.features.zlib? && Puppet[:zlib] + end + + def requiring_zlib + if use_zlib? + yield + else + raise Puppet::Error, "the zlib library is not installed or is disabled." + end + end def intern(klass, text) decode(text) @@ -70,7 +81,7 @@ Puppet::Network::FormatHandler.create(:b64_zlib_yaml, :mime => "text/b64_zlib_ya # Because of yaml issue in ruby 1.8.1... def supported?(klass) - RUBY_VERSION != '1.8.1' + RUBY_VERSION != '1.8.1' and use_zlib? end # fixup invalid yaml as per: @@ -81,11 +92,15 @@ Puppet::Network::FormatHandler.create(:b64_zlib_yaml, :mime => "text/b64_zlib_ya end def encode(text) - Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION)) + requiring_zlib do + Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION)) + end end def decode(yaml) - YAML.load(Zlib::Inflate.inflate(Base64.decode64(yaml))) + requiring_zlib do + YAML.load(Zlib::Inflate.inflate(Base64.decode64(yaml))) + end end end diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index 6bc6d9d4a..7049fb0dc 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -310,6 +310,7 @@ class Puppet::Network::Handler mount.info "allowing %s access" % val mount.allow(val) rescue AuthStoreError => detail + puts detail.backtrace if Puppet[:trace] raise FileServerError.new(detail.to_s, count, @configuration.file) end diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb index 817661db1..65bb0f82c 100644 --- a/lib/puppet/network/http/handler.rb +++ b/lib/puppet/network/http/handler.rb @@ -97,6 +97,7 @@ module Puppet::Network::HTTP::Handler # Execute our find. def do_find(indirection_request, request, response) unless result = indirection_request.model.find(indirection_request.key, indirection_request.to_hash) + Puppet.info("Could not find %s for '%s'" % [indirection_request.indirection_name, indirection_request.key]) return do_exception(response, "Could not find %s %s" % [indirection_request.indirection_name, indirection_request.key], 404) end diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb index e0fe8b621..1a3f5ddce 100644 --- a/lib/puppet/network/http/webrick.rb +++ b/lib/puppet/network/http/webrick.rb @@ -44,7 +44,8 @@ class Puppet::Network::HTTP::WEBrick sock.accept @server.run(sock) } - } + } + sleep 0.1 until @server.status == :Running end end diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb index f21254be9..01a55df36 100644 --- a/lib/puppet/network/server.rb +++ b/lib/puppet/network/server.rb @@ -22,7 +22,7 @@ class Puppet::Network::Server $stderr.reopen $stdout Puppet::Util::Log.reopen rescue => detail - File.open("/tmp/daemonout", "w") { |f| + Puppet::Util.secure_open("/tmp/daemonout", "w") { |f| f.puts "Could not start %s: %s" % [Puppet[:name], detail] } raise "Could not start %s: %s" % [Puppet[:name], detail] diff --git a/lib/puppet/parser/functions/shellquote.rb b/lib/puppet/parser/functions/shellquote.rb index 6c994520c..0a7ae5958 100644 --- a/lib/puppet/parser/functions/shellquote.rb +++ b/lib/puppet/parser/functions/shellquote.rb @@ -10,7 +10,7 @@ module Puppet::Parser::Functions with spaces. If an argument is an array, the elements of that array is interpolated within the rest of the arguments; this makes it possible to have an array of arguments and pass that array to - shellquote() instead of having to specify specify each argument + shellquote() instead of having to specify each argument individually in the call. ") \ do |args| diff --git a/lib/puppet/property.rb b/lib/puppet/property.rb index 76c388eb6..7d5edcfc1 100644 --- a/lib/puppet/property.rb +++ b/lib/puppet/property.rb @@ -355,20 +355,12 @@ class Puppet::Property < Puppet::Parameter end def should_to_s(newvalue) - newvalue = [newvalue] unless newvalue.is_a? Array - if defined? newvalue - newvalue.join(" ") - else - return nil - end + [newvalue].flatten.join(" ") end def sync - if value = self.should - set(value) - else - self.devfail "Got a nil value for should" - end + devfail "Got a nil value for should" unless should + set(should) end def to_s diff --git a/lib/puppet/provider/cron/crontab.rb b/lib/puppet/provider/cron/crontab.rb index 82384d09d..28ef05974 100755 --- a/lib/puppet/provider/cron/crontab.rb +++ b/lib/puppet/provider/cron/crontab.rb @@ -3,6 +3,8 @@ require 'puppet/provider/parsedfile' tab = case Facter.value(:operatingsystem) when "Solaris" :suntab + when "AIX" + :aixtab else :crontab end @@ -25,18 +27,13 @@ Puppet::Type.type(:cron).provide(:crontab, text_line :environment, :match => %r{^\w+=} - record_line :freebsd_special, :fields => %w{special command}, - :match => %r{^@(\w+)\s+(.+)$}, :pre_gen => proc { |record| - record[:special] = "@" + record[:special] - } - - crontab = record_line :crontab, :fields => %w{minute hour monthday month weekday command}, - :match => %r{^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$}, - :optional => %w{minute hour weekday month monthday}, :absent => "*" + crontab = record_line :crontab, :fields => %w{special minute hour monthday month weekday command}, + :match => %r{^\s*(?:@(\w+)|(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+))\s+(.+)$}, + :optional => %w{special minute hour weekday month monthday}, :absent => "*" class << crontab def numeric_fields - fields - [:command] + fields - [:command, :special] end # Do some post-processing of the parsed record. Basically just # split the numeric fields on ','. diff --git a/lib/puppet/provider/host/parsed.rb b/lib/puppet/provider/host/parsed.rb index e6381384e..f3e76305d 100644 --- a/lib/puppet/provider/host/parsed.rb +++ b/lib/puppet/provider/host/parsed.rb @@ -17,8 +17,8 @@ Puppet::Type.type(:host).provide(:parsed, text_line :comment, :match => /^#/ text_line :blank, :match => /^\s*$/ - record_line :parsed, :fields => %w{ip name alias}, - :optional => %w{alias}, + record_line :parsed, :fields => %w{ip name host_aliases}, + :optional => %w{host_aliases}, :rts => true do |line| hash = {} if line.sub!(/^(\S+)\s+(\S+)\s*/, '') @@ -30,7 +30,7 @@ Puppet::Type.type(:host).provide(:parsed, line.sub!(/^([^#]+)\s*/) do |value| aliases = $1 unless aliases =~ /^\s*$/ - hash[:alias] = aliases.split(/\s+/) + hash[:host_aliases] = aliases.split(/\s+/) end "" @@ -40,8 +40,8 @@ Puppet::Type.type(:host).provide(:parsed, raise Puppet::Error, "Could not match '%s'" % line end - if hash[:alias] == "" - hash.delete(:alias) + if hash[:host_aliases] == "" + hash.delete(:host_aliases) end return hash @@ -58,11 +58,11 @@ Puppet::Type.type(:host).provide(:parsed, str = "%s\t%s" % [hash[:ip], hash[:name]] - if hash.include? :alias - if hash[:alias].is_a? Array - str += "\t%s" % hash[:alias].join("\t") + if hash.include? :host_aliases + if hash[:host_aliases].is_a? Array + str += "\t%s" % hash[:host_aliases].join("\t") else - raise ArgumentError, "Aliases must be specified as an array" + raise ArgumentError, "Host aliases must be specified as an array" end end diff --git a/lib/puppet/provider/mount/parsed.rb b/lib/puppet/provider/mount/parsed.rb index c660807ce..b30de2bc7 100755 --- a/lib/puppet/provider/mount/parsed.rb +++ b/lib/puppet/provider/mount/parsed.rb @@ -31,6 +31,15 @@ Puppet::Type.type(:mount).provide(:parsed, text_line :comment, :match => /^\s*#/ text_line :blank, :match => /^\s*$/ - record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => [:pass, :dump] + optional_fields = @fields - [:device, :name, :blockdevice] + mandatory_fields = @fields - optional_fields + + # fstab will ignore lines that have fewer than the mandatory number of columns, + # so we should, too. + field_pattern = '(\s*(?>\S+))' + text_line :incomplete, :match => /^(?!#{field_pattern}{#{mandatory_fields.length}})/ + + record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => optional_fields + end diff --git a/lib/puppet/provider/package/blastwave.rb b/lib/puppet/provider/package/blastwave.rb index a2f86aa5a..cf2c87bfe 100755 --- a/lib/puppet/provider/package/blastwave.rb +++ b/lib/puppet/provider/package/blastwave.rb @@ -10,8 +10,9 @@ Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun commands :pkgget => pkgget - # This is so stupid, but then, so is blastwave. - ENV["PAGER"] = "/usr/bin/cat" + def pkgget_with_cat(*args) + withenv(:PAGER => "/usr/bin/cat") { pkgget(*args) } + end def self.extended(mod) unless command(:pkgget) != "pkg-get" @@ -40,7 +41,7 @@ Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun command << hash[:justme] end - output = pkgget command + output = pkgget_with_cat command list = output.split("\n").collect do |line| next if line =~ /^#/ @@ -88,7 +89,7 @@ Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun end def install - pkgget "-f", :install, @resource[:name] + pkgget_with_cat "-f", :install, @resource[:name] end # Retrieve the version from the current package file. @@ -107,11 +108,11 @@ Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun # Remove the old package, and install the new one def update - pkgget "-f", :upgrade, @resource[:name] + pkgget_with_cat "-f", :upgrade, @resource[:name] end def uninstall - pkgget "-f", :remove, @resource[:name] + pkgget_with_cat "-f", :remove, @resource[:name] end end diff --git a/lib/puppet/provider/package/rug.rb b/lib/puppet/provider/package/rug.rb index ca27cbbd3..9f09b35fe 100644 --- a/lib/puppet/provider/package/rug.rb +++ b/lib/puppet/provider/package/rug.rb @@ -36,7 +36,7 @@ Puppet::Type.type(:package).provide :rug, :parent => :rpm do #rug can only get a list of *all* available packages? output = rug "list-updates" - if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([0-9\.\-]+)/ + if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([^\s\|]+)/ return $1 else # rug didn't find updates, pretend the current diff --git a/lib/puppet/provider/package/sun.rb b/lib/puppet/provider/package/sun.rb index f72738e2f..4f8b311ab 100755 --- a/lib/puppet/provider/package/sun.rb +++ b/lib/puppet/provider/package/sun.rb @@ -94,7 +94,7 @@ Puppet::Type.type(:package).provide :sun, :parent => Puppet::Provider::Package d execpipe(cmd) { |process| # we're using the long listing, so each line is a separate # piece of information - process.each { |line| + process.readlines.each { |line| case line when /^$/ # ignore when /\s*([A-Z]+):\s+(.+)/ @@ -111,8 +111,10 @@ Puppet::Type.type(:package).provide :sun, :parent => Puppet::Provider::Package d } } return hash - rescue Puppet::ExecutionFailure - return nil + rescue Puppet::ExecutionFailure => detail + return {:ensure => :absent} if detail.message =~ /information for "#{Regexp.escape(@resource[:name])}" was not found/ + puts detail.backtrace if Puppet[:trace] + raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{detail}" end end diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb index 965773d96..c05a32677 100755 --- a/lib/puppet/provider/service/init.rb +++ b/lib/puppet/provider/service/init.rb @@ -70,8 +70,23 @@ Puppet::Type.type(:service).provide :init, :parent => :base do @initscript ||= self.search(@resource[:name]) end + def paths + @paths ||= @resource[:path].find_all do |path| + if File.directory?(path) + true + else + if File.exist?(path) and ! File.directory?(path) + self.debug "Search path #{path} is not a directory" + else + self.debug "Search path #{path} does not exist" + end + false + end + end + end + def search(name) - @resource[:path].each { |path| + paths.each { |path| fqname = File.join(path,name) begin stat = File.stat(fqname) @@ -84,7 +99,8 @@ Puppet::Type.type(:service).provide :init, :parent => :base do # if we've gotten this far, we found a valid script return fqname } - @resource[:path].each { |path| + + paths.each { |path| fqname_sh = File.join(path,"#{name}.sh") begin stat = File.stat(fqname_sh) diff --git a/lib/puppet/provider/sshkey/parsed.rb b/lib/puppet/provider/sshkey/parsed.rb index 0dc791bff..4673b5731 100755 --- a/lib/puppet/provider/sshkey/parsed.rb +++ b/lib/puppet/provider/sshkey/parsed.rb @@ -19,11 +19,9 @@ Puppet::Type.type(:sshkey).provide(:parsed, record_line :parsed, :fields => %w{name type key}, :post_parse => proc { |hash| - if hash[:name] =~ /,/ - names = hash[:name].split(",") - hash[:name] = names.shift - hash[:alias] = names - end + names = hash[:name].split(",", -1) + hash[:name] = names.shift + hash[:alias] = names }, :pre_gen => proc { |hash| if hash[:alias] diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb index 34ca58c5a..1e02408b8 100644 --- a/lib/puppet/rails.rb +++ b/lib/puppet/rails.rb @@ -29,7 +29,9 @@ module Puppet::Rails ActiveRecord::Base.verify_active_connections! begin - ActiveRecord::Base.establish_connection(database_arguments()) + args = database_arguments + Puppet.info "Connecting to #{args[:adapter]} database: #{args[:database]}" + ActiveRecord::Base.establish_connection(args) rescue => detail if Puppet[:trace] puts detail.backtrace @@ -46,12 +48,13 @@ module Puppet::Rails case adapter when "sqlite3" - args[:dbfile] = Puppet[:dblocation] + args[:database] = Puppet[:dblocation] when "mysql", "postgresql" args[:host] = Puppet[:dbserver] unless Puppet[:dbserver].empty? args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].empty? args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].empty? args[:database] = Puppet[:dbname] + args[:reconnect]= true socket = Puppet[:dbsocket] args[:socket] = socket unless socket.empty? diff --git a/lib/puppet/rails/benchmark.rb b/lib/puppet/rails/benchmark.rb index c33b2fb1e..1fbd011e9 100644 --- a/lib/puppet/rails/benchmark.rb +++ b/lib/puppet/rails/benchmark.rb @@ -64,6 +64,6 @@ module Puppet::Rails::Benchmark data = {} end data[branch] = $benchmarks - File.open(file, "w") { |f| f.print YAML.dump(data) } + Puppet::Util.secure_open(file, "w") { |f| f.print YAML.dump(data) } end end diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb index d66fd2ed7..6b057dd2d 100644 --- a/lib/puppet/rails/host.rb +++ b/lib/puppet/rails/host.rb @@ -172,11 +172,6 @@ class Puppet::Rails::Host < ActiveRecord::Base end def find_resources_parameters_tags(resources) - # initialize all resource parameters - resources.each do |key,resource| - resource.params_hash = [] - end - find_resources_parameters(resources) find_resources_tags(resources) end @@ -294,7 +289,7 @@ class Puppet::Rails::Host < ActiveRecord::Base # assign each loaded parameters/tags to the resource it belongs to params.each do |param| - resources[param['resource_id']].add_param_to_hash(param) if resources.include?(param['resource_id']) + resources[param['resource_id']].add_param_to_list(param) if resources.include?(param['resource_id']) end end @@ -302,7 +297,7 @@ class Puppet::Rails::Host < ActiveRecord::Base tags = Puppet::Rails::ResourceTag.find_all_tags_from_host(self) tags.each do |tag| - resources[tag['resource_id']].add_tag_to_hash(tag) if resources.include?(tag['resource_id']) + resources[tag['resource_id']].add_tag_to_list(tag) if resources.include?(tag['resource_id']) end end diff --git a/lib/puppet/rails/resource.rb b/lib/puppet/rails/resource.rb index 984bdc05a..7b37a52bf 100644 --- a/lib/puppet/rails/resource.rb +++ b/lib/puppet/rails/resource.rb @@ -63,22 +63,28 @@ class Puppet::Rails::Resource < ActiveRecord::Base unserialize_value(self[:title]) end - def add_param_to_hash(param) - @params_hash ||= [] - @params_hash << param + def params_list + @params_list ||= [] end - def add_tag_to_hash(tag) - @tags_hash ||= [] - @tags_hash << tag + def params_list=(params) + @params_list = params end - def params_hash=(hash) - @params_hash = hash + def add_param_to_list(param) + params_list << param end - def tags_hash=(hash) - @tags_hash = hash + def tags_list + @tags_list ||= [] + end + + def tags_list=(tags) + @tags_list = tags + end + + def add_tag_to_list(tag) + tags_list << tag end def [](param) @@ -116,7 +122,7 @@ class Puppet::Rails::Resource < ActiveRecord::Base db_params = {} deletions = [] - @params_hash.each do |value| + params_list.each do |value| # First remove any parameters our catalog resource doesn't have at all. deletions << value['id'] and next unless catalog_params.include?(value['name']) @@ -142,7 +148,7 @@ class Puppet::Rails::Resource < ActiveRecord::Base # Lastly, add any new parameters. catalog_params.each do |name, value| - next if db_params.include?(name) + next if db_params.include?(name) && ! db_params[name].find{ |val| deletions.include?( val["id"] ) } values = value.is_a?(Array) ? value : [value] values.each do |v| @@ -156,7 +162,7 @@ class Puppet::Rails::Resource < ActiveRecord::Base in_db = [] deletions = [] resource_tags = resource.tags - @tags_hash.each do |tag| + tags_list.each do |tag| deletions << tag['id'] and next unless resource_tags.include?(tag['name']) in_db << tag['name'] end @@ -187,18 +193,6 @@ class Puppet::Rails::Resource < ActiveRecord::Base end end - def parameters - result = get_params_hash - result.each do |param, value| - if value.is_a?(Array) - result[param] = value.collect { |v| v['value'] } - else - result[param] = value.value - end - end - result - end - def ref(dummy_argument=:work_arround_for_ruby_GC_bug) "%s[%s]" % [self[:restype].split("::").collect { |s| s.capitalize }.join("::"), self.title.to_s] end diff --git a/lib/puppet/resource/reference.rb b/lib/puppet/resource/reference.rb index dce4449de..eddb2d96b 100644 --- a/lib/puppet/resource/reference.rb +++ b/lib/puppet/resource/reference.rb @@ -50,6 +50,10 @@ class Puppet::Resource::Reference # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] x = @type = value.to_s.split("::").collect { |s| s.capitalize }.join("::") end + + if @title + self.title = @title + end end # Convert to the reference format that TransObject uses. Yay backward diff --git a/lib/puppet/ssl/certificate.rb b/lib/puppet/ssl/certificate.rb index f9297f380..b6cba99a7 100644 --- a/lib/puppet/ssl/certificate.rb +++ b/lib/puppet/ssl/certificate.rb @@ -28,7 +28,8 @@ class Puppet::SSL::Certificate < Puppet::SSL::Base end def expiration - return nil unless content - return content.not_after + # Our expiration is either that of the cache or the content, whichever comes first + cache_expiration = @expiration + [(content and content.not_after), cache_expiration].compact.sort.first end end diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb index 98061c5e2..5de2c5a18 100644 --- a/lib/puppet/ssl/host.rb +++ b/lib/puppet/ssl/host.rb @@ -94,12 +94,7 @@ class Puppet::SSL::Host # Remove all traces of a given host def self.destroy(name) - [Key, Certificate, CertificateRequest].inject(false) do |result, klass| - if klass.destroy(name) - result = true - end - result - end + [Key, Certificate, CertificateRequest].collect { |part| part.destroy(name) }.any? { |x| x } end # Search for more than one host, optionally only specifying @@ -107,12 +102,7 @@ class Puppet::SSL::Host # This just allows our non-indirected class to have one of # indirection methods. def self.search(options = {}) - classes = [Key, CertificateRequest, Certificate] - if klass = options[:for] - classlist = [klass].flatten - else - classlist = [Key, CertificateRequest, Certificate] - end + classlist = [options[:for] || [Key, CertificateRequest, Certificate]].flatten # Collect the results from each class, flatten them, collect all of the names, make the name list unique, # then create a Host instance for each one. @@ -127,8 +117,7 @@ class Puppet::SSL::Host end def key - return nil unless @key ||= Key.find(name) - @key + @key ||= Key.find(name) end # This is the private key; we can create it from scratch @@ -146,8 +135,7 @@ class Puppet::SSL::Host end def certificate_request - return nil unless @certificate_request ||= CertificateRequest.find(name) - @certificate_request + @certificate_request ||= CertificateRequest.find(name) end # Our certificate request requires the key but that's all. @@ -166,26 +154,19 @@ class Puppet::SSL::Host end def certificate - unless @certificate - generate_key unless key - + @certificate ||= ( # get the CA cert first, since it's required for the normal cert # to be of any use. - return nil unless Certificate.find(CA_NAME) unless ca? - return nil unless @certificate = Certificate.find(name) - - unless certificate_matches_key? - raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key" + if not (key or generate_key) or not (ca? or Certificate.find("ca")) or not (cert = Certificate.find(name)) or cert.expired? + nil + elsif not cert.content.check_private_key(key.content) + Certificate.expire(name) + Puppet.warning "Retrieved certificate does not match private key" + nil + else + cert end - end - @certificate - end - - def certificate_matches_key? - return false unless key - return false unless certificate - - return certificate.content.check_private_key(key.content) + ) end # Generate all necessary parts of our ssl host. diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb index fb5c1b749..62cfad1f0 100755 --- a/lib/puppet/sslcertificates.rb +++ b/lib/puppet/sslcertificates.rb @@ -2,11 +2,7 @@ require 'puppet' -begin - require 'openssl' -rescue LoadError - raise Puppet::Error, "You must have the Ruby openssl library installed" -end +raise Puppet::Error, "You must have the Ruby openssl library installed" unless Puppet.features.openssl? module Puppet::SSLCertificates #def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey) diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index f6bcbc1f7..f9efc02f7 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -278,12 +278,13 @@ class Puppet::SSLCertificates::CA host = thing2name(csr) csrfile = host2csrfile(host) - if File.exists?(csrfile) - raise Puppet::Error, "Certificate request for %s already exists" % host - end + raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile) + Puppet.settings.writesub(:csrdir, csrfile) { |f| f.print csr.to_pem } - Puppet.settings.writesub(:csrdir, csrfile) do |f| - f.print csr.to_pem + certfile = host2certfile(host) + if File.exists?(certfile) + Puppet.notice "Removing previously signed certificate #{certfile} for #{host}" + Puppet::SSLCertificates::Inventory::rebuild end end diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index a4666a95f..2f5b5dfaf 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -31,7 +31,7 @@ module Puppet validate do |value| unless value =~ /^#{File::SEPARATOR}/ - raise Puppet::Error, "File paths must be fully qualified, not '%s'" % value + fail Puppet::Error,"File paths must be fully qualified, not '#{value}'" end end @@ -147,7 +147,7 @@ module Puppet resource[:recurselimit] = value true else - raise ArgumentError, "Invalid recurse value %s" % value.inspect + self.fail "Invalid recurse value #{value.inspect}" end end end @@ -163,7 +163,7 @@ module Puppet when Integer, Fixnum, Bignum; value when /^\d+$/; Integer(value) else - raise ArgumentError, "Invalid recurselimit value %s" % value.inspect + self.fail "Invalid recurselimit value #{value.inspect}" end end end diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index 36e6c4172..032c7c839 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -116,7 +116,7 @@ module Puppet return :absent unless stat = @resource.stat ftype = stat.ftype # Don't even try to manage the content on directories or links - return nil if ["directory","link"].include? ftype + return nil if ["directory","link"].include? ftype or checksum_type.nil? begin "{#{checksum_type}}" + send(checksum_type.to_s + "_file", resource[:path]).to_s diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb index f4236b4fc..c4b5fa188 100755 --- a/lib/puppet/type/file/ensure.rb +++ b/lib/puppet/type/file/ensure.rb @@ -80,13 +80,9 @@ module Puppet newvalue(:link) do - if property = @resource.property(:target) - property.retrieve - - return property.mklink - else - self.fail "Cannot create a symlink without a target" - end + fail "Cannot create a symlink without a target" unless property = resource.property(:target) + property.retrieve + property.mklink end # Symlinks. @@ -97,16 +93,9 @@ module Puppet munge do |value| value = super(value) - - # It doesn't make sense to try to manage links unless, well, - # we're managing links. - resource[:links] = :manage if value == :link - return value if value.is_a? Symbol - - @resource[:target] = value - resource[:links] = :manage - - return :link + value,resource[:target] = :link,value unless value.is_a? Symbol + resource[:links] = :manage if value == :link and resource[:links] != :follow + value end def change_to_s(currentvalue, newvalue) diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 39d9a20df..838dabb27 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -93,11 +93,7 @@ module Puppet end def checksum - if metadata - metadata.checksum - else - nil - end + metadata && metadata.checksum end # Look up (if necessary) and return remote content. @@ -119,16 +115,20 @@ module Puppet [:owner, :mode, :group, :checksum].each do |param| next if param == :owner and Puppet::Util::SUIDManager.uid != 0 next if param == :checksum and metadata.ftype == "directory" - unless value = @resource[param] and value != :absent - @resource[param] = metadata.send(param) + unless value = resource[param] and value != :absent + resource[param] = metadata.send(param) end end - # Set the 'ensure' value, unless we're trying to delete the file. - @resource[:ensure] = metadata.ftype unless @resource[:ensure] == :absent - - if metadata.ftype == "link" - @resource[:target] = metadata.destination + if resource[:ensure] == :absent + # We know all we need to + elsif metadata.ftype != "link" + resource[:ensure] = metadata.ftype + elsif @resource[:links] == :follow + resource[:ensure] = :present + else + resource[:ensure] = "link" + resource[:target] = metadata.destination end end diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index c8b5934fa..6c4e07b45 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -13,12 +13,11 @@ module Puppet end - newproperty(:alias) do - desc "Any alias the host might have. Multiple values must be - specified as an array. Note that this state has the same name - as one of the metaparams; using this state to set aliases will - make those aliases available in your Puppet scripts and also on - disk." + newproperty(:host_aliases) do + desc 'Any aliases the host might have. Multiple values must be + specified as an array. Note that this property is not the same as + the "alias" metaparam; use this property to add aliases to a host + on disk, and "alias" to aliases for use in your Puppet scripts.' def insync?(is) is == @should @@ -63,9 +62,7 @@ module Puppet end validate do |value| - if value =~ /\s/ - raise Puppet::Error, "Aliases cannot include whitespace" - end + raise Puppet::Error, "Host aliases cannot include whitespace" if value =~ /\s/ end end diff --git a/lib/puppet/type/port.rb b/lib/puppet/type/port.rb index fbb24425d..f186023be 100755 --- a/lib/puppet/type/port.rb +++ b/lib/puppet/type/port.rb @@ -57,11 +57,12 @@ # desc "The port description." # end # -# newproperty(:alias) do -# desc "Any aliases the port might have. Multiple values must be -# specified as an array. Note that this property has the same name as -# one of the metaparams; using this property to set aliases will make -# those aliases available in your Puppet scripts and also on disk." +# newproperty(:port_aliases) do +# desc 'Any aliases the port might have. Multiple values must be +# specified as an array. Note that this property is not the same as +# the "alias" metaparam; use this property to add aliases to a port +# in the services file, and "alias" to aliases for use in your Puppet +# scripts.' # # # We actually want to return the whole array here, not just the first # # value. diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 04fd9042c..d2ba82afd 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -115,20 +115,7 @@ module Puppet value = [value] unless value.is_a?(Array) # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] # It affects stand-alone blocks, too. - paths = value.flatten.collect { |p| x = p.split(":") }.flatten.find_all do |path| - if FileTest.directory?(path) - true - else - if FileTest.exist?(path) and ! FileTest.directory?(path) - @resource.debug "Search path %s is not a directory" % [path] - else - @resource.debug("Search path %s does not exist" % [path]) - end - false - end - end - - paths + paths = value.flatten.collect { |p| x = p.split(":") }.flatten end defaultto { provider.class.defpath if provider.class.respond_to?(:defpath) } diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb index c9e8f3d8b..c1407a6ee 100755 --- a/lib/puppet/type/sshkey.rb +++ b/lib/puppet/type/sshkey.rb @@ -21,11 +21,11 @@ module Puppet # FIXME This should automagically check for aliases to the hosts, just # to see if we can automatically glean any aliases. - newproperty(:alias) do - desc "Any alias the host might have. Multiple values must be - specified as an array. Note that this parameter has the same name - as one of the metaparams; using this parameter to set aliases will - make those aliases available in your Puppet scripts." + newproperty(:host_aliases) do + desc 'Any aliases the host might have. Multiple values must be + specified as an array. Note that this property is not the same as + the "alias" metaparam; use this property to add aliases to a host + on disk, and "alias" to aliases for use in your Puppet scripts.' attr_accessor :meta diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb index 39b9cd30a..51ed17bff 100644 --- a/lib/puppet/type/yumrepo.rb +++ b/lib/puppet/type/yumrepo.rb @@ -233,12 +233,14 @@ module Puppet end newparam(:name) do - desc "The name of the repository." + desc "The name of the repository. This corresponds to the + repositoryid parameter in yum.conf(5)." isnamevar end newproperty(:descr, :parent => Puppet::IniProperty) do desc "A human readable description of the repository. + This corresponds to the name parameter in yum.conf(5). #{ABSENT_DOC}" newvalue(:absent) { self.should = :absent } newvalue(/.*/) { } diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index 21573d1da..503c02b36 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -422,6 +422,28 @@ module Util end module_function :memory, :thinmark + + def secure_open(file,must_be_w,&block) + raise Puppet::DevError,"secure_open only works with mode 'w'" unless must_be_w == 'w' + raise Puppet::DevError,"secure_open only requires a block" unless block_given? + Puppet.warning "#{file} was a symlink to #{File.readlink(file)}" if File.symlink?(file) + if File.exists?(file) or File.symlink?(file) + wait = File.symlink?(file) ? 5.0 : 0.1 + File.delete(file) + sleep wait # give it a chance to reappear, just in case someone is actively trying something. + end + begin + File.open(file,File::CREAT|File::EXCL|File::TRUNC|File::WRONLY,&block) + rescue Errno::EEXIST + desc = File.symlink?(file) ? "symlink to #{File.readlink(file)}" : File.stat(file).ftype + puts "Warning: #{file} was apparently created by another process (as" + puts "a #{desc}) as soon as it was deleted by this process. Someone may be trying" + puts "to do something objectionable (such as tricking you into overwriting system" + puts "files if you are running as root)." + raise + end + end + module_function :secure_open end end diff --git a/lib/puppet/util/backups.rb b/lib/puppet/util/backups.rb index 4ab67771d..470d6d1bb 100644 --- a/lib/puppet/util/backups.rb +++ b/lib/puppet/util/backups.rb @@ -26,8 +26,9 @@ module Puppet::Util::Backups info "Recursively backing up to filebucket" Find.find(self[:path]) { |f| backup_file_with_filebucket(f) if File.file?(f) } when "file"; backup_file_with_filebucket(file) - when "link"; return true + when "link"; end + true end def perform_backup_with_backuplocal(fileobj, backup) diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb index 93c002fa9..8e8b8dd5c 100755 --- a/lib/puppet/util/filetype.rb +++ b/lib/puppet/util/filetype.rb @@ -251,4 +251,50 @@ class Puppet::Util::FileType output_file.delete end end + + # Support for AIX crontab with output different than suntab's crontab command. + newfiletype(:aixtab) do + # Read a specific @path's cron tab. + def read + begin + output = Puppet::Util.execute(%w{crontab -l}, :uid => @path) + if output.include?("You are not authorized to use the cron command") + raise Puppet::Error, "User %s not authorized to use cron" % @path + end + return output + rescue => detail + raise Puppet::Error, "Could not read crontab for %s: %s" % [@path, detail] + end + end + + # Remove a specific @path's cron tab. + def remove + begin + Puppet::Util.execute(%w{crontab -r}, :uid => @path) + rescue => detail + raise Puppet::Error, "Could not remove crontab for %s: %s" % [@path, detail] + end + end + + # Overwrite a specific @path's cron tab; must be passed the @path name + # and the text with which to create the cron tab. + def write(text) + require "tempfile" + output_file = Tempfile.new("puppet") + fh = output_file.open + fh.print text + fh.close + + # We have to chown the stupid file to the user. + File.chown(Puppet::Util.uid(@path), nil, output_file.path) + + begin + Puppet::Util.execute(["crontab", output_file.path], :uid => @path) + rescue => detail + raise Puppet::Error, "Could not write crontab for %s: %s" % [@path, detail] + ensure + output_file.delete + end + end + end end diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb index 4cdad700c..90d722900 100644 --- a/lib/puppet/util/log.rb +++ b/lib/puppet/util/log.rb @@ -511,11 +511,16 @@ class Puppet::Util::Log # If they pass a source in to us, we make sure it is a string, and # we retrieve any tags we can. def source=(source) - # We can't store the actual source, we just store the path. - # We can't just check for whether it responds to :path, because - # plenty of providers respond to that in their normal function. - if (source.is_a?(Puppet::Type) or source.is_a?(Puppet::Parameter)) and source.respond_to?(:path) - set_source_from_ral(source) + if source.respond_to?(:source_descriptors) + descriptors = source.source_descriptors + @source = descriptors[:path] + + descriptors[:tags].each { |t| tag(t) } + + [:file, :line, :version].each do |param| + next unless descriptors[param] + send(param.to_s + "=", descriptors[param]) + end else @source = source.to_s end @@ -528,19 +533,6 @@ class Puppet::Util::Log def to_s return @message end - - private - - def set_source_from_ral(source) - @source = source.path - - source.tags.each { |t| tag(t) } - - [:file, :line, :version].each do |param| - next unless value = source.send(param) - send(param.to_s + "=", value) - end - end end # This is for backward compatibility from when we changed the constant to Puppet::Util::Log diff --git a/lib/puppet/util/log_paths.rb b/lib/puppet/util/log_paths.rb index 1a6bafc45..46f6c481d 100644 --- a/lib/puppet/util/log_paths.rb +++ b/lib/puppet/util/log_paths.rb @@ -11,5 +11,19 @@ module Puppet::Util::LogPaths return "/" + @path.join("/") end + + def source_descriptors + descriptors = {} + + descriptors[:tags] = tags + + [:path, :file, :line, :version].each do |param| + next unless value = send(param) + descriptors[param] = value + end + + return descriptors + end + end diff --git a/lib/puppet/util/rdoc/generators/puppet_generator.rb b/lib/puppet/util/rdoc/generators/puppet_generator.rb index 1a4219ff4..31181f05a 100644 --- a/lib/puppet/util/rdoc/generators/puppet_generator.rb +++ b/lib/puppet/util/rdoc/generators/puppet_generator.rb @@ -1,5 +1,7 @@ require 'rdoc/generators/html_generator' require 'puppet/util/rdoc/code_objects' +require 'digest/md5' + module Generators # This module holds all the classes needed to generate the HTML documentation @@ -364,7 +366,7 @@ module Generators resources.each do |r| res << { "name" => CGI.escapeHTML(r.name), - "aref" => "#{path_prefix}\##{r.aref}" + "aref" => CGI.escape(path_prefix)+"\#"+CGI.escape(r.aref) } end res @@ -465,7 +467,7 @@ module Generators if path['<<'] path.gsub!(/<<\s*(\w*)/) { "from-#$1" } end - File.join(prefix, path.split("::")) + ".html" + File.join(prefix, path.split("::").collect { |p| Digest::MD5.hexdigest(p) }) + ".html" end def parent_name @@ -568,7 +570,7 @@ module Generators h_name = CGI.escapeHTML(name) @values["classmod"] = "Node" - @values["title"] = "#{@values['classmod']}: #{h_name}" + @values["title"] = CGI.escapeHTML("#{@values['classmod']}: #{h_name}") c = @context c = c.parent while c and !c.diagram diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb index 7526e6566..93542df28 100644 --- a/lib/puppet/util/reference.rb +++ b/lib/puppet/util/reference.rb @@ -36,7 +36,7 @@ class Puppet::Util::Reference def self.pdf(text) puts "creating pdf" - File.open("/tmp/puppetdoc.txt", "w") do |f| + Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| f.puts text end rst2latex = %x{which rst2latex} @@ -48,6 +48,9 @@ class Puppet::Util::Reference end rst2latex.chomp! cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex} + Puppet::Util.secure_open("/tmp/puppetdoc.tex","w") do |f| + # If we get here without an error, /tmp/puppetdoc.tex isn't a tricky cracker's symlink + end output = %x{#{cmd}} unless $? == 0 $stderr.puts "rst2latex failed" @@ -67,7 +70,7 @@ class Puppet::Util::Reference puts "Creating markdown for #{name} reference." dir = "/tmp/" + Puppet::PUPPETVERSION FileUtils.mkdir(dir) unless File.directory?(dir) - File.open(dir + "/" + "#{name}.rst", "w") do |f| + Puppet::Util.secure_open(dir + "/" + "#{name}.rst", "w") do |f| f.puts text end pandoc = %x{which pandoc} @@ -190,7 +193,7 @@ class Puppet::Util::Reference end def trac - File.open("/tmp/puppetdoc.txt", "w") do |f| + Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| f.puts self.to_trac end diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb index 3eff03996..3801ecdb0 100644 --- a/lib/puppet/util/selinux.rb +++ b/lib/puppet/util/selinux.rb @@ -7,11 +7,7 @@ # was abysmal. At this time (2008-11-02) the only distribution providing # these Ruby SELinux bindings which I am aware of is Fedora (in libselinux-ruby). -begin - require 'selinux' -rescue LoadError - # Nothing -end +Puppet.features.selinux? # check, but continue even if it's not require 'pathname' @@ -73,7 +69,7 @@ module Puppet::Util::SELinux if context.nil? or context == "unlabeled" return nil end - unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/ + unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-zA-Z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/ raise Puppet::Error, "Invalid context to parse: #{context}" end ret = { @@ -170,8 +166,8 @@ module Puppet::Util::SELinux # that's expected rescue return nil - ensure - mountfh.close + ensure + mountfh.close if mountfh end mntpoint = {} diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index f2c513b29..e6e13339b 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -64,20 +64,25 @@ class Puppet::Util::Settings # Remove all set values, potentially skipping cli values. def clear(exceptcli = false) @sync.synchronize do - @values.each do |name, values| - @values.delete(name) unless exceptcli and name == :cli - end + unsafe_clear(exceptcli) + end + end + + # Remove all set values, potentially skipping cli values. + def unsafe_clear(exceptcli = false) + @values.each do |name, values| + @values.delete(name) unless exceptcli and name == :cli + end - # Don't clear the 'used' in this case, since it's a config file reparse, - # and we want to retain this info. - unless exceptcli - @used = [] - end + # Don't clear the 'used' in this case, since it's a config file reparse, + # and we want to retain this info. + unless exceptcli + @used = [] + end - @cache.clear + @cache.clear - @name = nil - end + @name = nil end # This is mostly just used for testing. @@ -325,23 +330,25 @@ class Puppet::Util::Settings # and reparsed if necessary. set_filetimeout_timer() - # Retrieve the value now, so that we don't lose it in the 'clear' call. - file = self[:config] - - return unless FileTest.exist?(file) - - # We have to clear outside of the sync, because it's - # also using synchronize(). - clear(true) - @sync.synchronize do - unsafe_parse(file) + unsafe_parse(self[:config]) end end # Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly. def unsafe_parse(file) - parse_file(file).each do |area, values| + return unless FileTest.exist?(file) + begin + data = parse_file(file) + rescue => details + puts details.backtrace if Puppet[:trace] + Puppet.err "Could not parse #{file}: #{details}" + return + end + + unsafe_clear(true) + + data.each do |area, values| @values[area] = values end @@ -433,9 +440,7 @@ class Puppet::Util::Settings def reparse if file and file.changed? Puppet.notice "Reparsing %s" % file.file - @sync.synchronize do - parse - end + parse reuse() end end |