diff options
author | Luke Kanies <luke@reductivelabs.com> | 2009-12-21 16:23:44 -0800 |
---|---|---|
committer | Luke Kanies <luke@reductivelabs.com> | 2009-12-21 16:23:44 -0800 |
commit | 740fd6b301af89ab3aad89bca183ad1fcdc24ac4 (patch) | |
tree | f34617a229509c373d28d67abb453e7ae2136c39 /lib | |
parent | 8971d8beae2c409f9052f27c3f80ad3bdfff4de2 (diff) | |
parent | 4a06379f8770c164e42bcc410d874076c6e95f24 (diff) | |
download | puppet-740fd6b301af89ab3aad89bca183ad1fcdc24ac4.tar.gz puppet-740fd6b301af89ab3aad89bca183ad1fcdc24ac4.tar.xz puppet-740fd6b301af89ab3aad89bca183ad1fcdc24ac4.zip |
Merge branch '0.25.x'
Conflicts:
lib/puppet/agent.rb
lib/puppet/application/puppetd.rb
lib/puppet/parser/ast/leaf.rb
lib/puppet/util/rdoc/parser.rb
Diffstat (limited to 'lib')
67 files changed, 488 insertions, 268 deletions
diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb index 7bd97415f..09607372f 100644 --- a/lib/puppet/agent.rb +++ b/lib/puppet/agent.rb @@ -52,7 +52,7 @@ class Puppet::Agent with_client do |client| begin sync.synchronize { lock { result = client.run(*args) } } - rescue => detail + rescue Exception => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not run %s: %s" % [client_class, detail] end @@ -124,7 +124,7 @@ class Puppet::Agent def with_client begin @client = client_class.new - rescue => detail + rescue Exception => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not create instance of %s: %s" % [client_class, detail] return diff --git a/lib/puppet/application/puppetd.rb b/lib/puppet/application/puppetd.rb index c1f733183..9302cf105 100644 --- a/lib/puppet/application/puppetd.rb +++ b/lib/puppet/application/puppetd.rb @@ -137,7 +137,7 @@ Puppet::Application.new(:puppetd) do options[:verbose] = true options[:onetime] = true options[:detailed_exitcodes] = true - options[:waitforcert] = 0 + options[:waitforcert] = 0 unless @explicit_waitforcert end # Handle the logging settings. @@ -172,13 +172,6 @@ Puppet::Application.new(:puppetd) do exit(14) end - # FIXME: we should really figure out how to distribute the CRL - # to clients. In the meantime, we just disable CRL checking if - # the CRL file doesn't exist - unless File::exist?(Puppet[:cacrl]) - Puppet[:cacrl] = 'false' - end - handlers = nil if options[:serve].empty? diff --git a/lib/puppet/application/puppetdoc.rb b/lib/puppet/application/puppetdoc.rb index a5496ccee..0a4e0c3c3 100644 --- a/lib/puppet/application/puppetdoc.rb +++ b/lib/puppet/application/puppetdoc.rb @@ -66,8 +66,9 @@ Puppet::Application.new(:puppetdoc) do exit_code = 0 files = [] unless @manifest - files += Puppet[:modulepath].split(':').collect { |p| File.expand_path(p) } - files += Puppet[:manifestdir].split(':').collect { |p| File.expand_path(p) } + env = Puppet::Node::Environment.new + files += env.modulepath + files += env.manifestdir end files += ARGV Puppet.info "scanning: %s" % files.inspect @@ -191,7 +192,7 @@ Puppet::Application.new(:puppetdoc) do end end - def setup_rdoc + def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug) # consume the unknown options # and feed them as settings if @unknown_args.size > 0 diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index b63df0754..72aef91c0 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -93,7 +93,7 @@ class Puppet::Configurer duration = thinmark do result = catalog_class.find(name, fact_options.merge(:ignore_cache => true)) end - rescue => detail + rescue Exception => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not retrieve catalog from remote server: %s" % detail end @@ -123,6 +123,7 @@ class Puppet::Configurer # Convert a plain resource catalog into our full host catalog. def convert_catalog(result, duration) catalog = result.to_ral + catalog.finalize catalog.retrieval_duration = duration catalog.host_config = true catalog.write_class_file @@ -133,7 +134,12 @@ class Puppet::Configurer # This just passes any options on to the catalog, # which accepts :tags and :ignoreschedules. def run(options = {}) - prepare() + begin + prepare() + rescue Exception => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Failed to prepare catalog: %s" % detail + end if catalog = options[:catalog] options.delete(:catalog) diff --git a/lib/puppet/configurer/fact_handler.rb b/lib/puppet/configurer/fact_handler.rb index 43e9f35f4..cbb627680 100644 --- a/lib/puppet/configurer/fact_handler.rb +++ b/lib/puppet/configurer/fact_handler.rb @@ -11,14 +11,13 @@ module Puppet::Configurer::FactHandler end def find_facts - reload_facter() - # This works because puppetd configures Facts to use 'facter' for # finding facts and the 'rest' terminus for caching them. Thus, we'll # compile them and then "cache" them on the server. begin + reload_facter() Puppet::Node::Facts.find(Puppet[:certname]) - rescue => detail + rescue Exception => detail puts detail.backtrace if Puppet[:trace] raise Puppet::Error, "Could not retrieve local facts: %s" % detail end @@ -29,11 +28,11 @@ module Puppet::Configurer::FactHandler #format = facts.class.default_format # Hard-code yaml, because I couldn't get marshal to work. - format = :yaml + format = :b64_zlib_yaml text = facts.render(format) - return {:facts_format => format, :facts => CGI.escape(text)} + return {:facts_format => :b64_zlib_yaml, :facts => CGI.escape(text)} end # Retrieve facts from the central server. diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 590de83fd..050fcaa7e 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -527,6 +527,18 @@ module Puppet authority requests. It's a separate server because it cannot and does not need to horizontally scale."], :ca_port => ["$masterport", "The port to use for the certificate authority."], + :catalog_format => { + :default => "", + :desc => "(Deprecated for 'preferred_serialization_format') What format to + use to dump the catalog. Only supports 'marshal' and 'yaml'. Only + matters on the client, since it asks the server for a specific format.", + :hook => proc { |value| + if value + Puppet.warning "Setting 'catalog_format' is deprecated; use 'preferred_serialization_format' instead." + Puppet.settings[:preferred_serialization_format] = value + end + } + }, :preferred_serialization_format => ["pson", "The preferred means of serializing ruby instances for passing over the wire. This won't guarantee that all instances will be serialized using this method, since not all classes diff --git a/lib/puppet/external/pson/common.rb b/lib/puppet/external/pson/common.rb index 71b85ce54..87bce988b 100644 --- a/lib/puppet/external/pson/common.rb +++ b/lib/puppet/external/pson/common.rb @@ -48,7 +48,7 @@ module PSON case when c.empty? then p when p.const_defined?(c) then p.const_get(c) - else raise ArgumentError, "can't find const #{path}" + else raise ArgumentError, "can't find const for unregistered document type #{path}" end end end diff --git a/lib/puppet/external/pson/pure.rb b/lib/puppet/external/pson/pure.rb index 43f39b2a6..7bb18aa70 100644 --- a/lib/puppet/external/pson/pure.rb +++ b/lib/puppet/external/pson/pure.rb @@ -11,8 +11,8 @@ module PSON UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc: UTF8toUTF16.iconv('no bom') rescue LoadError - raise MissingUnicodeSupport, - "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions" + # We actually don't care + Puppet.warning "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions" rescue Errno::EINVAL, Iconv::InvalidEncoding # Iconv doesn't support big endian utf-16. Let's try to hack this manually # into the converters. diff --git a/lib/puppet/file_serving/base.rb b/lib/puppet/file_serving/base.rb index c82bb1992..a7ab9b66e 100644 --- a/lib/puppet/file_serving/base.rb +++ b/lib/puppet/file_serving/base.rb @@ -22,7 +22,7 @@ class Puppet::FileServing::Base end # Return the full path to our file. Fails if there's no path set. - def full_path + def full_path(dummy_argument=:work_arround_for_ruby_GC_bug) (if relative_path.nil? or relative_path == "" or relative_path == "." path else @@ -74,4 +74,19 @@ class Puppet::FileServing::Base end File.send(@stat_method, full_path()) end + + def to_pson_data_hash + { + # No 'document_type' since we don't send these bare + 'data' => { + 'path' => @path, + 'relative_path' => @relative_path, + 'links' => @links + }, + 'metadata' => { + 'api_version' => 1 + } + } + end + end diff --git a/lib/puppet/file_serving/configuration.rb b/lib/puppet/file_serving/configuration.rb index ac54a7a8a..9034caed1 100644 --- a/lib/puppet/file_serving/configuration.rb +++ b/lib/puppet/file_serving/configuration.rb @@ -96,9 +96,9 @@ class Puppet::FileServing::Configuration def mk_default_mounts @mounts["modules"] ||= Mount::Modules.new("modules") - @mounts["modules"].allow('*') + @mounts["modules"].allow('*') if @mounts["modules"].empty? @mounts["plugins"] ||= Mount::Plugins.new("plugins") - @mounts["plugins"].allow('*') + @mounts["plugins"].allow('*') if @mounts["plugins"].empty? end # Read the configuration file. diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb index 335dad497..275a090eb 100644 --- a/lib/puppet/file_serving/metadata.rb +++ b/lib/puppet/file_serving/metadata.rb @@ -71,8 +71,47 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::Base end end - def initialize(*args) - @checksum_type = "md5" - super + def initialize(path,data={}) + @owner = data.delete('owner') + @group = data.delete('group') + @mode = data.delete('mode') + if checksum = data.delete('checksum') + @checksum_type = checksum['type'] + @checksum = checksum['value'] + end + @checksum_type ||= "md5" + @ftype = data.delete('type') + @destination = data.delete('destination') + super(path,data) + end + + PSON.register_document_type('FileMetadata',self) + def to_pson_data_hash + { + 'document_type' => 'FileMetadata', + 'data' => super['data'].update({ + 'owner' => owner, + 'group' => group, + 'mode' => mode, + 'checksum' => { + 'type' => checksum_type, + 'value' => checksum + }, + 'type' => ftype, + 'destination' => destination, + }), + 'metadata' => { + 'api_version' => 1 + } + } + end + + def to_pson(*args) + to_pson_data_hash.to_pson(*args) + end + + def self.from_pson(data) + new(data.delete('path'), data) end + end diff --git a/lib/puppet/indirector/catalog/active_record.rb b/lib/puppet/indirector/catalog/active_record.rb index e3b56ece6..575ce72fb 100644 --- a/lib/puppet/indirector/catalog/active_record.rb +++ b/lib/puppet/indirector/catalog/active_record.rb @@ -30,6 +30,11 @@ class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord host.merge_resources(catalog.vertices) host.last_compile = Time.now + if node = Puppet::Node.find(catalog.name) + host.ip = node.parameters["ipaddress"] + host.environment = node.environment + end + host.save end end diff --git a/lib/puppet/indirector/facts/facter.rb b/lib/puppet/indirector/facts/facter.rb index 9df71fcac..6c6cbc6be 100644 --- a/lib/puppet/indirector/facts/facter.rb +++ b/lib/puppet/indirector/facts/facter.rb @@ -29,7 +29,7 @@ class Puppet::Node::Facts::Facter < Puppet::Indirector::Code Timeout::timeout(self.timeout) do load file end - rescue => detail + rescue Exception => detail Puppet.warning "Could not load fact file %s: %s" % [fqfile, detail] end end diff --git a/lib/puppet/indirector/ldap.rb b/lib/puppet/indirector/ldap.rb index 7485bd932..51bab0e6e 100644 --- a/lib/puppet/indirector/ldap.rb +++ b/lib/puppet/indirector/ldap.rb @@ -40,7 +40,7 @@ class Puppet::Indirector::Ldap < Puppet::Indirector::Terminus found = true yield entry end - rescue => detail + rescue Exception => detail if count == 0 # Try reconnecting to ldap if we get an exception and we haven't yet retried. count += 1 diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb index 4600a0dd5..dd8cebfac 100644 --- a/lib/puppet/indirector/node/ldap.rb +++ b/lib/puppet/indirector/node/ldap.rb @@ -73,7 +73,7 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap # The attributes that Puppet will stack as array over the full # hierarchy. - def stacked_attributes + def stacked_attributes(dummy_argument=:work_arround_for_ruby_GC_bug) Puppet[:ldapstackedattrs].split(/\s*,\s*/) end diff --git a/lib/puppet/network/authstore.rb b/lib/puppet/network/authstore.rb index ab31faec8..fb3d0145b 100755 --- a/lib/puppet/network/authstore.rb +++ b/lib/puppet/network/authstore.rb @@ -63,6 +63,11 @@ module Puppet @globalallow end + # does this auth store has any rules? + def empty? + @globalallow.nil? && @declarations.size == 0 + end + def initialize @globalallow = nil @declarations = [] diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb index 2ffbcef3d..e508a0283 100644 --- a/lib/puppet/network/format_handler.rb +++ b/lib/puppet/network/format_handler.rb @@ -129,6 +129,8 @@ module Puppet::Network::FormatHandler 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}')" end list end diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb index df6ef399c..010c23521 100644 --- a/lib/puppet/network/formats.rb +++ b/lib/puppet/network/formats.rb @@ -39,6 +39,56 @@ Puppet::Network::FormatHandler.create(:yaml, :mime => "text/yaml") do end end +# This is a "special" format which is used for the moment only when sending facts +# as REST GET parameters (see Puppet::Configurer::FactHandler). +# 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 intern(klass, text) + decode(text) + end + + def intern_multiple(klass, text) + decode(text) + end + + def render(instance) + yaml = instance.to_yaml + + yaml = encode(fixup(yaml)) unless yaml.nil? + yaml + end + + def render_multiple(instances) + yaml = instances.to_yaml + + yaml = encode(fixup(yaml)) unless yaml.nil? + yaml + end + + # Because of yaml issue in ruby 1.8.1... + def supported?(klass) + RUBY_VERSION != '1.8.1' + end + + # fixup invalid yaml as per: + # http://redmine.ruby-lang.org/issues/show/1331 + def fixup(yaml) + yaml.gsub!(/((?:&id\d+\s+)?!ruby\/object:.*?)\s*\?/) { "? #{$1}" } + yaml + end + + def encode(text) + Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION)) + end + + def decode(yaml) + YAML.load(Zlib::Inflate.inflate(Base64.decode64(yaml))) + end +end + Puppet::Network::FormatHandler.create(:marshal, :mime => "text/marshal") do # Marshal doesn't need the class name; it's serialized. diff --git a/lib/puppet/network/http/rack/httphandler.rb b/lib/puppet/network/http/rack/httphandler.rb index 31aa8371e..e14206850 100644 --- a/lib/puppet/network/http/rack/httphandler.rb +++ b/lib/puppet/network/http/rack/httphandler.rb @@ -12,23 +12,5 @@ class Puppet::Network::HTTP::RackHttpHandler raise NotImplementedError, "Your RackHttpHandler subclass is supposed to override service(request)" end - def ssl_client_header(request) - env_or_request_env(Puppet[:ssl_client_header], request) - end - - def ssl_client_verify_header(request) - env_or_request_env(Puppet[:ssl_client_verify_header], request) - end - - # Older Passenger versions passed all Environment vars in app(env), - # but since 2.2.3 they (some?) are really in ENV. - # Mongrel, etc. may also still use request.env. - def env_or_request_env(var, request) - if ENV.include?(var) - ENV[var] - else - request.env[var] - end - end end diff --git a/lib/puppet/network/http/rack/rest.rb b/lib/puppet/network/http/rack/rest.rb index bdca651d1..104751271 100644 --- a/lib/puppet/network/http/rack/rest.rb +++ b/lib/puppet/network/http/rack/rest.rb @@ -63,11 +63,11 @@ class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler result[:ip] = request.ip # if we find SSL info in the headers, use them to get a hostname. - # try this with :ssl_client_header. - # For Apache you need special configuration, see ext/rack/README. - if dn = ssl_client_header(request) and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/) + # try this with :ssl_client_header, which defaults should work for + # Apache with StdEnvVars. + if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/) result[:node] = dn_matchdata[1].to_str - result[:authenticated] = (ssl_client_verify_header(request) == 'SUCCESS') + result[:authenticated] = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS') else result[:node] = resolve_node(result) result[:authenticated] = false diff --git a/lib/puppet/network/http/rack/xmlrpc.rb b/lib/puppet/network/http/rack/xmlrpc.rb index 9d0f486bc..4fc9e82fc 100644 --- a/lib/puppet/network/http/rack/xmlrpc.rb +++ b/lib/puppet/network/http/rack/xmlrpc.rb @@ -43,11 +43,11 @@ class Puppet::Network::HTTP::RackXMLRPC < Puppet::Network::HTTP::RackHttpHandler ip = request.ip # if we find SSL info in the headers, use them to get a hostname. - # try this with :ssl_client_header. - # For Apache you need special configuration, see ext/rack/README. - if dn = ssl_client_header(request) and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/) + # try this with :ssl_client_header, which defaults should work for + # Apache with StdEnvVars. + if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/) node = dn_matchdata[1].to_str - authenticated = (ssl_client_verify_header(request) == 'SUCCESS') + authenticated = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS') else begin node = Resolv.getname(ip) diff --git a/lib/puppet/network/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb index a863d3a20..2dae9ccd8 100644 --- a/lib/puppet/network/http_server/webrick.rb +++ b/lib/puppet/network/http_server/webrick.rb @@ -21,13 +21,10 @@ module Puppet # with them, with flags appropriate for checking client # certificates for revocation def x509store - if Puppet[:cacrl] == 'false' + unless File.exist?(Puppet[:cacrl]) # No CRL, no store needed return nil end - unless File.exist?(Puppet[:cacrl]) - raise Puppet::Error, "Could not find CRL; set 'cacrl' to 'false' to disable CRL usage" - end crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl])) store = OpenSSL::X509::Store.new store.purpose = OpenSSL::X509::PURPOSE_ANY diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index 133f22c77..94f899200 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -55,15 +55,7 @@ class Puppet::Node::Environment if ENV["PUPPETLIB"] dirs = ENV["PUPPETLIB"].split(File::PATH_SEPARATOR) + dirs end - dirs.collect do |dir| - if dir !~ /^#{File::SEPARATOR}/ - File.join(Dir.getwd, dir) - else - dir - end - end.find_all do |p| - p =~ /^#{File::SEPARATOR}/ && FileTest.directory?(p) - end + validate_dirs(dirs) end # Return all modules from this environment. @@ -73,7 +65,26 @@ class Puppet::Node::Environment module_names.collect { |path| Puppet::Module.new(path, self) rescue nil }.compact end + # Cache the manifestdir, so that we aren't searching through + # all known directories all the time. + cached_attr(:manifestdir, :ttl => Puppet[:filetimeout]) do + validate_dirs(self[:manifestdir].split(File::PATH_SEPARATOR)) + end + def to_s name.to_s end + + def validate_dirs(dirs) + dirs.collect do |dir| + if dir !~ /^#{File::SEPARATOR}/ + File.join(Dir.getwd, dir) + else + dir + end + end.find_all do |p| + p =~ /^#{File::SEPARATOR}/ && FileTest.directory?(p) + end + end + end diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb index f4086671d..58a91477a 100644 --- a/lib/puppet/parameter.rb +++ b/lib/puppet/parameter.rb @@ -293,6 +293,13 @@ class Puppet::Parameter define_method(:unmunge, &block) end + # Optionaly convert the value to a canonical form so that it will + # be found in hashes, etc. Mostly useful for namevars. + def to_canonicalize(&block) + metaclass = (class << self; self; end) + metaclass.send(:define_method,:canonicalize,&block) + end + # Mark whether we're the namevar. def isnamevar @isnamevar = true @@ -464,10 +471,19 @@ class Puppet::Parameter value end + # Assume the value is already in canonical form by default + def self.canonicalize(value) + value + end + + def canonicalize(value) + self.class.canonicalize(value) + end + # A wrapper around our munging that makes sure we raise useful exceptions. def munge(value) begin - ret = unsafe_munge(value) + ret = unsafe_munge(canonicalize(value)) rescue Puppet::Error => detail Puppet.debug "Reraising %s" % detail raise diff --git a/lib/puppet/parser/ast/boolean_operator.rb b/lib/puppet/parser/ast/boolean_operator.rb index 160e0e69e..89725d73b 100644 --- a/lib/puppet/parser/ast/boolean_operator.rb +++ b/lib/puppet/parser/ast/boolean_operator.rb @@ -20,14 +20,14 @@ class Puppet::Parser::AST # return result # lazy evaluate right operand case @operator - when "and"; + when "and" if Puppet::Parser::Scope.true?(lval) rval = @rval.safeevaluate(scope) Puppet::Parser::Scope.true?(rval) else # false and false == false false end - when "or"; + when "or" if Puppet::Parser::Scope.true?(lval) true else diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index a7f81b4e7..a6763c419 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -102,18 +102,24 @@ class Puppet::Parser::Collector raise Puppet::DevError, "Cannot collect resources for a nil host" unless @scope.host host = Puppet::Rails::Host.find_by_name(@scope.host) - query = {:include => {:param_values => :param_name}} - search = "(exported=? AND restype=?)" values = [true, @type] search += " AND (%s)" % @equery if @equery - # this is a small performance optimisation - # the tag mechanism involves 3 more joins, which are - # needed only if we query on tags. - if search =~ /puppet_tags/ - query[:include][:puppet_tags] = :resource_tags + # note: + # we're not eagerly including any relations here because + # it can creates so much objects we'll throw out later. + # We used to eagerly include param_names/values but the way + # the search filter is built ruined those efforts and we + # were eagerly loading only the searched parameter and not + # the other ones. + query = {} + case search + when /puppet_tags/ + query = {:joins => {:resource_tags => :puppet_tag}} + when /param_name/ + query = {:joins => {:param_values => :param_name}} end # We're going to collect objects from rails, but we don't want any @@ -139,7 +145,7 @@ class Puppet::Parser::Collector # and such, we'll need to vary the conditions, but this works with no # attributes, anyway. time = Puppet::Util.thinmark do - Puppet::Rails::Resource.find(:all, @type, true, query).each do |obj| + Puppet::Rails::Resource.find(:all, query).each do |obj| if resource = exported_resource(obj) count += 1 resources << resource diff --git a/lib/puppet/parser/functions/generate.rb b/lib/puppet/parser/functions/generate.rb index 1be9016ed..18fe883b4 100644 --- a/lib/puppet/parser/functions/generate.rb +++ b/lib/puppet/parser/functions/generate.rb @@ -1,7 +1,7 @@ # Runs an external command and returns the results Puppet::Parser::Functions::newfunction(:generate, :type => :rvalue, - :doc => "Calls an external command and returns the results of the - command. Any arguments are passed to the external command as + :doc => "Calls an external command on the Puppet master and returns + the results of the command. Any arguments are passed to the external command as arguments. If the generator does not exit with return code of 0, the generator is considered to have failed and a parse error is thrown. Generators can only have file separators, alphanumerics, dashes, diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb index 3a2032d7f..d72169af5 100644 --- a/lib/puppet/parser/functions/require.rb +++ b/lib/puppet/parser/functions/require.rb @@ -27,7 +27,10 @@ Note that this function only works with clients 0.25 and later, and it will fail if used with earlier clients. ") do |vals| - send(:function_include, vals) + # Verify that the 'include' function is loaded + method = Puppet::Parser::Functions.function(:include) + + send(method, vals) if resource.metaparam_compatibility_mode? warning "The 'require' function is only compatible with clients at 0.25 and above; including class but not adding dependency" else diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index bdf539127..9435655a7 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -18,7 +18,7 @@ This functions returns a number:: Example:: if versioncmp('2.6-1', '2.4.5') > 0 { - notify('2.6-1 is > than 2.4.5') + notice('2.6-1 is > than 2.4.5') } ") do |args| diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index b8aaf2715..651ed4224 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -139,6 +139,12 @@ class Puppet::Parser::Resource if params = options[:params] options.delete(:params) params.each do |param| + # Don't set the same parameter twice + if @params[param.name] + self.fail Puppet::ParseError, "Duplicate parameter '%s' for on %s" % + [param.name, self.to_s] + end + set_parameter(param) end end diff --git a/lib/puppet/provider/package/dpkg.rb b/lib/puppet/provider/package/dpkg.rb index a4c398282..d6ec56ad4 100755 --- a/lib/puppet/provider/package/dpkg.rb +++ b/lib/puppet/provider/package/dpkg.rb @@ -83,7 +83,7 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package def latest output = dpkg_deb "--show", @resource[:source] matches = /^(\S+)\t(\S+)$/.match(output).captures - unless matches[0].match(@resource[:name]) + unless matches[0].match( Regexp.escape(@resource[:name]) ) warning "source doesn't contain named package, but %s" % matches[0] end matches[1] diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb index e92058040..bd03aad2e 100644 --- a/lib/puppet/provider/package/portage.rb +++ b/lib/puppet/provider/package/portage.rb @@ -1,7 +1,6 @@ require 'puppet/provider/package' Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Package do - include Puppet::Util::Execution desc "Provides packaging support for Gentoo's portage system." has_feature :versionable @@ -13,33 +12,32 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa defaultfor :operatingsystem => :gentoo def self.instances - result_format = /(\S+) (\S+) \[(?:([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\([^\)]+\))?(?:\[([^\]]+)\])?[ ]*)*\] \[(?:(?:\{M\})?(?:\([~*]+\))?([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\(([^\)]+)\))?(?:![mf])*(?:\[([^\]]+)\])?)?\] ([\S]*) (.*)/ - result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :slot, :overlay, :vendor, :description] + result_format = /(\S+) (\S+) \[(\S+)\] \[(\S+)\] (\S+) (.*)/ + result_fields = [:category, :name, :ensure, :version_available, :vendor, :description] - version_format = "<version>{!last} {}" - search_format = "<category> <name> [<installedversions:SPLITVERSIONS>] [<bestversion:SPLITVERSIONS>] <homepage> <description>" + version_format = "{last}<version>{}" + search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n" begin if !FileUtils.uptodate?("/var/cache/eix", %w(/usr/bin/eix /usr/portage/metadata/timestamp)) update_eix end + search_output = nil - withenv :SPLITVERSIONS => version_format do - search_output = eix "--nocolor", "--pure-packages", "--installed", "--format", search_format + Puppet::Util::Execution.withenv :LASTVERSION => version_format do + search_output = eix "--nocolor", "--pure-packages", "--stable", "--installed", "--format", search_format end packages = [] search_output.each do |search_result| - match = result_format.match( search_result ) + match = result_format.match(search_result) if match package = {} - result_fields.zip(match.captures) { |field, value| + result_fields.zip(match.captures) do |field, value| package[field] = value unless !value or value.empty? - } + end package[:provider] = :portage - package[:ensure] = package[:ensure].split.last - packages << new(package) end end @@ -74,36 +72,35 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa end def query - result_format = /(\S+) (\S+) \[(?:([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\([^\)]+\))?(?:\[([^\]]+)\])?[ ]*)*\] \[(?:(?:\{M\})?(?:\([~*]+\))?([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\(([^\)]+)\))?(?:![mf])*(?:\[([^\]]+)\])?)?\] ([\S]*) (.*)/ - result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :slot, :overlay, :vendor, :description] + result_format = /(\S+) (\S+) \[(\S*)\] \[(\S+)\] (\S+) (.*)/ + result_fields = [:category, :name, :ensure, :version_available, :vendor, :description] + + version_format = "{last}<version>{}" + search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n" search_field = package_name.count('/') > 0 ? "--category-name" : "--name" search_value = package_name - version_format = "<version>{!last} {}" - search_format = "<category> <name> [<installedversions:FORMAT_PVERSION>] [<bestversion:FORMAT_PVERSION>] <homepage> <description>" - begin if !FileUtils.uptodate?("/var/cache/eix", %w(/usr/bin/eix /usr/portage/metadata/timestamp)) update_eix end + search_output = nil - withenv :SPLITVERSIONS => version_format do - search_output = eix "--nocolor", "--pure-packages", "--format", search_format, "--exact", search_field, search_value + Puppet::Util::Execution.withenv :LASTVERSION => version_format do + search_output = eix "--nocolor", "--pure-packages", "--stable", "--format", search_format, "--exact", search_field, search_value end packages = [] search_output.each do |search_result| - match = result_format.match( search_result ) + match = result_format.match(search_result) - if( match ) + if match package = {} - result_fields.zip( match.captures ) { |field, value| package[field] = value unless !value or value.empty? } - if package[:ensure] - package[:ensure] = package[:ensure].split.last - else - package[:ensure] = :absent + result_fields.zip(match.captures) do |field, value| + package[field] = value unless !value or value.empty? end + package[:ensure] = package[:ensure] ? package[:ensure] : :absent packages << package end end @@ -126,4 +123,3 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa return self.query[:version_available] end end - diff --git a/lib/puppet/provider/package/rug.rb b/lib/puppet/provider/package/rug.rb index b68ec30c5..ca27cbbd3 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 =~ /#{@resource[:name]}\s*\|\s*([0-9\.\-]+)/ + if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([0-9\.\-]+)/ return $1 else # rug didn't find updates, pretend the current diff --git a/lib/puppet/provider/package/up2date.rb b/lib/puppet/provider/package/up2date.rb index d8a12652f..284bbaf42 100644 --- a/lib/puppet/provider/package/up2date.rb +++ b/lib/puppet/provider/package/up2date.rb @@ -25,7 +25,7 @@ Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm d #up2date can only get a list of *all* available packages? output = up2date "--showall" - if output =~ /^#{@resource[:name]}-(\d+.*)\.\w+/ + if output =~ /^#{Regexp.escape @resource[:name]}-(\d+.*)\.\w+/ return $1 else # up2date didn't find updates, pretend the current diff --git a/lib/puppet/provider/package/urpmi.rb b/lib/puppet/provider/package/urpmi.rb index a95835284..a79e96227 100644 --- a/lib/puppet/provider/package/urpmi.rb +++ b/lib/puppet/provider/package/urpmi.rb @@ -43,7 +43,7 @@ Puppet::Type.type(:package).provide :urpmi, :parent => :rpm, :source => :rpm do def latest output = urpmq "-S", @resource[:name] - if output =~ /^#{@resource[:name]}\s+:\s+.*\(\s+(\S+)\s+\)/ + if output =~ /^#{Regexp.escape @resource[:name]}\s+:\s+.*\(\s+(\S+)\s+\)/ return $1 else # urpmi didn't find updates, pretend the current diff --git a/lib/puppet/provider/service/daemontools.rb b/lib/puppet/provider/service/daemontools.rb index 2c6c6dbc7..3749f9c2c 100644 --- a/lib/puppet/provider/service/daemontools.rb +++ b/lib/puppet/provider/service/daemontools.rb @@ -45,7 +45,7 @@ Puppet::Type.type(:service).provide :daemontools, :parent => :base do attr_writer :defpath # Determine the daemon path. - def defpath + def defpath(dummy_argument=:work_arround_for_ruby_GC_bug) unless defined?(@defpath) and @defpath ["/var/lib/service", "/etc"].each do |path| if FileTest.exist?(path) diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb index 7ddbd288b..51fb7a22b 100755 --- a/lib/puppet/provider/service/debian.rb +++ b/lib/puppet/provider/service/debian.rb @@ -29,7 +29,7 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do def enabled? # TODO: Replace system() call when Puppet::Util.execute gives us a way # to determine exit status. http://projects.reductivelabs.com/issues/2538 - system("/usr/sbin/invoke-rc.d", "--query", @resource[:name], "start") + system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start") # 104 is the exit status when you query start an enabled service. # 106 is the exit status when the policy layer supplies a fallback action diff --git a/lib/puppet/provider/service/runit.rb b/lib/puppet/provider/service/runit.rb index b313fc79c..b8b444e34 100644 --- a/lib/puppet/provider/service/runit.rb +++ b/lib/puppet/provider/service/runit.rb @@ -38,7 +38,7 @@ Puppet::Type.type(:service).provide :runit, :parent => :daemontools do class << self # this is necessary to autodetect a valid resource # default path, since there is no standard for such directory. - def defpath + def defpath(dummy_argument=:work_arround_for_ruby_GC_bug) unless defined?(@defpath) and @defpath ["/etc/sv", "/var/lib/service"].each do |path| if FileTest.exist?(path) diff --git a/lib/puppet/provider/ssh_authorized_key/parsed.rb b/lib/puppet/provider/ssh_authorized_key/parsed.rb index 69eec9fde..b435c513c 100644 --- a/lib/puppet/provider/ssh_authorized_key/parsed.rb +++ b/lib/puppet/provider/ssh_authorized_key/parsed.rb @@ -14,8 +14,9 @@ Puppet::Type.type(:ssh_authorized_key).provide(:parsed, :fields => %w{options type key name}, :optional => %w{options}, :rts => /^\s+/, - :match => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+)(?: (.+))?$/, + :match => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+) ?(.*)$/, :post_parse => proc { |h| + h[:name] = "" if h[:name] == :absent h[:options] ||= [:absent] h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String }, diff --git a/lib/puppet/provider/zone/solaris.rb b/lib/puppet/provider/zone/solaris.rb index 778b9e0a1..b047f6984 100644 --- a/lib/puppet/provider/zone/solaris.rb +++ b/lib/puppet/provider/zone/solaris.rb @@ -64,7 +64,7 @@ Puppet::Type.type(:zone).provide(:solaris) do @property_hash.clear end - def install + def install(dummy_argument=:work_arround_for_ruby_GC_bug) if @resource[:install_args] zoneadm :install, @resource[:install_args].split(" ") else @@ -156,11 +156,16 @@ Puppet::Type.type(:zone).provide(:solaris) do def start # Check the sysidcfg stuff if cfg = @resource[:sysidcfg] - path = File.join(@resource[:path], "root", "etc", "sysidcfg") + zoneetc = File.join(@resource[:path], "root", "etc") + sysidcfg = File.join(zoneetc, "sysidcfg") - unless File.exists?(path) + # if the zone root isn't present "ready" the zone + # which makes zoneadmd mount the zone root + zoneadm :ready unless File.directory?(zoneetc) + + unless File.exists?(sysidcfg) begin - File.open(path, "w", 0600) do |f| + File.open(sysidcfg, "w", 0600) do |f| f.puts cfg end rescue => detail @@ -193,6 +198,10 @@ Puppet::Type.type(:zone).provide(:solaris) do main end + def ready + zoneadm :ready + end + def stop zoneadm :halt end diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb index c941d8f3d..34ca58c5a 100644 --- a/lib/puppet/rails.rb +++ b/lib/puppet/rails.rb @@ -22,6 +22,10 @@ module Puppet::Rails ActiveRecord::Base.logger.level = Logger::DEBUG end + if (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1) + ActiveRecord::Base.allow_concurrency = true + end + ActiveRecord::Base.verify_active_connections! begin diff --git a/lib/puppet/rails/resource.rb b/lib/puppet/rails/resource.rb index 12d321143..984bdc05a 100644 --- a/lib/puppet/rails/resource.rb +++ b/lib/puppet/rails/resource.rb @@ -199,7 +199,7 @@ class Puppet::Rails::Resource < ActiveRecord::Base result end - def ref + 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/catalog.rb b/lib/puppet/resource/catalog.rb index 5bf9a8368..f21c820a0 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -78,7 +78,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph @resource_table[ref] = resource # If the name and title differ, set up an alias - #self.alias(resource, resource.name) if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title + if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title self.alias(resource, resource.name) if resource.isomorphic? end @@ -430,12 +430,12 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph # the class. edge = Puppet::Relationship.from_pson(edge) if edge.is_a?(Hash) unless source = result.resource(edge.source) - raise ArgumentError, "Could not convert from pson: Could not find relationship source '%s'" % source + raise ArgumentError, "Could not convert from pson: Could not find relationship source #{edge.source.inspect}" end edge.source = source unless target = result.resource(edge.target) - raise ArgumentError, "Could not convert from pson: Could not find relationship target '%s'" % target + raise ArgumentError, "Could not convert from pson: Could not find relationship target #{edge.target.inspect}" end edge.target = target diff --git a/lib/puppet/resource/reference.rb b/lib/puppet/resource/reference.rb index c205f1038..dce4449de 100644 --- a/lib/puppet/resource/reference.rb +++ b/lib/puppet/resource/reference.rb @@ -20,24 +20,12 @@ class Puppet::Resource::Reference end def initialize(argtype, argtitle = nil) - if argtitle.nil? - if argtype.is_a?(Puppet::Type) - self.title = argtype.title - self.type = argtype.class.name - else - self.title = argtype - if self.title == argtype - raise ArgumentError, "No title provided and title '%s' is not a valid resource reference" % argtype.inspect - end - end - else - # This will set @type if it looks like a resource reference. - self.title = argtitle - - # Don't override whatever was done by setting the title. - self.type ||= argtype - end - + self.type,self.title = + if (argtitle || argtype) =~ /^([^\[\]]+)\[(.+)\]$/m then [ $1, $2 ] + elsif argtitle then [ argtype, argtitle ] + elsif argtype.is_a?(Puppet::Type) then [ argtype.class.name, argtype.title ] + else raise ArgumentError, "No title provided and #{argtype.inspect} is not a valid resource reference" + end @builtin_type = nil end @@ -47,15 +35,11 @@ class Puppet::Resource::Reference return nil end - # If the title has square brackets, treat it like a reference and - # set things appropriately; else, just set it. def title=(value) - if value =~ /^([^\[\]]+)\[(.+)\]$/ - self.type = $1 - @title = $2 - else - @title = value + if @type and klass = Puppet::Type.type(@type.to_s.downcase) + value = klass.canonicalize_ref(value) end + @title = value end # Canonize the type so we know it's always consistent. diff --git a/lib/puppet/ssl/certificate_revocation_list.rb b/lib/puppet/ssl/certificate_revocation_list.rb index f3c1a348a..c725bde48 100644 --- a/lib/puppet/ssl/certificate_revocation_list.rb +++ b/lib/puppet/ssl/certificate_revocation_list.rb @@ -46,8 +46,6 @@ class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base # The name doesn't actually matter; there's only one CRL. # We just need the name so our Indirector stuff all works more easily. def initialize(fakename) - raise Puppet::Error, "Cannot manage the CRL when :cacrl is set to false" if [false, "false"].include?(Puppet[:cacrl]) - @name = "crl" end diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb index d7993e70e..98061c5e2 100644 --- a/lib/puppet/ssl/host.rb +++ b/lib/puppet/ssl/host.rb @@ -235,12 +235,11 @@ class Puppet::SSL::Host # Attempt to retrieve a cert, if we don't already have one. def wait_for_cert(time) - return if certificate begin + return if certificate generate - return if certificate - rescue StandardError => detail + rescue Exception => detail Puppet.err "Could not request certificate: %s" % detail.to_s if time < 1 puts "Exiting; failed to retrieve certificate and watiforcert is disabled" diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index b0bcdb612..f6bcbc1f7 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -134,7 +134,7 @@ class Puppet::SSLCertificates::CA # List certificates waiting to be signed. This returns a list of hostnames, not actual # files -- the names can be converted to full paths with host2csrfile. - def list + def list(dummy_argument=:work_arround_for_ruby_GC_bug) return Dir.entries(Puppet[:csrdir]).find_all { |file| file =~ /\.pem$/ }.collect { |file| @@ -144,7 +144,7 @@ class Puppet::SSLCertificates::CA # List signed certificates. This returns a list of hostnames, not actual # files -- the names can be converted to full paths with host2csrfile. - def list_signed + def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug) return Dir.entries(Puppet[:signeddir]).find_all { |file| file =~ /\.pem$/ }.collect { |file| @@ -194,9 +194,6 @@ class Puppet::SSLCertificates::CA # Revoke the certificate with serial number SERIAL issued by this # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE) - if @config[:cacrl] == 'false' - raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'false'" - end time = Time.now revoked = OpenSSL::X509::Revoked.new revoked.serial = serial @@ -344,8 +341,6 @@ class Puppet::SSLCertificates::CA @crl = OpenSSL::X509::CRL.new( File.read(@config[:cacrl]) ) - elsif @config[:cacrl] == 'false' - @crl = nil else # Create new CRL @crl = OpenSSL::X509::CRL.new diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index d04856d39..e132b7238 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -2,6 +2,7 @@ # and performs them require 'puppet' +require 'puppet/util/tagging' module Puppet class Transaction @@ -18,6 +19,7 @@ class Transaction attr_reader :events include Puppet::Util + include Puppet::Util::Tagging # Add some additional times for reporting def addtimes(hash) @@ -353,6 +355,7 @@ class Transaction made = [made] unless made.is_a?(Array) made.uniq.find_all do |res| begin + res.tag(*resource.tags) @catalog.add_resource(res) do |r| r.finish make_parent_child_relationship(resource, [r]) @@ -601,26 +604,26 @@ class Transaction # The tags we should be checking. def tags unless defined? @tags - tags = Puppet[:tags] - if tags.nil? or tags == "" - @tags = [] - else - @tags = tags.split(/\s*,\s*/) - end + self.tags = Puppet[:tags] end - @tags + super end - def tags=(tags) - tags = [tags] unless tags.is_a?(Array) - @tags = tags + def handle_qualified_tags( qualified ) + # The default behavior of Puppet::Util::Tagging is + # to split qualified tags into parts. That would cause + # qualified tags to match too broadly here. + return end # Is this resource tagged appropriately? def missing_tags?(resource) - return false if self.ignore_tags? or tags.empty? - return true unless resource.tagged?(tags) + not appropriately_tagged?(resource) + end + + def appropriately_tagged?(resource) + self.ignore_tags? or tags.empty? or resource.tagged?(*tags) end # Are there any edges that target this resource? diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index ee87c2680..2f7b57afc 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -210,8 +210,8 @@ class Type end # Find the namevar - def self.namevar - unless defined? @namevar + def self.namevar_parameter + @namevar_parameter ||= ( params = @parameters.find_all { |param| param.isnamevar? or param.name == :name } @@ -219,12 +219,19 @@ class Type if params.length > 1 raise Puppet::DevError, "Found multiple namevars for %s" % self.name elsif params.length == 1 - @namevar = params[0].name + params.first else raise Puppet::DevError, "No namevar for %s" % self.name end - end - @namevar + ) + end + + def self.namevar + @namevar ||= namevar_parameter.name + end + + def self.canonicalize_ref(s) + namevar_parameter.canonicalize(s) end # Create a new parameter. Requires a block and a name, stores it in the diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index 1269f3872..1cdd56184 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -312,7 +312,7 @@ Puppet::Type.newtype(:cron) do the crontab, e.g., ``PATH=/bin:/usr/bin:/usr/sbin``." validate do |value| - unless value =~ /^\s*(\w+)\s*=\s*(.+)\s*$/ or value == :absent or value == "absent" + unless value =~ /^\s*(\w+)\s*=\s*(.*)\s*$/ or value == :absent or value == "absent" raise ArgumentError, "Invalid environment setting %s" % value.inspect end diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 34dc4454e..a4666a95f 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -46,6 +46,12 @@ module Puppet unmunge do |value| File.join( Puppet::FileCollection.collection.path(value[:index]), value[:name] ) end + + to_canonicalize do |s| + # Get rid of any duplicate slashes, and remove any trailing slashes unless + # the title is just a slash, in which case leave it. + s.gsub(/\/+/, "/").sub(/(.)\/$/,'\1') + end end newparam(:backup) do @@ -120,10 +126,10 @@ module Puppet munge do |value| newval = super(value) case newval - when :true, :inf: true - when :false: false - when :remote: :remote - when Integer, Fixnum, Bignum: + when :true, :inf; true + when :false; false + when :remote; :remote + when Integer, Fixnum, Bignum self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit" # recurse == 0 means no recursion @@ -131,7 +137,7 @@ module Puppet resource[:recurselimit] = value true - when /^\d+$/: + when /^\d+$/ self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit" value = Integer(value) @@ -154,8 +160,8 @@ module Puppet munge do |value| newval = super(value) case newval - when Integer, Fixnum, Bignum: value - when /^\d+$/: Integer(value) + when Integer, Fixnum, Bignum; value + when /^\d+$/; Integer(value) else raise ArgumentError, "Invalid recurselimit value %s" % value.inspect end @@ -399,11 +405,7 @@ module Puppet super - # Get rid of any duplicate slashes, and remove any trailing slashes. - @title = @title.gsub(/\/+/, "/") - - @title.sub!(/\/$/, "") unless @title == "/" - + @title = self.class.canonicalize_ref(@title) @stat = nil end @@ -494,26 +496,18 @@ module Puppet # not likely to have many actual conflicts, which is good, because # this is a pretty inefficient implementation. def remove_less_specific_files(files) - # We sort the paths so we can short-circuit some tests. - mypath = self[:path] - other_paths = catalog.vertices.find_all do |r| - r.is_a?(self.class) and r[:path][0..(mypath.length - 1)] == mypath - end.collect { |r| r[:path] }.sort { |a, b| a.length <=> b.length } - [self[:path]] + mypath = self[:path].split(File::Separator) + other_paths = catalog.vertices. + select { |r| r.is_a?(self.class) and r[:path] != self[:path] }. + collect { |r| r[:path].split(File::Separator) }. + select { |p| p[0,mypath.length] == mypath } return files if other_paths.empty? - remove = [] - files.each do |file| - path = file[:path] - other_paths.each do |p| - if path[0..(p.length - 1)] == p - remove << file - break - end - end - end - - files - remove + files.reject { |file| + path = file[:path].split(File::Separator) + other_paths.any? { |p| path[0,p.length] == p } + } end # A simple method for determining whether we should be recursing. diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index ff71a55ce..36e6c4172 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -96,7 +96,7 @@ module Puppet return true if ! @resource.replace? if self.should - return super + result = super elsif source = resource.parameter(:source) fail "Got a remote source with no checksum" unless source.checksum result = (is == source.checksum) @@ -114,14 +114,14 @@ module Puppet def retrieve return :absent unless stat = @resource.stat - + ftype = stat.ftype # Don't even try to manage the content on directories or links - return nil if stat.ftype == "directory" + return nil if ["directory","link"].include? ftype begin - return "{#{checksum_type}}" + send(checksum_type.to_s + "_file", resource[:path]).to_s + "{#{checksum_type}}" + send(checksum_type.to_s + "_file", resource[:path]).to_s rescue => detail - raise Puppet::Error, "Could not read %s: %s" % [@resource.title, detail] + raise Puppet::Error, "Could not read #{ftype} #{@resource.title}: #{detail}" end end diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb index fd9c27ae6..83034cbd9 100755 --- a/lib/puppet/type/file/mode.rb +++ b/lib/puppet/type/file/mode.rb @@ -5,7 +5,24 @@ module Puppet Puppet::Type.type(:file).newproperty(:mode) do require 'etc' desc "Mode the file should be. Currently relatively limited: - you must specify the exact mode the file should be." + you must specify the exact mode the file should be. + + Note that when you set the mode of a directory, Puppet always + sets the search/traverse (1) bit anywhere the read (4) bit is set. + This is almost always what you want: read allows you to list the + entries in a directory, and search/traverse allows you to access + (read/write/execute) those entries.) Because of this feature, you + can recursively make a directory and all of the files in it + world-readable by setting e.g.:: + + file { '/some/dir': + mode => 644, + recurse => true, + } + + In this case all of the files underneath ``/some/dir`` will have + mode 644, and all of the directories will have mode 755." + @event = :file_changed # Our modes are octal, so make sure they print correctly. Other diff --git a/lib/puppet/type/file/owner.rb b/lib/puppet/type/file/owner.rb index 1dff59cb3..e5ca06a86 100755 --- a/lib/puppet/type/file/owner.rb +++ b/lib/puppet/type/file/owner.rb @@ -28,10 +28,7 @@ module Puppet end def insync?(current) - unless Puppet::Util::SUIDManager.uid == 0 - warning "Cannot manage ownership unless running as root" - return true - end + return true unless should @should.each do |value| if value =~ /^\d+$/ @@ -44,6 +41,12 @@ module Puppet return true if uid == current end + + unless Puppet::Util::SUIDManager.uid == 0 + warnonce "Cannot manage ownership unless running as root" + return true + end + return false end diff --git a/lib/puppet/type/k5login.rb b/lib/puppet/type/k5login.rb index 20c03241f..5526fda21 100644 --- a/lib/puppet/type/k5login.rb +++ b/lib/puppet/type/k5login.rb @@ -56,7 +56,7 @@ Puppet::Type.newtype(:k5login) do end # Return the principals - def principals + def principals(dummy_argument=:work_arround_for_ruby_GC_bug) if File.exists?(@resource[:name]) File.readlines(@resource[:name]).collect { |line| line.chomp } else diff --git a/lib/puppet/type/maillist.rb b/lib/puppet/type/maillist.rb index e2430aa13..4ab9be252 100755 --- a/lib/puppet/type/maillist.rb +++ b/lib/puppet/type/maillist.rb @@ -42,13 +42,10 @@ module Puppet should = :absent end atype = Puppet::Type.type(:mailalias) - return provider.aliases.collect do |name, recipient| - if atype[name] - nil - else - malias = Puppet::Type.type(:mailalias).new(:name => name, :recipient => recipient, :ensure => should) - end - end.compact + + provider.aliases. + reject { |name,recipient| catalog.resource(:mailalias, name) }. + collect { |name,recipient| atype.new(:name => name, :recipient => recipient, :ensure => should) } end end end diff --git a/lib/puppet/type/resources.rb b/lib/puppet/type/resources.rb index 87bde972b..e1de55711 100644 --- a/lib/puppet/type/resources.rb +++ b/lib/puppet/type/resources.rb @@ -99,18 +99,18 @@ Puppet::Type.newtype(:resources) do def generate return [] unless self.purge? resource_type.instances. - reject { |r| managed? }. - reject { |r| catalog.resources.include? r.ref }. - select { |r| check(r) }. - select { |r| able_to_ensure_absent?(r) }. - each { |resource| - @parameters.each do |name, param| - resource[name] = param.value if param.metaparam? - end - - # Mark that we're purging, so transactions can handle relationships - # correctly - resource.purging + reject { |r| catalog.resources.include? r.ref }. + select { |r| check(r) }. + select { |r| r.class.validproperty?(:ensure) }. + select { |r| able_to_ensure_absent?(r) }. + each { |resource| + @parameters.each do |name, param| + resource[name] = param.value if param.metaparam? + end + + # Mark that we're purging, so transactions can handle relationships + # correctly + resource.purging } end diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb index f45171d90..b5ccb3fb1 100755 --- a/lib/puppet/type/tidy.rb +++ b/lib/puppet/type/tidy.rb @@ -247,8 +247,15 @@ Puppet::Type.newtype(:tidy) do def generate return [] unless stat(self[:path]) - if self[:recurse] - files = Puppet::FileServing::Fileset.new(self[:path], :recurse => self[:recurse]).files.collect do |f| + case self[:recurse] + when Integer, Fixnum, Bignum, /^\d+$/ + parameter = { :recurse => true, :recurselimit => self[:recurse] } + when true, :true, :inf + parameter = { :recurse => true } + end + + if parameter + files = Puppet::FileServing::Fileset.new(self[:path], parameter).files.collect do |f| f == "." ? self[:path] : File.join(self[:path], f) end else diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index 6f83c7ac5..21573d1da 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -55,10 +55,11 @@ module Util end unless Puppet::Util::SUIDManager.uid == user begin + Puppet::Util::SUIDManager.initgroups(user) Puppet::Util::SUIDManager.uid = user Puppet::Util::SUIDManager.euid = user - rescue - $stderr.puts "could not change to user %s" % user + rescue => detail + $stderr.puts "Could not change to user %s: %s" % [user, detail] exit(74) end end diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb index 25c4677fb..4cdad700c 100644 --- a/lib/puppet/util/log.rb +++ b/lib/puppet/util/log.rb @@ -282,9 +282,9 @@ class Puppet::Util::Log def colorize(level, str) case Puppet[:color] - when false; str - when true, :ansi, "ansi"; console_color(level, str) + when true, :ansi, "ansi", :yes, "yes"; console_color(level, str) when :html, "html"; html_color(level, str) + else str end end diff --git a/lib/puppet/util/methodhelper.rb b/lib/puppet/util/methodhelper.rb index 32fca1877..ecc9d537f 100644 --- a/lib/puppet/util/methodhelper.rb +++ b/lib/puppet/util/methodhelper.rb @@ -12,11 +12,10 @@ module Puppet::Util::MethodHelper def set_options(options) options.each do |param,value| method = param.to_s + "=" - begin + if respond_to? method self.send(method, value) - rescue NoMethodError - raise ArgumentError, "Invalid parameter %s to object class %s" % - [param,self.class.to_s] + else + raise ArgumentError, "Invalid parameter #{param} to object class #{self.class}" end end end diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb index e69de29bb..6e438bc73 100644 --- a/lib/puppet/util/monkey_patches.rb +++ b/lib/puppet/util/monkey_patches.rb @@ -0,0 +1,8 @@ +module RDoc + def self.caller(skip=nil) + in_gem_wrapper = false + Kernel.caller.reject { |call| + in_gem_wrapper ||= call =~ /#{Regexp.escape $0}:\d+:in `load'/ + } + end +end diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb index 3f04fbf52..4d0ac484f 100644 --- a/lib/puppet/util/rdoc/parser.rb +++ b/lib/puppet/util/rdoc/parser.rb @@ -200,9 +200,20 @@ class Parser if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil? begin - ref = resource_stmt_to_ref(stmt) - Puppet.debug "rdoc: found resource: %s[%s]" % [ref.type, ref.title] - container.add_resource(ref) + type = stmt.type.split("::").collect { |s| s.capitalize }.join("::") + title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s + Puppet.debug "rdoc: found resource: %s[%s]" % [type,title] + + param = [] + stmt.params.children.each do |p| + res = {} + res["name"] = p.param + res["value"] = "#{p.value.to_s}" unless p.value.nil? + + param << res + end + + container.add_resource(PuppetResource.new(type, title, stmt.doc, param)) rescue => detail raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}" end diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb index bdf44152b..3eff03996 100644 --- a/lib/puppet/util/selinux.rb +++ b/lib/puppet/util/selinux.rb @@ -13,6 +13,8 @@ rescue LoadError # Nothing end +require 'pathname' + module Puppet::Util::SELinux def selinux_support? @@ -91,7 +93,7 @@ module Puppet::Util::SELinux # I believe that the OS should always provide at least a fall-through context # though on any well-running system. def set_selinux_context(file, value, component = false) - unless selinux_support? + unless selinux_support? && selinux_label_support?(file) return nil end @@ -185,9 +187,19 @@ module Puppet::Util::SELinux return mntpoint end + def realpath(path) + path, rest = Pathname.new(path), [] + path, rest = path.dirname, [path.basename] + rest while ! path.exist? + File.join( path.realpath, *rest ) + end + + def parent_directory(path) + Pathname.new(path).dirname.to_s + end + # Internal helper function to return which type of filesystem a # given file path resides on - def find_fs(file) + def find_fs(path) unless mnts = read_mounts() return nil end @@ -198,13 +210,12 @@ module Puppet::Util::SELinux # Just in case: return something if you're down to "/" or "" # Remove the last slash and everything after it, # and repeat with that as the file for the next loop through. - ary = file.split('/') - while not ary.empty? do - path = ary.join('/') + path = realpath(path) + while not path.empty? do if mnts.has_key?(path) return mnts[path] end - ary.pop + path = parent_directory(path) end return mnts['/'] end diff --git a/lib/puppet/util/subclass_loader.rb b/lib/puppet/util/subclass_loader.rb index 8776e855c..b71ec7293 100644 --- a/lib/puppet/util/subclass_loader.rb +++ b/lib/puppet/util/subclass_loader.rb @@ -72,7 +72,7 @@ module Puppet::Util::SubclassLoader end # Retrieve or calculate a name. - def name + def name(dummy_argument=:work_arround_for_ruby_GC_bug) unless defined? @name @name = self.to_s.sub(/.+::/, '').intern end diff --git a/lib/puppet/util/suidmanager.rb b/lib/puppet/util/suidmanager.rb index c5df0d198..a0a9178bb 100644 --- a/lib/puppet/util/suidmanager.rb +++ b/lib/puppet/util/suidmanager.rb @@ -7,7 +7,7 @@ module Puppet::Util::SUIDManager extend Forwardable to_delegate_to_process = [ :euid=, :euid, :egid=, :egid, - :uid=, :uid, :gid=, :gid ] + :uid=, :uid, :gid=, :gid, :groups=, :groups ] to_delegate_to_process.each do |method| def_delegator Process, method @@ -26,13 +26,16 @@ module Puppet::Util::SUIDManager # We set both because some programs like to drop privs, i.e. bash. old_uid, old_gid = self.uid, self.gid old_euid, old_egid = self.euid, self.egid + old_groups = self.groups begin self.egid = convert_xid :gid, new_gid if new_gid + self.initgroups(convert_xid(:uid, new_uid)) if new_uid self.euid = convert_xid :uid, new_uid if new_uid yield ensure self.euid, self.egid = old_euid, old_egid + self.groups = old_groups end end module_function :asuser @@ -49,6 +52,13 @@ module Puppet::Util::SUIDManager end module_function :convert_xid + # Initialize supplementary groups + def initgroups(user) + require 'etc' + Process.initgroups(Etc.getpwuid(user).name, Process.gid) + end + + module_function :initgroups def run_and_capture(command, new_uid=nil, new_gid=nil) output = Puppet::Util.execute(command, :failonfail => false, :uid => new_uid, :gid => new_gid) diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb index f421d18d8..9ee90799f 100644 --- a/lib/puppet/util/tagging.rb +++ b/lib/puppet/util/tagging.rb @@ -16,13 +16,12 @@ module Puppet::Util::Tagging @tags << tag unless @tags.include?(tag) end - # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] - qualified.collect { |name| x = name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) } + handle_qualified_tags( qualified ) end # Are we tagged with the provided tag? - def tagged?(tag) - defined?(@tags) and @tags.include?(tag.to_s) + def tagged?(*tags) + not ( self.tags & tags.flatten.collect { |t| t.to_s } ).empty? end # Return a copy of the tag list, so someone can't ask for our tags @@ -32,8 +31,27 @@ module Puppet::Util::Tagging @tags.dup end + def tags=(tags) + @tags = [] + + return if tags.nil? or tags == "" + + if tags.is_a?(String) + tags = tags.strip.split(/\s*,\s*/) + end + + tags.each do |t| + tag(t) + end + end + private + def handle_qualified_tags( qualified ) + # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com] + qualified.collect { |name| x = name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) } + end + def valid_tag?(tag) tag =~ /^\w[-\w:.]*$/ end |