From 111a4b546dd1bcaab182d5c8ad694404c2c2f91c Mon Sep 17 00:00:00 2001 From: Ben Hughes Date: Fri, 1 Apr 2011 15:23:14 +1100 Subject: (#6857) Password disclosure when changing a user's password Make the should_to_s and is_to_s functions to return a form of 'redacted'. Rather than send the password hash to system logs in cases of failure or running in --noop mode, just state whether it's the new or old hash. We're already doing this with password changes that work, so this just brings it inline with those, albeit via a slightly different pair of methods. --- lib/puppet/type/user.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index f74e4266f..8d04fdc30 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -165,6 +165,14 @@ module Puppet return "changed password" end end + + def is_to_s( currentvalue ) + return '[old password hash redacted]' + end + def should_to_s( newvalue ) + return '[new password hash redacted]' + end + end newproperty(:password_min_age, :required_features => :manages_password_age) do -- cgit From 6996e0bbfb3559773e5fa0d133a7632dcb06b2d5 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Fri, 10 Jun 2011 14:03:47 -0700 Subject: Do not needlessly create multiple reports when creating a transaction Previously, the transaction would always create a report, which would some times be overridden with a new report. Now, the transaction optionally takes a report at initialization time, and only creates a report of its own if none was provided. Reviewed-by: Jacob Helwig --- lib/puppet/resource/catalog.rb | 3 +-- lib/puppet/transaction.rb | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index a8668d844..8d4918bbf 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -132,9 +132,8 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph expire Puppet::Util::Storage.load if host_config? - transaction = Puppet::Transaction.new(self) + transaction = Puppet::Transaction.new(self, options[:report]) - transaction.report = options[:report] if options[:report] transaction.tags = options[:tags] if options[:tags] transaction.ignoreschedules = true if options[:ignoreschedules] diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 48154ad6f..16f201ec5 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -15,7 +15,7 @@ class Puppet::Transaction attr_accessor :sorted_resources, :configurator # The report, once generated. - attr_accessor :report + attr_reader :report # Routes and stores any events and subscriptions. attr_reader :event_manager @@ -228,13 +228,10 @@ class Puppet::Transaction # this should only be called by a Puppet::Type::Component resource now # and it should only receive an array - def initialize(catalog) + def initialize(catalog, report = nil) @catalog = catalog - - @report = Report.new("apply", catalog.version) - + @report = report || Report.new("apply", catalog.version) @event_manager = Puppet::Transaction::EventManager.new(self) - @resource_harness = Puppet::Transaction::ResourceHarness.new(self) end -- cgit From 98ba4071f424932173b450d1a94a9ae39f33a6c7 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Fri, 10 Jun 2011 14:09:32 -0700 Subject: (#7127) Stop puppet if a prerun command fails Before this change there were several problems with pre and post run commands, logging, and sending of reports. 1. If a prerun command failed, puppet would attempt to apply the catalog. Now puppet will not apply the catalog, but it will run the postrun command and send the report (as it did before). 2. If a postrun command failed, puppet would not send the report. Sending the report is now in an outer ensure block from the postrun command, so postrun failures won't prevent the report from being sent. 3. Errors, e.g. Puppet.err, occuring during the prepare step, which which includes plugin/fact download and prerun commands were not appended to the report. Now the report log destination is registered as early as possible, and unregistered as late as possible to ensure Configurer errors that occur in the run method are included in the report. 4. The transaction was closing the Configurer's report destination out from underneath it. As a result, postrun errors were not included in the report. Paired-with: Nick Lewis Reviewed-by: Jacob Helwig --- lib/puppet/application/apply.rb | 8 ++- lib/puppet/configurer.rb | 107 ++++++++++++++++++++------------------- lib/puppet/resource/catalog.rb | 9 +++- lib/puppet/transaction.rb | 32 +++++------- lib/puppet/transaction/report.rb | 4 +- 5 files changed, 85 insertions(+), 75 deletions(-) (limited to 'lib') diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index 717935640..f2bbcb99b 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -130,7 +130,13 @@ class Puppet::Application::Apply < Puppet::Application configurer = Puppet::Configurer.new report = configurer.run(:skip_plugin_download => true, :catalog => catalog) - exit( options[:detailed_exitcodes] ? report.exit_status : 0 ) + if not report + exit(1) + elsif options[:detailed_exitcodes] then + exit(report.exit_status) + else + exit(0) + end rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts detail.message diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index 596d2dc53..7f39a3853 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -5,8 +5,6 @@ require 'puppet/network/http_pool' require 'puppet/util' class Puppet::Configurer - class CommandHookError < RuntimeError; end - require 'puppet/configurer/fact_handler' require 'puppet/configurer/plugin_handler' @@ -79,8 +77,6 @@ class Puppet::Configurer download_plugins unless options[:skip_plugin_download] download_fact_plugins unless options[:skip_plugin_download] - - execute_prerun_command end # Get the remote catalog, yo. Returns nil if no catalog can be found. @@ -109,67 +105,73 @@ class Puppet::Configurer catalog end - # The code that actually runs the catalog. - # This just passes any options on to the catalog, - # which accepts :tags and :ignoreschedules. - def run(options = {}) - begin - prepare(options) - rescue SystemExit,NoMemoryError - raise - rescue Exception => detail - puts detail.backtrace if Puppet[:trace] - Puppet.err "Failed to prepare catalog: #{detail}" + # Retrieve (optionally) and apply a catalog. If a catalog is passed in + # the options, then apply that one, otherwise retrieve it. + def retrieve_and_apply_catalog(options, fact_options) + unless catalog = (options.delete(:catalog) || retrieve_catalog(fact_options)) + Puppet.err "Could not retrieve catalog; skipping run" + return end - if Puppet::Resource::Catalog.indirection.terminus_class == :rest - # This is a bit complicated. We need the serialized and escaped facts, - # and we need to know which format they're encoded in. Thus, we - # get a hash with both of these pieces of information. - fact_options = facts_for_uploading + report = options[:report] + report.configuration_version = catalog.version + + benchmark(:notice, "Finished catalog run") do + catalog.apply(options) end + report.finalize_report + report + end + + # The code that actually runs the catalog. + # This just passes any options on to the catalog, + # which accepts :tags and :ignoreschedules. + def run(options = {}) options[:report] ||= Puppet::Transaction::Report.new("apply") report = options[:report] - Puppet::Util::Log.newdestination(report) - if catalog = options[:catalog] - options.delete(:catalog) - elsif ! catalog = retrieve_catalog(fact_options) - Puppet.err "Could not retrieve catalog; skipping run" - return - end + Puppet::Util::Log.newdestination(report) + begin + prepare(options) - report.configuration_version = catalog.version + if Puppet::Resource::Catalog.indirection.terminus_class == :rest + # This is a bit complicated. We need the serialized and escaped facts, + # and we need to know which format they're encoded in. Thus, we + # get a hash with both of these pieces of information. + fact_options = facts_for_uploading + end - transaction = nil + # set report host name now that we have the fact + report.host = Puppet[:node_name_value] - begin - benchmark(:notice, "Finished catalog run") do - transaction = catalog.apply(options) + begin + execute_prerun_command or return nil + retrieve_and_apply_catalog(options, fact_options) + rescue SystemExit,NoMemoryError + raise + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Failed to apply catalog: #{detail}" + return nil + ensure + execute_postrun_command or return nil end - report - rescue => detail - puts detail.backtrace if Puppet[:trace] - Puppet.err "Failed to apply catalog: #{detail}" - return + ensure + # Make sure we forget the retained module_directories of any autoload + # we might have used. + Thread.current[:env_module_directories] = nil + + # Now close all of our existing http connections, since there's no + # reason to leave them lying open. + Puppet::Network::HttpPool.clear_http_instances end ensure - # Make sure we forget the retained module_directories of any autoload - # we might have used. - Thread.current[:env_module_directories] = nil - - # Now close all of our existing http connections, since there's no - # reason to leave them lying open. - Puppet::Network::HttpPool.clear_http_instances - execute_postrun_command - Puppet::Util::Log.close(report) - send_report(report, transaction) + send_report(report) end - def send_report(report, trans) - report.finalize_report if trans + def send_report(report) puts report.summary if Puppet[:summarize] save_last_run_summary(report) report.save if Puppet[:report] @@ -207,12 +209,15 @@ class Puppet::Configurer end def execute_from_setting(setting) - return if (command = Puppet[setting]) == "" + return true if (command = Puppet[setting]) == "" begin Puppet::Util.execute([command]) + true rescue => detail - raise CommandHookError, "Could not run command from #{setting}: #{detail}" + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not run command from #{setting}: #{detail}" + false end end diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index 8d4918bbf..0a63ff172 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -132,7 +132,9 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph expire Puppet::Util::Storage.load if host_config? + transaction = Puppet::Transaction.new(self, options[:report]) + register_report = options[:report].nil? transaction.tags = options[:tags] if options[:tags] transaction.ignoreschedules = true if options[:ignoreschedules] @@ -140,7 +142,12 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph transaction.add_times :config_retrieval => self.retrieval_duration || 0 begin - transaction.evaluate + Puppet::Util::Log.newdestination(transaction.report) if register_report + begin + transaction.evaluate + ensure + Puppet::Util::Log.close(transaction.report) if register_report + end rescue Puppet::Error => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not apply complete catalog: #{detail}" diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 16f201ec5..d6d50d410 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -123,31 +123,23 @@ class Puppet::Transaction # collects all of the changes, executes them, and responds to any # necessary events. def evaluate - # Start logging. - Puppet::Util::Log.newdestination(@report) - prepare Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version - begin - @sorted_resources.each do |resource| - next if stop_processing? - if resource.is_a?(Puppet::Type::Component) - Puppet.warning "Somehow left a component in the relationship graph" - next - end - ret = nil - seconds = thinmark do - ret = eval_resource(resource) - end - - resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config? - ret + @sorted_resources.each do |resource| + next if stop_processing? + if resource.is_a?(Puppet::Type::Component) + Puppet.warning "Somehow left a component in the relationship graph" + next + end + ret = nil + seconds = thinmark do + ret = eval_resource(resource) end - ensure - # And then close the transaction log. - Puppet::Util::Log.close(@report) + + resource.info "valuated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config? + ret end Puppet.debug "Finishing transaction #{object_id}" diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb index 841c56968..77b9da833 100644 --- a/lib/puppet/transaction/report.rb +++ b/lib/puppet/transaction/report.rb @@ -10,8 +10,8 @@ class Puppet::Transaction::Report indirects :report, :terminus_class => :processor - attr_accessor :configuration_version - attr_reader :resource_statuses, :logs, :metrics, :host, :time, :kind, :status + attr_accessor :configuration_version, :host + attr_reader :resource_statuses, :logs, :metrics, :time, :kind, :status # This is necessary since Marshall doesn't know how to # dump hash with default proc (see below @records) -- cgit From de064693c3b6846718497bcfb42ef0b9e44ab90b Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Mon, 13 Jun 2011 17:19:52 -0700 Subject: (#5641) Help text: document that puppet doc takes modulepath, manifestdir, and environment options Puppet doc didn't have the usual subcommand caveat about configuration settings being valid command line options, nor did it explicitly call out the three settings that it actually cares about. I opted to do the latter, since the number of relevant settings was so small. Note that --environment is currently broken; this is filed as bug #7907. --- lib/puppet/application/doc.rb | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb index a88f27c78..65cd37da8 100644 --- a/lib/puppet/application/doc.rb +++ b/lib/puppet/application/doc.rb @@ -87,29 +87,40 @@ puppet doc will output a single manifest's documentation on stdout. OPTIONS ------- * --all: - Output the docs for all of the reference types. In 'rdoc' - modes, this also outputs documentation for all resources + Output the docs for all of the reference types. In 'rdoc' mode, this also + outputs documentation for all resources. * --help: Print this help message * --outputdir: - Specifies the directory where to output the rdoc - documentation in 'rdoc' mode. + Used only in 'rdoc' mode. The directory to which the rdoc output should + be written. * --mode: - Determine the output mode. Valid modes are 'text', 'pdf' and - 'rdoc'. The 'pdf' mode creates PDF formatted files in the - /tmp directory. The default mode is 'text'. In 'rdoc' mode - you must provide 'manifests-path' + Determine the output mode. Valid modes are 'text', 'pdf' and 'rdoc'. The 'pdf' + mode creates PDF formatted files in the /tmp directory. The default mode is + 'text'. In 'rdoc' mode you must provide 'manifests-path' * --reference: - Build a particular reference. Get a list of references by - running 'puppet doc --list'. + Build a particular reference. Get a list of references by running + 'puppet doc --list'. * --charset: - Used only in 'rdoc' mode. It sets the charset used in the - html files produced. + Used only in 'rdoc' mode. It sets the charset used in the html files produced. + +* --manifestdir: + Used only in 'rdoc' mode. The directory to scan for stand-alone manifests. + If not supplied, puppet doc will use the manifestdir from puppet.conf. + +* --modulepath: + Used only in 'rdoc' mode. The directory or directories to scan for modules. + If not supplied, puppet doc will use the modulepath from puppet.conf. + +* --environment: + Used only in 'rdoc' mode. The configuration environment from which + to read the modulepath and manifestdir settings, when reading said settings + from puppet.conf. Due to a known bug, this option is not currently effective. EXAMPLE -- cgit From 1d867b026dbfa38d44f042680acf708b42295882 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Tue, 14 Jun 2011 14:42:21 -0700 Subject: (#7224) Add a helper to Puppet::SSL::Certificate to retrieve alternate names Alternate names, if present, are specified in the subjectAltName extension of the certificate. The values are in the form: "DNS:alternate_name1, DNS:alternate_name2" This helper will retrieve the value of the subjectAltName extension and extract the alternate names, returning and empty list if the extension is absent. This will make it easier to access the entire list of possible names for a certificate, rather than just the common name; this is helpful for generating more detailed SSL error messages. Paired-With: Jacob Helwig --- lib/puppet/ssl/certificate.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/puppet/ssl/certificate.rb b/lib/puppet/ssl/certificate.rb index a0e600291..d57ac1a06 100644 --- a/lib/puppet/ssl/certificate.rb +++ b/lib/puppet/ssl/certificate.rb @@ -27,6 +27,12 @@ class Puppet::SSL::Certificate < Puppet::SSL::Base [:s] end + def alternate_names + alts = content.extensions.find{|ext| ext.oid == "subjectAltName"} + return [] unless alts + alts.value.split(/,\s+/).map{|al| al.sub(/^DNS:/,'')} + end + def expiration return nil unless content content.not_after -- cgit From 99330fa56d5f2a459fe560d7f7506d42d4a98d14 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Tue, 14 Jun 2011 15:31:13 -0700 Subject: (#7224) Reword 'hostname was not match' error message This error message is grammatically incorrect and unhelpful, so we replace it with a message that explains more correctly what went wrong and what was expected. This message happens when making an authenticated connection to a server where the certificate doesn't match its hostname. This happens in the REST terminuses, so we wrap their HTTP methods with a helper that will catch the appropriate SSLError and re-raise it with the better message stating the hostname used, and the list of hostnames that we were expecting it to be a part of. Unfortunately, because the certificate in question isn't available at error time, we have to use the Net::HTTP#verify_callback to capture it. Paired-With: Jacob Helwig Reviewed-By: Dominic Maraglia --- lib/puppet/indirector/rest.rb | 47 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb index 0d3997221..8018fe8e3 100644 --- a/lib/puppet/indirector/rest.rb +++ b/lib/puppet/indirector/rest.rb @@ -71,16 +71,49 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus Puppet::Network::HttpPool.http_instance(request.server || self.class.server, request.port || self.class.port) end + [:get, :post, :head, :delete, :put].each do |method| + define_method "http_#{method}" do |request, *args| + http_request(method, request, *args) + end + end + + def http_request(method, request, *args) + http_connection = network(request) + peer_certs = [] + + # We add the callback to collect the certificates for use in constructing + # the error message if the verification failed. This is necessary since we + # don't have direct access to the cert that we expected the connection to + # use otherwise. + # + http_connection.verify_callback = proc do |preverify_ok, ssl_context| + peer_certs << Puppet::SSL::Certificate.from_s(ssl_context.current_cert.to_pem) + preverify_ok + end + + http_connection.send(method, *args) + rescue OpenSSL::SSL::SSLError => error + if error.message.include? "hostname was not match" + raise unless cert = peer_certs.find { |c| c.name !~ /^puppet ca/i } + + valid_certnames = [cert.name, *cert.alternate_names].uniq + msg = valid_certnames.length > 1 ? "one of #{valid_certnames.join(', ')}" : valid_certnames.first + + raise Puppet::Error, "Server hostname '#{http_connection.address}' did not match server certificate; expected #{msg}" + else + raise + end + end + def find(request) uri, body = request_to_uri_and_body(request) uri_with_query_string = "#{uri}?#{body}" - http_connection = network(request) # WEBrick in Ruby 1.9.1 only supports up to 1024 character lines in an HTTP request # http://redmine.ruby-lang.org/issues/show/3991 response = if "GET #{uri_with_query_string} HTTP/1.1\r\n".length > 1024 - http_connection.post(uri, body, headers) + http_post(request, uri, body, headers) else - http_connection.get(uri_with_query_string, headers) + http_get(request, uri_with_query_string, headers) end result = deserialize response result.name = request.key if result.respond_to?(:name=) @@ -88,7 +121,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus end def head(request) - response = network(request).head(indirection2uri(request), headers) + response = http_head(request, indirection2uri(request), headers) case response.code when "404" return false @@ -101,7 +134,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus end def search(request) - unless result = deserialize(network(request).get(indirection2uri(request), headers), true) + unless result = deserialize(http_get(request, indirection2uri(request), headers), true) return [] end result @@ -109,12 +142,12 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus def destroy(request) raise ArgumentError, "DELETE does not accept options" unless request.options.empty? - deserialize network(request).delete(indirection2uri(request), headers) + deserialize http_delete(request, indirection2uri(request), headers) end def save(request) raise ArgumentError, "PUT does not accept options" unless request.options.empty? - deserialize network(request).put(indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime })) + deserialize http_put(request, indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime })) end private -- cgit From cba645c8b8a2c5293d50829c18cd753bcea34e81 Mon Sep 17 00:00:00 2001 From: Michael Stahnke Date: Tue, 14 Jun 2011 17:52:24 -0700 Subject: Bumping release in lib/puppet.rb and updating CHANGELOG. This is for release 2.6.9rc1. Signed-off-by: Michael Stahnke --- lib/puppet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet.rb b/lib/puppet.rb index f97d28642..b4650a245 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -24,7 +24,7 @@ require 'puppet/util/run_mode' # it's also a place to find top-level commands like 'debug' module Puppet - PUPPETVERSION = '2.6.8' + PUPPETVERSION = '2.6.9' def Puppet.version PUPPETVERSION -- cgit From 51608221da248e679326087303ecd0c649225d5b Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Fri, 17 Jun 2011 11:26:58 -0700 Subject: Clean up indentation, whitespace, and commented out code The mis-indented code, extra newlines, and commented out code were noticed while investigating the order dependent test failure fixed in 4365c8ba. Reviewed-by: Max Martin --- lib/puppet/parser/functions.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 5807c0bbe..e19ac127f 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -16,11 +16,9 @@ module Puppet::Parser::Functions def self.autoloader unless defined?(@autoloader) - - @autoloader = Puppet::Util::Autoload.new( + @autoloader = Puppet::Util::Autoload.new( self, "puppet/parser/functions", - :wrap => false ) end @@ -88,7 +86,6 @@ module Puppet::Parser::Functions ret = "" functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash| - #ret += "#{name}\n#{hash[:type]}\n" ret += "#{name}\n#{"-" * name.to_s.length}\n" if hash[:doc] ret += Puppet::Util::Docs.scrub(hash[:doc]) @@ -114,11 +111,9 @@ module Puppet::Parser::Functions end # Runs a newfunction to create a function for each of the log levels - Puppet::Util::Log.levels.each do |level| newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals| send(level, vals.join(" ")) end end - end -- cgit From a126aee16294b183d2c6068b46ad8e394d2d95f8 Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Tue, 21 Jun 2011 18:54:35 -0700 Subject: (#8032) Add containment to create_resources Without this change native resource types declared using the create_resources() function are not contained within the class scope of the function call. As a result, resources were "floating off" in the graph, disconnected from the rest of the relationship edges. With this change, the scope is preserved and native resources are contained by the class the function call is executed from. Reviewed-by: Dan Bode --- lib/puppet/parser/functions/create_resources.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb index 430f110b4..3b8bb3543 100644 --- a/lib/puppet/parser/functions/create_resources.rb +++ b/lib/puppet/parser/functions/create_resources.rb @@ -27,15 +27,16 @@ Takes two parameters: args[1].each do |title, params| raise ArgumentError, 'params should not contain title' if(params['title']) case type_of_resource - when :type - res = resource.hash2resource(params.merge(:title => title)) - catalog.add_resource(res) - when :define + # JJM The only difference between a type and a define is the call to instantiate_resource + # for a defined type. + when :type, :define p_resource = Puppet::Parser::Resource.new(type_name, title, :scope => self, :source => resource) params.merge(:name => title).each do |k,v| p_resource.set_parameter(k,v) end - resource.instantiate_resource(self, p_resource) + if type_of_resource == :define then + resource.instantiate_resource(self, p_resource) + end compiler.add_resource(self, p_resource) when :class klass = find_hostclass(title) -- cgit From a49d5b885a62aa9bd3a686d411739723a67c399c Mon Sep 17 00:00:00 2001 From: Michael Stahnke Date: Wed, 22 Jun 2011 14:57:03 -0700 Subject: (#8048) Gem install puppet no longer fails if rdoc enabled. Rdoc wouldn't parse lib/puppet/interface/options.rb The offending code has been removed. This was causing issues for users wishing to upgrade puppet, via gem or puppet. Signed-off-by: Michael Stahnke --- lib/puppet/interface/option.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/option.rb b/lib/puppet/interface/option.rb index b68bdeb12..3cd930acf 100644 --- a/lib/puppet/interface/option.rb +++ b/lib/puppet/interface/option.rb @@ -2,8 +2,6 @@ require 'puppet/interface' class Puppet::Interface::Option include Puppet::Interface::TinyDocs - # For compatibility, deprecated, and should go fairly soon... - ['', '='].each { |x| alias :"desc#{x}" :"description#{x}" } def initialize(parent, *declaration, &block) @parent = parent -- cgit From a23e39165a9509a9fa40370929a50fcd1709f4a2 Mon Sep 17 00:00:00 2001 From: Michael Stahnke Date: Wed, 22 Jun 2011 15:25:50 -0700 Subject: Updating for 2.7.1 release. Signed-off-by: Michael Stahnke --- lib/puppet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet.rb b/lib/puppet.rb index e20874b61..054948b7c 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -24,7 +24,7 @@ require 'puppet/util/run_mode' # it's also a place to find top-level commands like 'debug' module Puppet - PUPPETVERSION = '2.7.0' + PUPPETVERSION = '2.7.1' def Puppet.version PUPPETVERSION -- cgit From 7ad1b04244e0b6252d7fea7ca76e8bb708caa66a Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Fri, 17 Jun 2011 11:26:58 -0700 Subject: Clean up indentation, whitespace, and commented out code The mis-indented code, extra newlines, and commented out code were noticed while investigating the order dependent test failure fixed in 4365c8ba. Reviewed-by: Max Martin --- lib/puppet/parser/functions.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 5807c0bbe..e19ac127f 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -16,11 +16,9 @@ module Puppet::Parser::Functions def self.autoloader unless defined?(@autoloader) - - @autoloader = Puppet::Util::Autoload.new( + @autoloader = Puppet::Util::Autoload.new( self, "puppet/parser/functions", - :wrap => false ) end @@ -88,7 +86,6 @@ module Puppet::Parser::Functions ret = "" functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash| - #ret += "#{name}\n#{hash[:type]}\n" ret += "#{name}\n#{"-" * name.to_s.length}\n" if hash[:doc] ret += Puppet::Util::Docs.scrub(hash[:doc]) @@ -114,11 +111,9 @@ module Puppet::Parser::Functions end # Runs a newfunction to create a function for each of the log levels - Puppet::Util::Log.levels.each do |level| newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals| send(level, vals.join(" ")) end end - end -- cgit From f6882d6d5779883e931a6f558c06f631098011c5 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Wed, 29 Jun 2011 16:50:46 -0700 Subject: (#8147) Change default reporturl to match newer Dashboard versions Puppet's default reporturl setting was http://localhost:3000/reports, which has been deprecated in Puppet Dashboard in favor of http://localhost:3000/reports/upload. As Dashboard is the first-class destination for the http report processor, this commit changes Puppet's default to match what current versions of Dashboard expect. Reviewed-By: Jacob Helwig --- lib/puppet/defaults.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 07442d0e9..2247634b3 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -466,7 +466,7 @@ module Puppet :desc => "The directory in which to store reports received from the client. Each client gets a separate subdirectory."}, - :reporturl => ["http://localhost:3000/reports", + :reporturl => ["http://localhost:3000/reports/upload", "The URL used by the http reports processor to send reports"], :fileserverconfig => ["$confdir/fileserver.conf", "Where the fileserver configuration is stored."], :strict_hostname_checking => [false, "Whether to only search for the complete -- cgit From 726274322ceecf7adf6affe378b15af39abdf8f4 Mon Sep 17 00:00:00 2001 From: Michael Stahnke Date: Wed, 6 Jul 2011 14:14:37 -0700 Subject: Updated CHANGELOG and package building files for 2.7.2rc1 Signed-off-by: Michael Stahnke --- lib/puppet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet.rb b/lib/puppet.rb index c895da921..765c95cbf 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -24,7 +24,7 @@ require 'puppet/util/run_mode' # it's also a place to find top-level commands like 'debug' module Puppet - PUPPETVERSION = '2.7.1' + PUPPETVERSION = '2.7.2' def Puppet.version PUPPETVERSION -- cgit From faf8a5c05f50d98835a1db05b96146618f485a04 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Mon, 27 Jun 2011 13:33:31 -0700 Subject: (#7581) Provide more detailed error message when missing gems on Windows Running Puppet on Windows requires the sys-admin, win32-process & win32-dir gems. If any of these gems were missing, Puppet would fail with the message "Cannot determine basic system flavour". When trying to determine if we are on Windows, we now warn with the message "Cannot run on Microsoft Windows without the sys-admin, win32-process & win32-dir gems: #{err}", where err is the normal ruby load error message stating which gem could not be loaded. We also only warn if the POSIX feature is not present. Signed-off-by: James Turnbull Signed-off-by: Jacob Helwig Reviewed-by: Cameron Thomas --- lib/puppet/feature/base.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb index c983f5c12..9ed3deef5 100644 --- a/lib/puppet/feature/base.rb +++ b/lib/puppet/feature/base.rb @@ -43,7 +43,15 @@ Puppet.features.add(:posix) do end # We can use Microsoft Windows functions -Puppet.features.add(:microsoft_windows, :libs => ["sys/admin", "win32/process", "win32/dir"]) +Puppet.features.add(:microsoft_windows) do + begin + require 'sys/admin' + require 'win32/process' + require 'win32/dir' + rescue LoadError => err + warn "Cannot run on Microsoft Windows without the sys-admin, win32-process & win32-dir gems: #{err}" unless Puppet.features.posix? + end +end raise Puppet::Error,"Cannot determine basic system flavour" unless Puppet.features.posix? or Puppet.features.microsoft_windows? -- cgit From 3a70503b60f9fd51177df4e9267c5ac28b06fb2d Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Fri, 8 Jul 2011 11:25:03 -0700 Subject: Disable the master on Windows instead of blowing up with failed resources Running the Puppet master on Windows is not supported, so instead of failing with what can be cryptic error messages about failed resources we fail with an explicit error message about the master on Windows not being supported. This way a user isn't mistakenly given the impression that running a master on Windows will work, and they just have something mis-configured. Signed-off-by: Jacob Helwig Reviewed-by: Max Martin --- lib/puppet/application/master.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb index 18425c8bc..b4da770f0 100644 --- a/lib/puppet/application/master.rb +++ b/lib/puppet/application/master.rb @@ -206,6 +206,8 @@ Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License end def setup + raise Puppet::Error.new("Puppet master is not supported on Microsoft Windows") if Puppet.features.microsoft_windows? + # Handle the logging settings. if options[:debug] or options[:verbose] if options[:debug] -- cgit From 5826f7399325c784a5e8e33c7fabc46e202334a8 Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Tue, 21 Jun 2011 18:54:35 -0700 Subject: (#8032) Add containment to create_resources Without this change native resource types declared using the create_resources() function are not contained within the class scope of the function call. As a result, resources were "floating off" in the graph, disconnected from the rest of the relationship edges. With this change, the scope is preserved and native resources are contained by the class the function call is executed from. Reviewed-by: Dan Bode --- lib/puppet/parser/functions/create_resources.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb index 430f110b4..3b8bb3543 100644 --- a/lib/puppet/parser/functions/create_resources.rb +++ b/lib/puppet/parser/functions/create_resources.rb @@ -27,15 +27,16 @@ Takes two parameters: args[1].each do |title, params| raise ArgumentError, 'params should not contain title' if(params['title']) case type_of_resource - when :type - res = resource.hash2resource(params.merge(:title => title)) - catalog.add_resource(res) - when :define + # JJM The only difference between a type and a define is the call to instantiate_resource + # for a defined type. + when :type, :define p_resource = Puppet::Parser::Resource.new(type_name, title, :scope => self, :source => resource) params.merge(:name => title).each do |k,v| p_resource.set_parameter(k,v) end - resource.instantiate_resource(self, p_resource) + if type_of_resource == :define then + resource.instantiate_resource(self, p_resource) + end compiler.add_resource(self, p_resource) when :class klass = find_hostclass(title) -- cgit From ae3ef423c03b7ef27f975dadfb67bf77ca481503 Mon Sep 17 00:00:00 2001 From: Dan Bode Date: Wed, 6 Jul 2011 21:59:05 -0700 Subject: (#7699) - Help should only show options once puppet help was reprinting every option once for every alias that is had. This fix involves only storing the option.name in the @options instance var for both face and actions options. The @options_hash still maintains the list of options and aliases as its keys. Reviewed-by: Daniel Pittman (puppet-dev list) --- lib/puppet/interface/action.rb | 3 ++- lib/puppet/interface/option_manager.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index 185302b07..fe77a9658 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -227,8 +227,9 @@ WRAPPER end end + @options << option.name + option.aliases.each do |name| - @options << name @options_hash[name] = option end diff --git a/lib/puppet/interface/option_manager.rb b/lib/puppet/interface/option_manager.rb index 326a91d92..a1f300e8e 100644 --- a/lib/puppet/interface/option_manager.rb +++ b/lib/puppet/interface/option_manager.rb @@ -26,8 +26,9 @@ module Puppet::Interface::OptionManager end end + @options << option.name + option.aliases.each do |name| - @options << name @options_hash[name] = option end -- cgit From 1feccc3f2db29d112308a55032e7f93ca44b45aa Mon Sep 17 00:00:00 2001 From: Jeff McCune Date: Sun, 10 Jul 2011 13:51:31 -0700 Subject: Revert "Merge branch 'ticket/2.7.x/7699_fix_help_listing_options_twice' into 2.7.x" This reverts commit b7ee0258ab40478329c20177eda9b250f27ede18, reversing changes made to 8fe2e555ac3d57f5b6503ffe1a5466db8d6e190a. --- lib/puppet/interface/action.rb | 3 +-- lib/puppet/interface/option_manager.rb | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index fe77a9658..185302b07 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -227,9 +227,8 @@ WRAPPER end end - @options << option.name - option.aliases.each do |name| + @options << name @options_hash[name] = option end diff --git a/lib/puppet/interface/option_manager.rb b/lib/puppet/interface/option_manager.rb index a1f300e8e..326a91d92 100644 --- a/lib/puppet/interface/option_manager.rb +++ b/lib/puppet/interface/option_manager.rb @@ -26,9 +26,8 @@ module Puppet::Interface::OptionManager end end - @options << option.name - option.aliases.each do |name| + @options << name @options_hash[name] = option end -- cgit From d7d384ec0b7f28a8f0be20defcc2eebd0550aff0 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Mon, 11 Jul 2011 16:40:00 -0700 Subject: (#8356) Color defaults to false on Windows Windows consoles do not support ansi escape sequences for colorizing output. This commit changes the default setting of 'color' to false when the "microsoft_windows" feature is present. Paired-with: Jacob Helwig --- lib/puppet/defaults.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 07442d0e9..488b991d7 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -47,7 +47,7 @@ module Puppet exits. Comma-separate multiple values. For a list of all values, specify 'all'. This feature is only available in Puppet versions higher than 0.18.4."], - :color => ["ansi", "Whether to use colors when logging to the console. + :color => [(Puppet.features.microsoft_windows? ? "false" : "ansi"), "Whether to use colors when logging to the console. Valid values are `ansi` (equivalent to `true`), `html` (mostly used during testing with TextMate), and `false`, which produces no color."], -- cgit From b84bdbf31bbb0c5d5501bf6f32a9c0d0dc6acc94 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 12 Jul 2011 14:14:13 -0700 Subject: (#8356) Specify setting type for color Because we default the color setting to "false" on Microsoft Windows, the heuristics used to detect which type of setting we're using were getting confused, and mis-detected color as being a BooleanSetting rather than just a Setting. By specifying that color is a "Setting", we can skip the auto-detection, and avoid this problem entirely. Reviewed-by: Josh Cooper --- lib/puppet/defaults.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 488b991d7..d5e06c54a 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -47,10 +47,14 @@ module Puppet exits. Comma-separate multiple values. For a list of all values, specify 'all'. This feature is only available in Puppet versions higher than 0.18.4."], - :color => [(Puppet.features.microsoft_windows? ? "false" : "ansi"), "Whether to use colors when logging to the console. + :color => { + :default => (Puppet.features.microsoft_windows? ? "false" : "ansi"), + :type => :setting, + :desc => "Whether to use colors when logging to the console. Valid values are `ansi` (equivalent to `true`), `html` (mostly used during testing with TextMate), and `false`, which produces - no color."], + no color.", + }, :mkusers => [false, "Whether to create the necessary user and group that puppet agent will run as."], -- cgit From 45b3908e03734388b6c699ffbc4223f43b44a1d5 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 12 Jul 2011 15:47:21 -0700 Subject: (#4142) Fix module check not to fail when empty metadata.json Even though the puppet module tool was fixed to generate the required metadata attributes when it packages modules, it still creates an empty metadata.json file that gets checked into everybody's module repos. This causes the module to be unusable straight from a git clone since puppet was requiring all the required metadata attributes just with the presence of that file, and resulting in the error: No source module metadata provided for mcollective at This change makes it so that if you have an empty metadata.json (like the moduletool generates), puppet doesn't consider it to have metadata. If you have ANY metadata attributes in that file, it will still check to make sure all the required attributes are present. The work around up to this point has just been to delete the metadata.json file in git cloned modules. This also fixed the tests around this to actually run, since previously the tests depended on the a json feature, which we didn't have. We do, however, have a pson feature. Reviewed-by: Nick Lewis --- lib/puppet/module.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb index 059591ed8..00468df96 100644 --- a/lib/puppet/module.rb +++ b/lib/puppet/module.rb @@ -42,7 +42,10 @@ class Puppet::Module def has_metadata? return false unless metadata_file - FileTest.exist?(metadata_file) + return false unless FileTest.exist?(metadata_file) + + metadata = PSON.parse File.read(metadata_file) + return metadata.is_a?(Hash) && !metadata.keys.empty? end def initialize(name, environment = nil) -- cgit From b82f29c61aa84a12fc208487e4b049cb24702261 Mon Sep 17 00:00:00 2001 From: Dan Bode Date: Wed, 13 Jul 2011 15:38:32 -0700 Subject: (#7699) Help command should only list options once The problem was caused by the fact that the options method returns a list of options that treated the aliases as seperate options. The fix is to only maintain a list of options and not add all aliases to the options list. --- lib/puppet/interface/action.rb | 3 ++- lib/puppet/interface/option_manager.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index 185302b07..fe77a9658 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -227,8 +227,9 @@ WRAPPER end end + @options << option.name + option.aliases.each do |name| - @options << name @options_hash[name] = option end diff --git a/lib/puppet/interface/option_manager.rb b/lib/puppet/interface/option_manager.rb index 326a91d92..a1f300e8e 100644 --- a/lib/puppet/interface/option_manager.rb +++ b/lib/puppet/interface/option_manager.rb @@ -26,8 +26,9 @@ module Puppet::Interface::OptionManager end end + @options << option.name + option.aliases.each do |name| - @options << name @options_hash[name] = option end -- cgit From b268fb3d4cca79bdce0adc7da8b4d47f20769521 Mon Sep 17 00:00:00 2001 From: Max Martin Date: Wed, 6 Jul 2011 15:04:27 -0700 Subject: (#7144) Update Settings#writesub to convert mode to Fixnum Settings#writesub was not checking the type of the mode value passed in from the defaults, causing it to pass a string for mode to File.open, leading to failures. This commit resolves that issue. Paired-with: Matt Robinson --- lib/puppet/util.rb | 1 - lib/puppet/util/settings.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index d06f44808..34c6ec1ed 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -29,7 +29,6 @@ module Util end end - def self.synchronize_on(x,type) sync_object,users = 0,1 begin diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index f243b8691..4559e9af3 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -721,7 +721,7 @@ if @config.include?(:run_mode) end Puppet::Util::SUIDManager.asuser(*chown) do - mode = obj.mode || 0640 + mode = obj.mode ? obj.mode.to_i : 0640 args << "w" if args.empty? args << mode -- cgit From c4848d25f51372b9c8fc0e5259b7d58fd23ebb44 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Thu, 14 Jul 2011 14:13:31 -0700 Subject: maint: Fix documentation link for fileserver configuration The link to the filesever configuration page linked to the wiki, which links back to the docs site. Short circuiting that do just link to where you want to go. Reviewed-by: Nick Lewis --- lib/puppet/type/file/source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 76c646baf..49e885865 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -42,7 +42,7 @@ module Puppet on the local host, whereas `agent` will connect to the puppet server that it received the manifest from. - See the [fileserver configuration documentation](http://projects.puppetlabs.com/projects/puppet/wiki/File_Serving_Configuration) for information on how to configure + See the [fileserver configuration documentation](http://docs.puppetlabs.com/guides/file_serving.html) for information on how to configure and use file services within Puppet. If you specify multiple file sources for a file, then the first -- cgit From 2263be6f190e025d424358862b8f22b54a9a1529 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Thu, 14 Jul 2011 15:07:12 -0700 Subject: (#5108) Update service type docs for new hasstatus default Commit #7d35a479 changed the default value of the service type's hasstatus attribute. This was never documented. This commit documents the changed behavior, which will end up in the type references (and puppet describe) for version 2.7.2 and greater. (I intend to manually change the cached references for versions 2.7.[01].) --- lib/puppet/type/service.rb | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 5a2c69b87..3116f5f8e 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -8,17 +8,15 @@ module Puppet newtype(:service) do @doc = "Manage running services. Service support unfortunately varies - widely by platform --- some platforms have very little if any - concept of a running service, and some have a very codified and - powerful concept. Puppet's service support will generally be able - to do the right thing regardless (e.g., if there is no - 'status' command, then Puppet will look in the process table for a - command matching the service name), but the more information you - can provide, the better behaviour you will get. In particular, any - virtual services that don't have a predictable entry in the process table - (for example, `network` on Red Hat/CentOS systems) will manifest odd - behavior on restarts if you don't specify `hasstatus` or a `status` - command. + widely by platform --- some platforms have very little if any concept of a + running service, and some have a very codified and powerful concept. + Puppet's service support is usually capable of doing the right thing, but + the more information you can provide, the better behaviour you will get. + + Puppet 2.7 and newer expect init scripts to have a working status command. + If this isn't the case for any of your services' init scripts, you will + need to set `hasstatus` to false and possibly specify a custom status + command in the `status` attribute. Note that if a `service` receives an event from another resource, the service will get restarted. The actual command to restart the @@ -93,19 +91,17 @@ module Puppet end newparam(:hasstatus) do - desc "Declare the the service's init script has a - functional status command. Based on testing, it was found - that a large number of init scripts on different platforms do - not support any kind of status command; thus, you must specify - manually whether the service you are running has such a - command. Alternately, you can provide a specific command using the - `status` attribute. - - If you specify neither of these, then Puppet will look for the - service name in the process table. Be aware that 'virtual' init - scripts such as networking will respond poorly to refresh events - (via notify and subscribe relationships) if you don't override - this default behavior." + desc "Declare whether the service's init script has a functional status + command; defaults to `true`. This attribute's default value changed in + Puppet 2.7.0. + + If a service's init script does not support any kind of status command, + you should set `hasstatus` to false and either provide a specific + command using the `status` attribute or expect that Puppet will look for + the service name in the process table. Be aware that 'virtual' init + scripts (like 'network' under Red Hat systems) will respond poorly to + refresh events from other resources if you override the default behavior + without providing a status command." newvalues(:true, :false) -- cgit From 1cbe2ad70eddbf00ef2d3127a9ffcc9f220ee277 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 12 Apr 2011 21:08:57 -0700 Subject: (7080) Adding json support to Indirector Request We'll be using this to do RPC over mcollective. Reviewed-by: Daniel Pittman Reviewed-by: Nick Lewis Signed-off-by: Luke Kanies --- lib/puppet/indirector/request.rb | 51 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb index fd8d654dd..1918a3fb5 100644 --- a/lib/puppet/indirector/request.rb +++ b/lib/puppet/indirector/request.rb @@ -14,6 +14,51 @@ class Puppet::Indirector::Request OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment] + def self.from_pson(json) + raise ArgumentError, "No indirection name provided in json data" unless indirection_name = json['type'] + raise ArgumentError, "No method name provided in json data" unless method = json['method'] + raise ArgumentError, "No key provided in json data" unless key = json['key'] + + request = new(indirection_name, method, key, json['attributes']) + + if instance = json['instance'] + klass = Puppet::Indirector::Indirection.instance(request.indirection_name).model + if instance.is_a?(klass) + request.instance = instance + else + request.instance = klass.from_pson(instance) + end + end + + request + end + + def to_pson(*args) + result = { + 'document_type' => 'Puppet::Indirector::Request', + 'data' => { + 'type' => indirection_name, + 'method' => method, + 'key' => key + } + } + data = result['data'] + attributes = {} + OPTION_ATTRIBUTES.each do |key| + next unless value = send(key) + attributes[key] = value + end + + options.each do |opt, value| + attributes[opt] = value + end + + data['attributes'] = attributes unless attributes.empty? + data['instance'] = instance if instance + + result.to_pson(*args) + end + # Is this an authenticated request? def authenticated? # Double negative, so we just get true or false @@ -61,9 +106,11 @@ class Puppet::Indirector::Request self.indirection_name = indirection_name self.method = method + options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash } + set_attributes(options) - @options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash } + @options = options if key_or_instance.is_a?(String) || key_or_instance.is_a?(Symbol) key = key_or_instance @@ -153,7 +200,7 @@ class Puppet::Indirector::Request def set_attributes(options) OPTION_ATTRIBUTES.each do |attribute| - if options.include?(attribute) + if options.include?(attribute.to_sym) send(attribute.to_s + "=", options[attribute]) options.delete(attribute) end -- cgit From f4acb025f3a125d4c3c359fb6896ac20b36e06ab Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 12 Apr 2011 21:41:06 -0700 Subject: Adding json support to Puppet::Node Reviewed-by: Daniel Pittman Reviewed-by: Nick Lewis Signed-off-by: Luke Kanies --- lib/puppet/node.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'lib') diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index 5b0a98615..4bd4d1de6 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -20,6 +20,29 @@ class Puppet::Node attr_accessor :name, :classes, :source, :ipaddress, :parameters attr_reader :time + def self.from_pson(pson) + raise ArgumentError, "No name provided in pson data" unless name = pson['name'] + + node = new(name) + node.classes = pson['classes'] + node.parameters = pson['parameters'] + node.environment = pson['environment'] + node + end + + def to_pson(*args) + result = { + 'document_type' => "Puppet::Node", + 'data' => {} + } + result['data']['name'] = name + result['data']['classes'] = classes unless classes.empty? + result['data']['parameters'] = parameters unless parameters.empty? + result['data']['environment'] = environment.name + + result.to_pson(*args) + end + def environment return super if @environment -- cgit From 7e5ca648112a2703ba827f96f36fe2a5f7d1c751 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 7 Jul 2011 00:03:51 -0700 Subject: Making Fact json handling more resilient We were failing if any values were nil, and values were often nil, at least in testing. We now only include non-nil values, and we handle nil values just fine. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/node/facts.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb index 577b62b62..8d0a03474 100755 --- a/lib/puppet/node/facts.rb +++ b/lib/puppet/node/facts.rb @@ -61,18 +61,21 @@ class Puppet::Node::Facts def self.from_pson(data) result = new(data['name'], data['values']) - result.timestamp = Time.parse(data['timestamp']) - result.expiration = Time.parse(data['expiration']) + result.timestamp = Time.parse(data['timestamp']) if data['timestamp'] + result.expiration = Time.parse(data['expiration']) if data['expiration'] result end def to_pson(*args) - { - 'expiration' => expiration, + result = { 'name' => name, - 'timestamp' => timestamp, 'values' => strip_internal, - }.to_pson(*args) + } + + result['timestamp'] = timestamp if timestamp + result['expiration'] = expiration if expiration + + result.to_pson(*args) end # Add internal data to the facts for storage. -- cgit From 361220166525762634dd1886f84c9a928b28766b Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Fri, 15 Jul 2011 11:05:50 -0700 Subject: (#7080) Registering PSON document types We were originally using the actual constant for both Indirector Requests and Nodes, and this registers their document types as symbolic names. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/indirector/request.rb | 6 +++++- lib/puppet/node.rb | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb index 1918a3fb5..697d9df47 100644 --- a/lib/puppet/indirector/request.rb +++ b/lib/puppet/indirector/request.rb @@ -1,6 +1,7 @@ require 'cgi' require 'uri' require 'puppet/indirector' +require 'puppet/util/pson' # This class encapsulates all of the information you need to make an # Indirection call, and as a a result also handles REST calls. It's somewhat @@ -14,6 +15,9 @@ class Puppet::Indirector::Request OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment] + # Load json before trying to register. + Puppet.features.pson? and ::PSON.register_document_type('IndirectorRequest',self) + def self.from_pson(json) raise ArgumentError, "No indirection name provided in json data" unless indirection_name = json['type'] raise ArgumentError, "No method name provided in json data" unless method = json['method'] @@ -35,7 +39,7 @@ class Puppet::Indirector::Request def to_pson(*args) result = { - 'document_type' => 'Puppet::Indirector::Request', + 'document_type' => 'IndirectorRequest', 'data' => { 'type' => indirection_name, 'method' => method, diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index 4bd4d1de6..16a0e5c3d 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -19,6 +19,9 @@ class Puppet::Node attr_accessor :name, :classes, :source, :ipaddress, :parameters attr_reader :time + # + # Load json before trying to register. + Puppet.features.pson? and ::PSON.register_document_type('Node',self) def self.from_pson(pson) raise ArgumentError, "No name provided in pson data" unless name = pson['name'] @@ -32,7 +35,7 @@ class Puppet::Node def to_pson(*args) result = { - 'document_type' => "Puppet::Node", + 'document_type' => "Node", 'data' => {} } result['data']['name'] = name -- cgit From 0d2e0672eb516a1b1f2ced6b8c74bd2064dd205e Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 8 Jun 2011 07:03:54 -0700 Subject: Adding []/[]= support to Scope The interface to scope is much clearer this way anyway, but this is needed to integrate Puppet with Hiera[1]. It just provides hash-like behavior to Scope, which Hiera and others can now easily rely on. I also went through all of the code that used Scope#lookupvar and Scope#setvar and changed it if possible, and at the same time cleaned up a lot of tests that were unnecessarily stubbing (and thus making it difficult to tell if I had actually broken anything). 1 - https://github.com/ripienaar/hiera Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/ast/leaf.rb | 4 +-- lib/puppet/parser/compiler.rb | 4 +-- lib/puppet/parser/functions/extlookup.rb | 12 +++---- lib/puppet/parser/functions/fqdn_rand.rb | 2 +- lib/puppet/parser/resource.rb | 2 +- lib/puppet/parser/scope.rb | 57 +++++++++++++++++++------------- lib/puppet/parser/templatewrapper.rb | 4 +-- lib/puppet/resource/type.rb | 16 ++++----- 8 files changed, 56 insertions(+), 45 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index c8ebc9483..64a197492 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -124,7 +124,7 @@ class Puppet::Parser::AST # not include syntactical constructs, like '$' and '{}'). def evaluate(scope) parsewrap do - if (var = scope.lookupvar(@value, :file => file, :line => line)) == :undefined + if (var = scope[@value, {:file => file, :line => line}]) == :undefined var = :undef end var @@ -141,7 +141,7 @@ class Puppet::Parser::AST def evaluate_container(scope) container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable - (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container, :file => file, :line => line) + (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope[container, {:file => file, :line => line}] end def evaluate_key(scope) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index c1daade4c..f43a31285 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -450,7 +450,7 @@ class Puppet::Parser::Compiler # Set the node's parameters into the top-scope as variables. def set_node_parameters node.parameters.each do |param, value| - @topscope.setvar(param, value) + @topscope[param] = value end # These might be nil. @@ -473,7 +473,7 @@ class Puppet::Parser::Compiler Puppet.settings.each do |name, setting| next if name.to_s == "name" - scope.setvar name.to_s, environment[name] + scope[name.to_s] = environment[name] end end diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb index 5fbf26cec..9ffca59a7 100644 --- a/lib/puppet/parser/functions/extlookup.rb +++ b/lib/puppet/parser/functions/extlookup.rb @@ -91,9 +91,9 @@ This is for back compatibility to interpolate variables with %. % interpolation raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 - extlookup_datadir = undef_as('',lookupvar('::extlookup_datadir')) + extlookup_datadir = undef_as('',self['::extlookup_datadir']) - extlookup_precedence = undef_as([],lookupvar('::extlookup_precedence')).collect { |var| var.gsub(/%\{(.+?)\}/) { lookupvar("::#{$1}") } } + extlookup_precedence = undef_as([],self['::extlookup_precedence']).collect { |var| var.gsub(/%\{(.+?)\}/) { self["::#{$1}"] } } datafiles = Array.new @@ -121,9 +121,9 @@ This is for back compatibility to interpolate variables with %. % interpolation if result[0].length == 2 val = result[0][1].to_s - # parse %{}'s in the CSV into local variables using lookupvar() + # parse %{}'s in the CSV into local variables using the current scope while val =~ /%\{(.+?)\}/ - val.gsub!(/%\{#{$1}\}/, lookupvar($1)) + val.gsub!(/%\{#{$1}\}/, self[$1]) end desired = val @@ -134,9 +134,9 @@ This is for back compatibility to interpolate variables with %. % interpolation # Individual cells in a CSV result are a weird data type and throws # puppets yaml parsing, so just map it all to plain old strings desired = cells.map do |c| - # parse %{}'s in the CSV into local variables using lookupvar() + # parse %{}'s in the CSV into local variables using the current scope while c =~ /%\{(.+?)\}/ - c.gsub!(/%\{#{$1}\}/, lookupvar($1)) + c.gsub!(/%\{#{$1}\}/, self[$1]) end c.to_s diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb index 93ab98bcd..668802e73 100644 --- a/lib/puppet/parser/functions/fqdn_rand.rb +++ b/lib/puppet/parser/functions/fqdn_rand.rb @@ -7,6 +7,6 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc => $random_number_seed = fqdn_rand(30,30)") do |args| require 'digest/md5' max = args.shift - srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex) + srand(Digest::MD5.hexdigest([self['::fqdn'],args].join(':')).hex) rand(max).to_s end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 3bb5f8601..305ba81e8 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -258,7 +258,7 @@ class Puppet::Parser::Resource < Puppet::Resource def add_backward_compatible_relationship_param(name) # Skip metaparams for which we get no value. - return unless val = scope.lookupvar(name.to_s) and val != :undefined + return unless val = scope[name.to_s] and val != :undefined # The default case: just set the value set_parameter(name, val) and return unless @parameters[name] diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index ed67cd141..67dcb1cb0 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -48,6 +48,35 @@ class Puppet::Parser::Scope end end + def [](name, options = {}) + table = ephemeral?(name) ? @ephemeral.last : @symtable + # If the variable is qualified, then find the specified scope and look the variable up there instead. + if name =~ /^(.*)::(.+)$/ + begin + qualified_scope($1)[$2,options] + rescue RuntimeError => e + location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' + warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" + :undefined + end + elsif ephemeral_include?(name) or table.include?(name) + # We can't use "if table[name]" here because the value might be false + if options[:dynamic] and self != compiler.topscope + location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' + Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated. Support will be removed in Puppet 2.8. Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes." + end + table[name] + elsif parent + parent[name,options.merge(:dynamic => (dynamic || options[:dynamic]))] + else + :undefined + end + end + + def []=(var, value) + setvar(var, value) + end + # A demeterific shortcut to the catalog. def catalog compiler.catalog @@ -223,29 +252,9 @@ class Puppet::Parser::Scope private :qualified_scope # Look up a variable. The simplest value search we do. + # This method is effectively deprecated - use self[] instead. def lookupvar(name, options = {}) - table = ephemeral?(name) ? @ephemeral.last : @symtable - # If the variable is qualified, then find the specified scope and look the variable up there instead. - if name =~ /^(.*)::(.+)$/ - begin - qualified_scope($1).lookupvar($2,options) - rescue RuntimeError => e - location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' - warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" - :undefined - end - elsif ephemeral_include?(name) or table.include?(name) - # We can't use "if table[name]" here because the value might be false - if options[:dynamic] and self != compiler.topscope - location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' - Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated. Support will be removed in Puppet 2.8. Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes." - end - table[name] - elsif parent - parent.lookupvar(name,options.merge(:dynamic => (dynamic || options[:dynamic]))) - else - :undefined - end + self[name, options] end # Return a hash containing our variables and their values, optionally (and @@ -312,6 +321,8 @@ class Puppet::Parser::Scope # Set a variable in the current scope. This will override settings # in scopes above, but will not allow variables in the current scope # to be reassigned. + # It's preferred that you use self[]= instead of this; only use this + # when you need to set options. def setvar(name,value, options = {}) table = options[:ephemeral] ? @ephemeral.last : @symtable if table.include?(name) @@ -329,7 +340,7 @@ class Puppet::Parser::Scope table[name] = value else # append case # lookup the value in the scope if it exists and insert the var - table[name] = undef_as('',lookupvar(name)) + table[name] = undef_as('',self[name]) # concatenate if string, append if array, nothing for other types case value when Array diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 27d75bf92..83d18cc3f 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -25,7 +25,7 @@ class Puppet::Parser::TemplateWrapper # Should return true if a variable is defined, false if it is not def has_variable?(name) - scope.lookupvar(name.to_s, :file => file, :line => script_line) != :undefined + scope[name.to_s, {:file => file, :line => script_line}] != :undefined end # Allow templates to access the defined classes @@ -56,7 +56,7 @@ class Puppet::Parser::TemplateWrapper # the missing_method definition here until we declare the syntax finally # dead. def method_missing(name, *args) - value = scope.lookupvar(name.to_s,:file => file,:line => script_line) + value = scope[name.to_s, {:file => file,:line => script_line}] if value != :undefined return value else diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index f8d820b77..7b251e8c7 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -225,22 +225,22 @@ class Puppet::Resource::Type param = param.to_sym fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param) - exceptwrap { scope.setvar(param.to_s, value) } + exceptwrap { scope[param.to_s] = value } set[param] = true end if @type == :hostclass - scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title - scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name + scope["title"] = resource.title.to_s.downcase unless set.include? :title + scope["name"] = resource.name.to_s.downcase unless set.include? :name else - scope.setvar("title", resource.title ) unless set.include? :title - scope.setvar("name", resource.name ) unless set.include? :name + scope["title"] = resource.title unless set.include? :title + scope["name"] = resource.name unless set.include? :name end - scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name + scope["module_name"] = module_name if module_name and ! set.include? :module_name if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) - scope.setvar("caller_module_name", caller_name) + scope["caller_module_name"] = caller_name end scope.class_set(self.name,scope) if hostclass? or node? # Verify that all required arguments are either present or @@ -253,7 +253,7 @@ class Puppet::Resource::Type fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default value = default.safeevaluate(scope) - scope.setvar(param.to_s, value) + scope[param.to_s] = value # Set it in the resource, too, so the value makes it to the client. resource[param] = value -- cgit From 06e86e40bbb173fa24a7d1c2ecf4e54e1748de67 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 8 Jun 2011 18:55:10 -0700 Subject: Adding default environment to Scope We were previously not defaulting to an environment, which is silly given that there's always a default. It just made setup code harder. We now default to the default environment. This makes further testing involving scopes much easier. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/scope.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 67dcb1cb0..711655e44 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -82,10 +82,6 @@ class Puppet::Parser::Scope compiler.catalog end - def environment - compiler.environment - end - # Proxy accessors def host @compiler.node.name @@ -130,7 +126,7 @@ class Puppet::Parser::Scope # Remove this when rebasing def environment - compiler ? compiler.environment : nil + compiler ? compiler.environment : Puppet::Node::Environment.new end def find_hostclass(name) @@ -454,6 +450,6 @@ class Puppet::Parser::Scope def extend_with_functions_module extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root) - extend Puppet::Parser::Functions.environment_module(environment) + extend Puppet::Parser::Functions.environment_module(environment) if environment != Puppet::Node::Environment.root end end -- cgit From 9d608ea176224f38c6af349883065d9363dd1bb1 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 8 Jun 2011 22:36:25 -0700 Subject: Resource type defaults cleanup This is again done to make support for hiera easier. The way we were handling lookup of resource defaults was over-complicated. This does a decent bit of cleanup overall, but primarily focused on resource type defaults and how they get set during compilation. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/compiler.rb | 10 ++++++---- lib/puppet/resource.rb | 33 +++++++++++++++++++++++++++++++++ lib/puppet/resource/type.rb | 34 +++++++++++++++------------------- 3 files changed, 54 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index f43a31285..06cd80a1e 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -139,19 +139,21 @@ class Puppet::Parser::Compiler # evaluated later in the process. def evaluate_classes(classes, scope, lazy_evaluate = true) raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source - param_classes = nil + class_parameters = nil # if we are a param class, save the classes hash # and transform classes to be the keys if classes.class == Hash - param_classes = classes + class_parameters = classes classes = classes.keys end classes.each do |name| # If we can find the class, then make a resource that will evaluate it. if klass = scope.find_hostclass(name) - if param_classes - resource = klass.ensure_in_catalog(scope, param_classes[name] || {}) + # If parameters are passed, then attempt to create a duplicate resource + # so the appropriate error is thrown. + if class_parameters + resource = klass.ensure_in_catalog(scope, class_parameters[name] || {}) else next if scope.class_scope(klass) resource = klass.ensure_in_catalog(scope) diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index 59e387d00..217eb11c8 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -343,6 +343,26 @@ class Puppet::Resource [ type, title ].join('/') end + def set_default_parameters(scope) + return [] unless resource_type and resource_type.respond_to?(:arguments) + + result = [] + + resource_type.arguments.each do |param, default| + param = param.to_sym + next if parameters.include?(param) + unless is_a?(Puppet::Parser::Resource) + fail Puppet::DevError, "Cannot evaluate default parameters for #{self} - not a parser resource" + end + + next if default.nil? + + self[param] = default.safeevaluate(scope) + result << param + end + result + end + def to_resource self end @@ -351,6 +371,19 @@ class Puppet::Resource resource_type.valid_parameter?(name) end + # Verify that all required arguments are either present or + # have been provided with defaults. + # Must be called after 'set_default_parameters'. We can't join the methods + # because Type#set_parameters needs specifically ordered behavior. + def validate_complete + return unless resource_type and resource_type.respond_to?(:arguments) + + resource_type.arguments.each do |param, default| + param = param.to_sym + fail Puppet::ParseError, "Must pass #{param} to #{self}" unless parameters.include?(param) + end + end + def validate_parameter(name) raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name) end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index 7b251e8c7..ca6e8b53b 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -158,11 +158,7 @@ class Puppet::Resource::Type return resource end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) - if parameters - parameters.each do |k,v| - resource.set_parameter(k,v) - end - end + assign_parameter_values(parameters, resource) instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) resource @@ -188,6 +184,14 @@ class Puppet::Resource::Type @name.is_a?(Regexp) end + def assign_parameter_values(parameters, resource) + return unless parameters + scope = resource.scope || {} + arguments.merge(parameters).each do |name, default| + resource.set_parameter name, default + end + end + # MQR TODO: # # The change(s) introduced by the fix for #4270 are mostly silly & should be @@ -243,22 +247,14 @@ class Puppet::Resource::Type scope["caller_module_name"] = caller_name end scope.class_set(self.name,scope) if hostclass? or node? - # Verify that all required arguments are either present or - # have been provided with defaults. - arguments.each do |param, default| - param = param.to_sym - next if set.include?(param) - - # Even if 'default' is a false value, it's an AST value, so this works fine - fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default - value = default.safeevaluate(scope) - scope[param.to_s] = value - - # Set it in the resource, too, so the value makes it to the client. - resource[param] = value - end + # Evaluate the default parameters, now that all other variables are set + default_params = resource.set_default_parameters(scope) + default_params.each { |param| scope[param.to_s] = resource[param] } + # This has to come after the above parameters so that default values + # can use their values + resource.validate_complete end # Check whether a given argument is valid. -- cgit From b3c155430965280ab59b1dd70c020c6da3396fc9 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 16 Jun 2011 18:37:04 -0700 Subject: Adding Scope#include? method This is primarily for Hiera/DataLibrary support, but is a decent idea regardless. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/scope.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 711655e44..7b75ca86b 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -87,6 +87,10 @@ class Puppet::Parser::Scope @compiler.node.name end + def include?(name) + self[name] != :undefined + end + # Is the value true? This allows us to control the definition of truth # in one place. def self.true?(value) -- cgit From 3b2a24602d11d4ca2f7e761fb831f126ecf2de62 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 16 Jun 2011 18:41:19 -0700 Subject: Adding Scope#each method The capability was already there via to_hash, and Enumerable was already included, but this method was missing. Given the kind of hacking RI is doing, this seemed appropriate. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/scope.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 7b75ca86b..3a87f964b 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -82,6 +82,10 @@ class Puppet::Parser::Scope compiler.catalog end + def each + to_hash.each { |name, value| yield(name, value) } + end + # Proxy accessors def host @compiler.node.name -- cgit From 784d54c20bbc6272d408de1aee831a883298c5cd Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 11:57:53 -0700 Subject: Improving an error message Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/resource.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 305ba81e8..6b072bd90 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -173,7 +173,7 @@ class Puppet::Parser::Resource < Puppet::Resource :name => param, :value => value, :source => self.source ) elsif ! param.is_a?(Puppet::Parser::Resource::Param) - raise ArgumentError, "Must pass a parameter or all necessary values" + raise ArgumentError, "Received incomplete information - no value provided for parameter #{param}" end tag(*param.value) if param.name == :tag -- cgit From 79c8023d45d8c86f0f21cf6c4c27e0e5389c7528 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 11:58:34 -0700 Subject: Fixing default parameter value assignment The method for adding class resources to the catalog was only working in cases where the default values weren't AST objects. This commit fixes this, along with the tests that were failing and drew out the problem. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/resource/type.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index ca6e8b53b..8b154ce95 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -187,8 +187,12 @@ class Puppet::Resource::Type def assign_parameter_values(parameters, resource) return unless parameters scope = resource.scope || {} - arguments.merge(parameters).each do |name, default| - resource.set_parameter name, default + + # It'd be nice to assign default parameter values here, + # but we can't because they often rely on local variables + # created during set_resource_parameters. + parameters.each do |name, value| + resource.set_parameter name, value end end -- cgit From 2431bb3fc8fba238cb2cf1bb71f316c62ba384b7 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 12:03:40 -0700 Subject: Cleaning up indentation in versoncmp function Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/functions/versioncmp.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index 6091e0923..e4edb151e 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -1,10 +1,8 @@ require 'puppet/util/package' - Puppet::Parser::Functions::newfunction( - :versioncmp, :type => :rvalue, - - :doc => "Compares two versions +Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, +:doc => "Compares two versions Prototype: -- cgit From baf32de1dcda02f7da8b2926abee7f46d0d47fe1 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 12:25:54 -0700 Subject: Making the Functions module more resilient We were previously storing the module name with the environment instances as the key, which meant if the environment instances were removed, we could never get those modules again. Given that the functions weren't reloaded, this meant the functions were gone if we ever reloaded the environment. This makes the Functions environment module resilient across environment reloads, and it also makes the method work correctly when handed either an environment or a string. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/functions.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index e19ac127f..22eee70d7 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -29,8 +29,11 @@ module Puppet::Parser::Functions Environment = Puppet::Node::Environment def self.environment_module(env = nil) + if env and ! env.is_a?(Puppet::Node::Environment) + env = Puppet::Node::Environment.new(env) + end @modules.synchronize { - @modules[ env || Environment.current || Environment.root ] ||= Module.new + @modules[ (env || Environment.current || Environment.root).name ] ||= Module.new } end -- cgit From bdc0f8716ae8ccb2b2657dfab591afe9589d8902 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 16:32:03 -0700 Subject: Scope[] now returns nil for undefined variables Given that we have the 'include?' method, this feature is unnecessary, and it makes sense to convert to more ruby-like behavior. Any code that previously checked whether lookupvar (or the new []) returned :undefined should now check whether 'scope.include?(var)'. Thus, you can have the same behavior, but it takes a bit different code to get it. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/ast/leaf.rb | 7 ++++--- lib/puppet/parser/resource.rb | 3 ++- lib/puppet/parser/scope.rb | 12 ++++++++---- lib/puppet/parser/templatewrapper.rb | 7 +++---- 4 files changed, 17 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 64a197492..3efb52f63 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -124,10 +124,11 @@ class Puppet::Parser::AST # not include syntactical constructs, like '$' and '{}'). def evaluate(scope) parsewrap do - if (var = scope[@value, {:file => file, :line => line}]) == :undefined - var = :undef + if ! scope.include?(@value) + :undef + else + scope[@value, {:file => file, :line => line}] end - var end end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 6b072bd90..56887c357 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -258,7 +258,8 @@ class Puppet::Parser::Resource < Puppet::Resource def add_backward_compatible_relationship_param(name) # Skip metaparams for which we get no value. - return unless val = scope[name.to_s] and val != :undefined + return unless scope.include?(name.to_s) + val = scope[name.to_s] # The default case: just set the value set_parameter(name, val) and return unless @parameters[name] diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 3a87f964b..9d84c7e65 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -57,7 +57,7 @@ class Puppet::Parser::Scope rescue RuntimeError => e location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" - :undefined + nil end elsif ephemeral_include?(name) or table.include?(name) # We can't use "if table[name]" here because the value might be false @@ -69,7 +69,7 @@ class Puppet::Parser::Scope elsif parent parent[name,options.merge(:dynamic => (dynamic || options[:dynamic]))] else - :undefined + nil end end @@ -92,7 +92,7 @@ class Puppet::Parser::Scope end def include?(name) - self[name] != :undefined + ! self[name].nil? end # Is the value true? This allows us to control the definition of truth @@ -244,7 +244,11 @@ class Puppet::Parser::Scope end def undef_as(x,v) - (v == :undefined) ? x : (v == :undef) ? x : v + if v.nil? or v == :undef + x + else + v + end end def qualified_scope(classname) diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 83d18cc3f..9336e704d 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -25,7 +25,7 @@ class Puppet::Parser::TemplateWrapper # Should return true if a variable is defined, false if it is not def has_variable?(name) - scope[name.to_s, {:file => file, :line => script_line}] != :undefined + scope.include?(name.to_s) end # Allow templates to access the defined classes @@ -56,9 +56,8 @@ class Puppet::Parser::TemplateWrapper # the missing_method definition here until we declare the syntax finally # dead. def method_missing(name, *args) - value = scope[name.to_s, {:file => file,:line => script_line}] - if value != :undefined - return value + if scope.include?(name.to_s) + return scope[name.to_s, {:file => file,:line => script_line}] else # Just throw an error immediately, instead of searching for # other missingmethod things or whatever. -- cgit From d02000bf0060045eb27649ce2b433dcac34a7827 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Fri, 15 Jul 2011 10:52:37 -0700 Subject: (#8401) Document that --detailed-exitcodes is a bitmask The agent/apply/device man pages mentioned the 2 and 4 exit codes, but didn't mention that they can combine to make 6 if there are both changes and failures. This commit adds the missing information to all three man pages. Reviewed-by: Matt Robinson --- lib/puppet/application/agent.rb | 8 ++++---- lib/puppet/application/apply.rb | 7 ++++--- lib/puppet/application/device.rb | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb index f0442648b..ea7cbdfb5 100644 --- a/lib/puppet/application/agent.rb +++ b/lib/puppet/application/agent.rb @@ -187,10 +187,10 @@ configuration options can also be generated by running puppet agent with should always at least contain MD5, MD2, SHA1 and SHA256. * --detailed-exitcodes: - Provide transaction information via exit codes. If this is enabled, an - exit code of '2' means there were changes, and an exit code of '4' - means that there were failures during the transaction. This option - only makes sense in conjunction with --onetime. + Provide transaction information via exit codes. If this is enabled, an exit + code of '2' means there were changes, an exit code of '4' means there were + failures during the transaction, and an exit code of '6' means there were both + changes and failures. * --disable: Disable working on the local system. This puts a lock file in place, diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index 5562a9b09..200309b7d 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -82,9 +82,10 @@ configuration options can also be generated by running puppet with Enable full debugging. * --detailed-exitcodes: - Provide transaction information via exit codes. If this is enabled, an - exit code of '2' means there were changes, and an exit code of '4' - means that there were failures during the transaction. + Provide transaction information via exit codes. If this is enabled, an exit + code of '2' means there were changes, an exit code of '4' means there were + failures during the transaction, and an exit code of '6' means there were both + changes and failures. * --help: Print this help message diff --git a/lib/puppet/application/device.rb b/lib/puppet/application/device.rb index 3e2dec98c..977c5c023 100644 --- a/lib/puppet/application/device.rb +++ b/lib/puppet/application/device.rb @@ -113,10 +113,10 @@ parameter, so you can specify '--server ' as an argument. Enable full debugging. * --detailed-exitcodes: - Provide transaction information via exit codes. If this is enabled, an - exit code of '2' means there were changes, and an exit code of '4' means - that there were failures during the transaction. This option only makes - sense in conjunction with --onetime. + Provide transaction information via exit codes. If this is enabled, an exit + code of '2' means there were changes, an exit code of '4' means there were + failures during the transaction, and an exit code of '6' means there were both + changes and failures. * --help: Print this help message -- cgit From 72abe6ce7192bba0b295a8a83483668d21050624 Mon Sep 17 00:00:00 2001 From: Pieter van de Bruggen Date: Tue, 19 Jul 2011 10:55:26 -0700 Subject: (#7204) Consolidate Semantic Versioning code. This introduces a class representing a semantic version, and implementing a few of the most common uses of them: validation, comparison, and finding the greatest available version matching a range. This refactoring also allows us to easily expand our matching of version ranges in the future, which is a big plus. Reviewed-By: Daniel Pittman --- lib/puppet/interface.rb | 5 ++- lib/puppet/interface/face_collection.rb | 49 +++---------------------- lib/semver.rb | 65 +++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 46 deletions(-) create mode 100644 lib/semver.rb (limited to 'lib') diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb index 6be8b6930..6c288f3c0 100644 --- a/lib/puppet/interface.rb +++ b/lib/puppet/interface.rb @@ -2,6 +2,7 @@ require 'puppet' require 'puppet/util/autoload' require 'puppet/interface/documentation' require 'prettyprint' +require 'semver' class Puppet::Interface include FullDocs @@ -84,12 +85,12 @@ class Puppet::Interface attr_reader :name, :version def initialize(name, version, &block) - unless Puppet::Interface::FaceCollection.validate_version(version) + unless SemVer.valid?(version) raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!" end @name = Puppet::Interface::FaceCollection.underscorize(name) - @version = version + @version = SemVer.new(version) # The few bits of documentation we actually demand. The default license # is a favour to our end users; if you happen to get that in a core face diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index 12d3c56b1..4522824fd 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -1,8 +1,6 @@ require 'puppet/interface' module Puppet::Interface::FaceCollection - SEMVER_VERSION = /^(\d+)\.(\d+)\.(\d+)([A-Za-z][0-9A-Za-z-]*|)$/ - @faces = Hash.new { |hash, key| hash[key] = {} } def self.faces @@ -17,55 +15,18 @@ module Puppet::Interface::FaceCollection @faces.keys.select {|name| @faces[name].length > 0 } end - def self.validate_version(version) - !!(SEMVER_VERSION =~ version.to_s) - end - - def self.semver_to_array(v) - parts = SEMVER_VERSION.match(v).to_a[1..4] - parts[0..2] = parts[0..2].map { |e| e.to_i } - parts - end - - def self.cmp_semver(a, b) - a, b = [a, b].map do |x| semver_to_array(x) end - - cmp = a[0..2] <=> b[0..2] - if cmp == 0 - cmp = a[3] <=> b[3] - cmp = +1 if a[3].empty? && !b[3].empty? - cmp = -1 if b[3].empty? && !a[3].empty? - end - cmp - end - - def self.prefix_match?(desired, target) - # Can't meaningfully do a prefix match with current on either side. - return false if desired == :current - return false if target == :current - - # REVISIT: Should probably fail if the matcher is not valid. - prefix = desired.split('.').map {|x| x =~ /^\d+$/ and x.to_i } - have = semver_to_array(target) - - while want = prefix.shift do - return false unless want == have.shift - end - return true - end - def self.[](name, version) name = underscorize(name) get_face(name, version) or load_face(name, version) end # get face from memory, without loading. - def self.get_face(name, desired_version) + def self.get_face(name, pattern) return nil unless @faces.has_key? name + return @faces[name][:current] if pattern == :current - return @faces[name][:current] if desired_version == :current - - found = @faces[name].keys.select {|v| prefix_match?(desired_version, v) }.sort.last + versions = @faces[name].keys - [ :current ] + found = SemVer.find_matching(pattern, versions) return @faces[name][found] end @@ -108,7 +69,7 @@ module Puppet::Interface::FaceCollection # versions here and return the last item in that set. # # --daniel 2011-04-06 - latest_ver = @faces[name].keys.sort {|a, b| cmp_semver(a, b) }.last + latest_ver = @faces[name].keys.sort.last @faces[name][:current] = @faces[name][latest_ver] end rescue LoadError => e diff --git a/lib/semver.rb b/lib/semver.rb new file mode 100644 index 000000000..ef9435abd --- /dev/null +++ b/lib/semver.rb @@ -0,0 +1,65 @@ +class SemVer + VERSION = /^v?(\d+)\.(\d+)\.(\d+)([A-Za-z][0-9A-Za-z-]*|)$/ + SIMPLE_RANGE = /^v?(\d+|[xX])(?:\.(\d+|[xX])(?:\.(\d+|[xX]))?)?$/ + + include Comparable + + def self.valid?(ver) + VERSION =~ ver + end + + def self.find_matching(pattern, versions) + versions.select { |v| v.matched_by?("#{pattern}") }.sort.last + end + + attr_reader :major, :minor, :tiny, :special + + def initialize(ver) + unless SemVer.valid?(ver) + raise ArgumentError.new("Invalid version string '#{ver}'!") + end + + @major, @minor, @tiny, @special = VERSION.match(ver).captures.map do |x| + # Because Kernel#Integer tries to interpret hex and octal strings, which + # we specifically do not want, and which cannot be overridden in 1.8.7. + Float(x).to_i rescue x + end + end + + def <=>(other) + other = SemVer.new("#{other}") unless other.is_a? SemVer + return self.major <=> other.major unless self.major == other.major + return self.minor <=> other.minor unless self.minor == other.minor + return self.tiny <=> other.tiny unless self.tiny == other.tiny + + return 0 if self.special == other.special + return 1 if self.special == '' + return -1 if other.special == '' + + return self.special <=> other.special + end + + def matched_by?(pattern) + # For the time being, this is restricted to exact version matches and + # simple range patterns. In the future, we should implement some or all of + # the comparison operators here: + # https://github.com/isaacs/node-semver/blob/d474801/semver.js#L340 + + case pattern + when SIMPLE_RANGE + pattern = SIMPLE_RANGE.match(pattern).captures + pattern[1] = @minor unless pattern[1] && pattern[1] !~ /x/i + pattern[2] = @tiny unless pattern[2] && pattern[2] !~ /x/i + [@major, @minor, @tiny] == pattern.map { |x| x.to_i } + when VERSION + self == SemVer.new(pattern) + else + false + end + end + + def inspect + "v#{@major}.#{@minor}.#{@tiny}#{@special}" + end + alias :to_s :inspect +end -- cgit From 26ee468e8b963d63933d9a27a65d55510ff87618 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Mon, 18 Jul 2011 22:28:18 -0700 Subject: (#8489) Consistently use File::PATH_SEPARATOR Puppet uses both colon and File::PATH_SEPARATOR in various places, which does not work on Windows, where File::PATH_SEPARATOR is a semi-colon. This commit changes the code and tests to consistently use File::PATH_SEPARATOR. Reviewed-by: Jacob Helwig --- lib/puppet/defaults.rb | 8 +++++--- lib/puppet/indirector/facts/facter.rb | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index d5e06c54a..e6beb512e 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -441,9 +441,11 @@ module Puppet authorization system for `puppet master`." ], :ca => [true, "Wether the master should function as a certificate authority."], - :modulepath => {:default => "$confdir/modules:/usr/share/puppet/modules", - :desc => "The search path for modules as a colon-separated list of - directories.", :type => :setting }, # We don't want this to be considered a file, since it's multiple files. + :modulepath => { + :default => "$confdir/modules#{File::PATH_SEPARATOR}/usr/share/puppet/modules", + :desc => "The search path for modules as a list of directories separated by the '#{File::PATH_SEPARATOR}' character.", + :type => :setting # We don't want this to be considered a file, since it's multiple files. + }, :ssl_client_header => ["HTTP_X_CLIENT_DN", "The header containing an authenticated client's SSL DN. Only used with Mongrel. This header must be set by the proxy to the authenticated client's SSL DN (e.g., `/CN=puppet.puppetlabs.com`). diff --git a/lib/puppet/indirector/facts/facter.rb b/lib/puppet/indirector/facts/facter.rb index ab7378a34..6312a95fb 100644 --- a/lib/puppet/indirector/facts/facter.rb +++ b/lib/puppet/indirector/facts/facter.rb @@ -9,12 +9,12 @@ class Puppet::Node::Facts::Facter < Puppet::Indirector::Code def self.load_fact_plugins # Add any per-module fact directories to the factpath - module_fact_dirs = Puppet[:modulepath].split(":").collect do |d| + module_fact_dirs = Puppet[:modulepath].split(File::PATH_SEPARATOR).collect do |d| ["lib", "plugins"].map do |subdirectory| Dir.glob("#{d}/*/#{subdirectory}/facter") end end.flatten - dirs = module_fact_dirs + Puppet[:factpath].split(":") + dirs = module_fact_dirs + Puppet[:factpath].split(File::PATH_SEPARATOR) x = dirs.each do |dir| load_facts_in_dir(dir) end -- cgit From 45ae5b4a9ced26dfcd3e324391f9a26cb02bf93d Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Mon, 18 Jul 2011 22:44:10 -0700 Subject: (#8268) Require windows drive letters in absolute file paths When testing whether a file path is absolute, the regexp was only handling POSIX style file paths. This commit requires Windows style file paths to start with a drive letter. A future commit will refacter the various places we do path validation to support both Windows drive letters and UNC paths. Reviewed-by: Jacob Helwig --- lib/puppet/file_serving/fileset.rb | 9 +++++++-- lib/puppet/node/environment.rb | 5 +++-- lib/puppet/parser/type_loader.rb | 3 ++- lib/puppet/type/file.rb | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_serving/fileset.rb b/lib/puppet/file_serving/fileset.rb index f29f70a53..b4f1457df 100644 --- a/lib/puppet/file_serving/fileset.rb +++ b/lib/puppet/file_serving/fileset.rb @@ -59,8 +59,13 @@ class Puppet::FileServing::Fileset end def initialize(path, options = {}) - path = path.chomp(File::SEPARATOR) unless path == File::SEPARATOR - raise ArgumentError.new("Fileset paths must be fully qualified") unless File.expand_path(path) == path + if Puppet.features.microsoft_windows? + # REMIND: UNC path + path = path.chomp(File::SEPARATOR) unless path =~ /^[A-Za-z]:\/$/ + else + path = path.chomp(File::SEPARATOR) unless path == File::SEPARATOR + end + raise ArgumentError.new("Fileset paths must be fully qualified: #{path}") unless File.expand_path(path) == path @path = path diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index dc631979e..96fdc3c1e 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -136,14 +136,15 @@ class Puppet::Node::Environment end def validate_dirs(dirs) + dir_regex = Puppet.features.microsoft_windows? ? /^[A-Za-z]:#{File::SEPARATOR}/ : /^#{File::SEPARATOR}/ dirs.collect do |dir| - if dir !~ /^#{File::SEPARATOR}/ + if dir !~ dir_regex File.join(Dir.getwd, dir) else dir end end.find_all do |p| - p =~ /^#{File::SEPARATOR}/ && FileTest.directory?(p) + p =~ dir_regex && FileTest.directory?(p) end end diff --git a/lib/puppet/parser/type_loader.rb b/lib/puppet/parser/type_loader.rb index 1fba73d0b..68def068d 100644 --- a/lib/puppet/parser/type_loader.rb +++ b/lib/puppet/parser/type_loader.rb @@ -80,7 +80,8 @@ class Puppet::Parser::TypeLoader loaded_asts = [] files.each do |file| - unless file =~ /^#{File::SEPARATOR}/ + regex = Puppet.features.microsoft_windows? ? /^[A-Za-z]:#{File::SEPARATOR}/ : /^#{File::SEPARATOR}/ + unless file =~ regex file = File.join(dir, file) end @loading_helper.do_once(file) do diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 72e9a9495..8ab12ca2f 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -36,7 +36,7 @@ Puppet::Type.newtype(:file) do validate do |value| # accept various path syntaxes: lone slash, posix, win32, unc - unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) + unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^[A-Za-z]:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) fail Puppet::Error, "File paths must be fully qualified, not '#{value}'" end end -- cgit From 185a666018c0cf0b2c497f655f942a82cd22e49e Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Tue, 19 Jul 2011 15:19:10 -0700 Subject: Remove Puppet::Network::HttpPool keep_alive handling Keep alive has been disabled since 2008, and seems to have caused problems when it was enabled before then. Since there doesn't seem to be any push to get it working again, just remove it to simplify this code. This also allows us to entirely remove the usage of Puppet::Util::Cacher from HttpPool. Paired-With: Jacob Helwig --- lib/puppet/configurer.rb | 4 --- lib/puppet/network/client.rb | 5 ---- lib/puppet/network/http_pool.rb | 55 ----------------------------------------- 3 files changed, 64 deletions(-) (limited to 'lib') diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index 3d6e8557c..5581917a1 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -161,10 +161,6 @@ class Puppet::Configurer # Make sure we forget the retained module_directories of any autoload # we might have used. Thread.current[:env_module_directories] = nil - - # Now close all of our existing http connections, since there's no - # reason to leave them lying open. - Puppet::Network::HttpPool.clear_http_instances end ensure Puppet::Util::Log.close(report) diff --git a/lib/puppet/network/client.rb b/lib/puppet/network/client.rb index c56b21393..f9c4c5fea 100644 --- a/lib/puppet/network/client.rb +++ b/lib/puppet/network/client.rb @@ -82,11 +82,6 @@ class Puppet::Network::Client self.read_cert - # We have to start the HTTP connection manually before we start - # sending it requests or keep-alive won't work. Note that with #1010, - # we don't currently actually want keep-alive. - @driver.start if @driver.respond_to? :start and Puppet::Network::HttpPool.keep_alive? - @local = false elsif hash.include?(driverparam) @driver = hash[driverparam] diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb index 7d227b4d4..d4ec48d22 100644 --- a/lib/puppet/network/http_pool.rb +++ b/lib/puppet/network/http_pool.rb @@ -4,50 +4,12 @@ require 'puppet/util/cacher' module Puppet::Network; end -# Manage Net::HTTP instances for keep-alive. module Puppet::Network::HttpPool - class << self - include Puppet::Util::Cacher - - private - - cached_attr(:http_cache) { Hash.new } - end - # Use the global localhost instance. def self.ssl_host Puppet::SSL::Host.localhost end - # 2008/03/23 - # LAK:WARNING: Enabling this has a high propability of - # causing corrupt files and who knows what else. See #1010. - HTTP_KEEP_ALIVE = false - - def self.keep_alive? - HTTP_KEEP_ALIVE - end - - # Clear our http cache, closing all connections. - def self.clear_http_instances - http_cache.each do |name, connection| - connection.finish if connection.started? - end - Puppet::Util::Cacher.expire - end - - # Make sure we set the driver up when we read the cert in. - def self.read_cert - if val = super # This calls read_cert from the Puppet::SSLCertificates::Support module. - # Clear out all of our connections, since they previously had no cert and now they - # should have them. - clear_http_instances - return val - else - return false - end - end - # Use cert information from a Puppet client to set up the http object. def self.cert_setup(http) # Just no-op if we don't have certs. @@ -63,21 +25,6 @@ module Puppet::Network::HttpPool # Retrieve a cached http instance if caching is enabled, else return # a new one. def self.http_instance(host, port, reset = false) - # We overwrite the uninitialized @http here with a cached one. - key = "#{host}:#{port}" - - # Return our cached instance if we've got a cache, as long as we're not - # resetting the instance. - if keep_alive? - return http_cache[key] if ! reset and http_cache[key] - - # Clean up old connections if we have them. - if http = http_cache[key] - http_cache.delete(key) - http.finish if http.started? - end - end - args = [host, port] if Puppet[:http_proxy_host] == "none" args << nil << nil @@ -97,8 +44,6 @@ module Puppet::Network::HttpPool cert_setup(http) - http_cache[key] = http if keep_alive? - http end end -- cgit From cc311ad3dcb70547d7249e7aec9f545672c3e8e2 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Tue, 19 Jul 2011 16:45:26 -0700 Subject: maint: SSL::Inventory.serial should report missing names. Our SSL inventory was able to find the serial number of a certificate by name, but was incapable of living up to the contract it offered, that it would actually report when a certificate was missing. Now it returns `nil`, which is the same case as "no inventory", if the certificate was not found, rather than accidentally returning the entire inventory data as raw strings. Reviewed-By: Pieter van de Bruggen --- lib/puppet/ssl/inventory.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/ssl/inventory.rb b/lib/puppet/ssl/inventory.rb index e094da100..c210fdc35 100644 --- a/lib/puppet/ssl/inventory.rb +++ b/lib/puppet/ssl/inventory.rb @@ -48,5 +48,7 @@ class Puppet::SSL::Inventory return Integer($1) end + + return nil end end -- cgit From c830ab01f31b3c6999953783a0ec1939bdbc25a9 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Mon, 18 Jul 2011 11:40:05 -0700 Subject: (#6789) Port SSL::CertificateAuthority::Interface to a Face The Puppet::SSL::CertificateAuthority::Interface class was an early prototype heading toward building out a system like Faces. Now that we have done that, this changeset ports the early code to a new face. Reviewed-By: Pieter van de Bruggen --- lib/puppet/application/ca.rb | 5 + lib/puppet/face/ca.rb | 233 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 lib/puppet/application/ca.rb create mode 100644 lib/puppet/face/ca.rb (limited to 'lib') diff --git a/lib/puppet/application/ca.rb b/lib/puppet/application/ca.rb new file mode 100644 index 000000000..d1ec2502e --- /dev/null +++ b/lib/puppet/application/ca.rb @@ -0,0 +1,5 @@ +require 'puppet/application/face_base' + +class Puppet::Application::Ca < Puppet::Application::FaceBase + run_mode :master +end diff --git a/lib/puppet/face/ca.rb b/lib/puppet/face/ca.rb new file mode 100644 index 000000000..e643530f0 --- /dev/null +++ b/lib/puppet/face/ca.rb @@ -0,0 +1,233 @@ +require 'puppet/face' + +Puppet::Face.define(:ca, '0.1.0') do + copyright "Puppet Labs", 2011 + license "Apache 2 license; see COPYING" + + summary "Local Puppet Certificate Authority management." + + description < e + "- #{name} (#{host.certificate.fingerprint}) (#{e.to_s})" + end + end + end.join("\n") + end + end + + action :destroy do + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + ca.destroy host + end + end + + action :revoke do + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + begin + ca.revoke host + rescue ArgumentError => e + # This is a bit naff, but it makes the behaviour consistent with the + # destroy action. The underlying tools could be nicer for that sort + # of thing; they have fairly inconsistent reporting of failures. + raise unless e.to_s =~ /Could not find a serial number for / + "Nothing was revoked" + end + end + end + + action :generate do + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + begin + ca.generate host + rescue RuntimeError => e + if e.to_s =~ /already has a requested certificate/ + "#{host} already has a certificate request; use sign instead" + else + raise + end + rescue ArgumentError => e + if e.to_s =~ /A Certificate already exists for / + "#{host} already has a certificate" + else + raise + end + end + end + end + + action :sign do + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + begin + ca.sign host + rescue ArgumentError => e + if e.to_s =~ /Could not find certificate request/ + e.to_s + else + raise + end + end + end + end + + action :print do + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + ca.print host + end + end + + action :fingerprint do + option "--digest ALGORITHM" do + summary "The hash algorithm to use when displaying the fingerprint" + end + + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + begin + # I want the default from the CA, not to duplicate it, but passing + # 'nil' explicitly means that we don't get that. This works... + if options.has_key? :digest + ca.fingerprint host, options[:digest] + else + ca.fingerprint host + end + rescue ArgumentError => e + raise unless e.to_s =~ /Could not find a certificate or csr for/ + nil + end + end + end + + action :verify do + when_invoked do |host, options| + raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca? + unless ca = Puppet::SSL::CertificateAuthority.instance + raise "Unable to fetch the CA" + end + + begin + ca.verify host + { :host => host, :valid => true } + rescue ArgumentError => e + raise unless e.to_s =~ /Could not find a certificate for/ + { :host => host, :valid => false, :error => e.to_s } + rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e + { :host => host, :valid => false, :error => e.to_s } + end + end + + when_rendering :console do |value| + if value[:valid] + nil + else + "Could not verify #{value[:host]}: #{value[:error]}" + end + end + end +end -- cgit From b75b1c19ecf6c278b065d203ac8486fa598caa8b Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Wed, 20 Jul 2011 11:58:55 -0700 Subject: (#6787) Add `default_to` for options. This implement support for options with default values, allowing faces to set those values when not invoked. This can eliminate substantial duplicate code from actions, especially when there are face-level options in use. Reviewed-By: Pieter van de Bruggen --- lib/puppet/interface/action.rb | 9 +++++++++ lib/puppet/interface/option.rb | 19 +++++++++++++++++++ lib/puppet/interface/option_builder.rb | 13 +++++++++++++ 3 files changed, 41 insertions(+) (limited to 'lib') diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index fe77a9658..fc1121eb6 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -199,6 +199,7 @@ def #{@name}(#{decl.join(", ")}) options = args.last action = get_action(#{name.inspect}) + action.add_default_args(args) action.validate_args(args) __invoke_decorations(:before, action, args, options) rval = self.__send__(#{internal_name.inspect}, *args) @@ -252,6 +253,14 @@ WRAPPER option end + def add_default_args(args) + options.map {|x| get_option(x) }.each do |option| + if option.has_default? and not option.aliases.any? {|x| args.last.has_key? x} + args.last[option.name] = option.default + end + end + end + def validate_args(args) # Check for multiple aliases for the same option... args.last.keys.each do |name| diff --git a/lib/puppet/interface/option.rb b/lib/puppet/interface/option.rb index 3cd930acf..01f6f2307 100644 --- a/lib/puppet/interface/option.rb +++ b/lib/puppet/interface/option.rb @@ -6,6 +6,7 @@ class Puppet::Interface::Option def initialize(parent, *declaration, &block) @parent = parent @optparse = [] + @default = nil # Collect and sort the arguments in the declaration. dups = {} @@ -81,8 +82,26 @@ class Puppet::Interface::Option !!@required end + def has_default? + !!@default + end + + def default=(proc) + required and raise ArgumentError, "#{self} can't be optional and have a default value" + proc.is_a? Proc or raise ArgumentError, "default value for #{self} is a #{proc.class.name.inspect}, not a proc" + @default = proc + end + + def default + @default and @default.call + end + attr_reader :parent, :name, :aliases, :optparse attr_accessor :required + def required=(value) + has_default? and raise ArgumentError, "#{self} can't be optional and have a default value" + @required = value + end attr_accessor :before_action def before_action=(proc) diff --git a/lib/puppet/interface/option_builder.rb b/lib/puppet/interface/option_builder.rb index 5676ec977..c87adc2c0 100644 --- a/lib/puppet/interface/option_builder.rb +++ b/lib/puppet/interface/option_builder.rb @@ -51,4 +51,17 @@ class Puppet::Interface::OptionBuilder def required(value = true) @option.required = value end + + def default_to(&block) + block or raise ArgumentError, "#{@option} default_to requires a block" + if @option.has_default? + raise ArgumentError, "#{@option} already has a default value" + end + # Ruby 1.8 treats a block without arguments as accepting any number; 1.9 + # gets this right, so we work around it for now... --daniel 2011-07-20 + unless block.arity == 0 or (RUBY_VERSION =~ /^1\.8/ and block.arity == -1) + raise ArgumentError, "#{@option} default_to block should not take any arguments" + end + @option.default = block + end end -- cgit From fd6a653cb32cb03e339655862c526fd5dccbfcf0 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Wed, 20 Jul 2011 12:35:22 -0700 Subject: (#7123) Support runtime setting of 'default' on actions. Given the inheritance model for actions, we are sometimes going to need to set them to 'default' at runtime, rather than during their static declaration. Add tests to verify that this works correctly, and update the code to ensure that happens. This gives up caching of the default action, but this should be an extremely rare operation - pretty much only CLI invocation, really. Reviewed-By: Pieter van de Bruggen --- lib/puppet/interface/action_manager.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/action_manager.rb b/lib/puppet/interface/action_manager.rb index fbf588d7d..5c9af4f96 100644 --- a/lib/puppet/interface/action_manager.rb +++ b/lib/puppet/interface/action_manager.rb @@ -7,13 +7,14 @@ module Puppet::Interface::ActionManager require 'puppet/interface/action_builder' @actions ||= {} - @default_action ||= nil raise "Action #{name} already defined for #{self}" if action?(name) + action = Puppet::Interface::ActionBuilder.build(self, name, &block) - if action.default - raise "Actions #{@default_action.name} and #{name} cannot both be default" if @default_action - @default_action = action + + if action.default and current = get_default_action + raise "Actions #{current.name} and #{name} cannot both be default" end + @actions[action.name] = action end @@ -61,7 +62,11 @@ module Puppet::Interface::ActionManager end def get_default_action - @default_action + default = actions.map {|x| get_action(x) }.select {|x| x.default } + if default.length > 1 + raise "The actions #{default.map(&:name).join(", ")} cannot all be default" + end + default.first end def action?(name) -- cgit From 395c1742981590c694ee6f0154ba7ad63c6bcb36 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Wed, 20 Jul 2011 12:37:53 -0700 Subject: (#7123) Make `find` the default action... Part of the progress toward getting the `puppet status` invocation working nicely is that it should default to invoking the `find` operation. This implements that, using the new runtime default action facility. Reviewed-By: Pieter van de Bruggen --- lib/puppet/face/status.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/puppet/face/status.rb b/lib/puppet/face/status.rb index bdb0c4d26..e8c87e98d 100644 --- a/lib/puppet/face/status.rb +++ b/lib/puppet/face/status.rb @@ -12,6 +12,7 @@ Puppet::Indirector::Face.define(:status, '0.0.1') do get_action(:search).summary "Invalid for this subcommand." find = get_action(:find) + find.default = true find.summary "Check status of puppet master server." find.arguments "" find.returns <<-'EOT' -- cgit From 4bad729f56c26d8154cd0f20614fa4e478de9d40 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:36:03 -0700 Subject: Remove use of Util::Cacher in FileServing::Configuration This class was using Util::Cacher for its singleton instance, when that was unnecessary. The FileServing::Configuration instance already manages whether or not to reparse its config file, based on whether it has changed. Thus, there is no need for it to be manually expired via the cacher. Reviewed-By: Jacob Helwig --- lib/puppet/file_serving/configuration.rb | 16 +++++++--------- lib/puppet/indirector/file_server.rb | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_serving/configuration.rb b/lib/puppet/file_serving/configuration.rb index 78e4de6cb..d88d57cb0 100644 --- a/lib/puppet/file_serving/configuration.rb +++ b/lib/puppet/file_serving/configuration.rb @@ -2,29 +2,27 @@ # Created by Luke Kanies on 2007-10-16. # Copyright (c) 2007. All rights reserved. +require 'monitor' require 'puppet' require 'puppet/file_serving' require 'puppet/file_serving/mount' require 'puppet/file_serving/mount/file' require 'puppet/file_serving/mount/modules' require 'puppet/file_serving/mount/plugins' -require 'puppet/util/cacher' class Puppet::FileServing::Configuration require 'puppet/file_serving/configuration/parser' - class << self - include Puppet::Util::Cacher - cached_attr(:configuration) { new } + extend MonitorMixin + + def self.configuration + synchronize do + @configuration ||= new + end end Mount = Puppet::FileServing::Mount - # Create our singleton configuration. - def self.create - configuration - end - private_class_method :new attr_reader :mounts diff --git a/lib/puppet/indirector/file_server.rb b/lib/puppet/indirector/file_server.rb index 46a08c97d..d6a8ab872 100644 --- a/lib/puppet/indirector/file_server.rb +++ b/lib/puppet/indirector/file_server.rb @@ -64,6 +64,6 @@ class Puppet::Indirector::FileServer < Puppet::Indirector::Terminus # Our fileserver configuration, if needed. def configuration - Puppet::FileServing::Configuration.create + Puppet::FileServing::Configuration.configuration end end -- cgit From 6a1b65760a0d8c6299d5c6d260dc37b5e0637706 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:37:06 -0700 Subject: Remove use of Util::Cacher from FileServing::Mount::File Allowing this value to be expirable is superfluous; it is only used on the master, which never expires its cache. Additionally, it was providing partial support for an event we don't fully support already (hostname and domain changing during the lifetime of a master). Reviewed-By: Jacob Helwig --- lib/puppet/file_serving/mount.rb | 1 - lib/puppet/file_serving/mount/file.rb | 21 +++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_serving/mount.rb b/lib/puppet/file_serving/mount.rb index 37dd89537..79290ab81 100644 --- a/lib/puppet/file_serving/mount.rb +++ b/lib/puppet/file_serving/mount.rb @@ -4,7 +4,6 @@ require 'puppet/network/authstore' require 'puppet/util/logging' -require 'puppet/util/cacher' require 'puppet/file_serving' require 'puppet/file_serving/metadata' require 'puppet/file_serving/content' diff --git a/lib/puppet/file_serving/mount/file.rb b/lib/puppet/file_serving/mount/file.rb index 7d622e4bf..7f5af7f52 100644 --- a/lib/puppet/file_serving/mount/file.rb +++ b/lib/puppet/file_serving/mount/file.rb @@ -1,18 +1,15 @@ -require 'puppet/util/cacher' - require 'puppet/file_serving/mount' class Puppet::FileServing::Mount::File < Puppet::FileServing::Mount - class << self - include Puppet::Util::Cacher - - cached_attr(:localmap) do - { "h" => Facter.value("hostname"), - "H" => [Facter.value("hostname"), - Facter.value("domain")].join("."), - "d" => Facter.value("domain") - } - end + def self.localmap + @localmap ||= { + "h" => Facter.value("hostname"), + "H" => [ + Facter.value("hostname"), + Facter.value("domain") + ].join("."), + "d" => Facter.value("domain") + } end def complete_path(relative_path, node) -- cgit From 93299e90e231bb407923e3534a0e33d841b95355 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:37:33 -0700 Subject: Remove unused require 'puppet/util/cacher' from Network::HttpPool The use of Puppet::Util::Cacher in this module was removed previously, and this stray, unnecessary require was left around. Reviewed-By: Jacob Helwig --- lib/puppet/network/http_pool.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb index d4ec48d22..8baf48c77 100644 --- a/lib/puppet/network/http_pool.rb +++ b/lib/puppet/network/http_pool.rb @@ -1,6 +1,5 @@ require 'puppet/ssl/host' require 'net/https' -require 'puppet/util/cacher' module Puppet::Network; end -- cgit From fac867c7bdbfbd431b089eb1bfb6eb73230e912c Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:38:51 -0700 Subject: Remove Util::Cacher usage from SSL::CertificateAuthority Allowing the singleton_instance value to be expirable is unnecessary, because there will never be a need for a different CA instance in the lifetime of a master. Additionally, the master never expired its cache anyway. This was only using the cacher so it could be expired for tests, so it can safely be removed. Reviewed-By: Jacob Helwig --- lib/puppet/ssl/certificate_authority.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb index d65067c70..a4cbaf78a 100644 --- a/lib/puppet/ssl/certificate_authority.rb +++ b/lib/puppet/ssl/certificate_authority.rb @@ -1,6 +1,6 @@ +require 'monitor' require 'puppet/ssl/host' require 'puppet/ssl/certificate_request' -require 'puppet/util/cacher' # The class that knows how to sign certificates. It creates # a 'special' SSL::Host whose name is 'ca', thus indicating @@ -17,6 +17,8 @@ class Puppet::SSL::CertificateAuthority require 'puppet/ssl/certificate_authority/interface' require 'puppet/network/authstore' + extend MonitorMixin + class CertificateVerificationError < RuntimeError attr_accessor :error_code @@ -25,10 +27,10 @@ class Puppet::SSL::CertificateAuthority end end - class << self - include Puppet::Util::Cacher - - cached_attr(:singleton_instance) { new } + def self.singleton_instance + synchronize do + @singleton_instance ||= new + end end def self.ca? -- cgit From bdcb9be3b5d7cd54548cbeb7b13bee6fe4e730f7 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:40:00 -0700 Subject: Remove Puppet::Util::Cacher usage from Puppet::Util::Settings The path attribute was being unnecessarily cached. The value is a LoadedFile instance, which already knows how to check whether it needs to be reloaded. The act of reparsing was being triggered separately from the cacher mechanism. The comment indicated this value was only being cached so it could be easily cleared for tests, but it wasn't being cleared for tests. Thus, there is no reason for this attribute to be cached, so remove it. Reviewed-By: Jacob Helwig --- lib/puppet/util/settings.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb index 4559e9af3..caaf61b7b 100644 --- a/lib/puppet/util/settings.rb +++ b/lib/puppet/util/settings.rb @@ -2,13 +2,11 @@ require 'puppet' require 'sync' require 'getoptlong' require 'puppet/external/event-loop' -require 'puppet/util/cacher' require 'puppet/util/loadedfile' # The class for handling configuration files. class Puppet::Util::Settings include Enumerable - include Puppet::Util::Cacher require 'puppet/util/settings/setting' require 'puppet/util/settings/file_setting' @@ -401,11 +399,10 @@ class Puppet::Util::Settings } end - # Cache this in an easily clearable way, since we were - # having trouble cleaning it up after tests. - cached_attr(:file) do + def file + return @file if @file if path = self[:config] and FileTest.exist?(path) - Puppet::Util::LoadedFile.new(path) + @file = Puppet::Util::LoadedFile.new(path) end end -- cgit From 4b0c847f19d5db81758b5561bdc8196591209ef0 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:41:04 -0700 Subject: Remove cached_attrs from Puppet::Type::File These values needn't be cached_attrs, because they can be managed manually. 'stat' does need to be cached, so that we avoid statting the file for each property we want to check from disk. The 'content' attribute of 'source' also needs to be cached, because it's retrieved from the server, which we certainly don't want to do multiple times. We need a mechanism for invalidating the 'stat' after we've written the file, so we use a special value :needs_stat, which essentially represented "undefined". We use this rather than nil so that we can store a failed stat if it occurs. Because the content and metadata of our source file will never change, there is no need to be able to similarly expire the values of those attributes. Reviewed-By: Jacob Helwig --- lib/puppet/type/file.rb | 23 ++++++++++++++--------- lib/puppet/type/file/source.rb | 18 +++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 8ab12ca2f..988416ab5 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -394,7 +394,7 @@ Puppet::Type.newtype(:file) do @parameters.each do |name, param| param.flush if param.respond_to?(:flush) end - @stat = nil + @stat = :needs_stat end def initialize(hash) @@ -413,7 +413,7 @@ Puppet::Type.newtype(:file) do end end - @stat = nil + @stat = :needs_stat end # Configure discovered resources to be purged. @@ -623,7 +623,7 @@ Puppet::Type.newtype(:file) do else self.fail "Could not back up files of type #{s.ftype}" end - expire + @stat = :needs_stat end def retrieve @@ -674,22 +674,27 @@ Puppet::Type.newtype(:file) do # use either 'stat' or 'lstat', and we expect the properties to use the # resulting stat object accordingly (mostly by testing the 'ftype' # value). - cached_attr(:stat) do + # + # We use the initial value :needs_stat to ensure we only stat the file once, + # but can also keep track of a failed stat (@stat == nil). This also allows + # us to re-stat on demand by setting @stat = :needs_stat. + def stat + return @stat unless @stat == :needs_stat + method = :stat # Files are the only types that support links if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy method = :lstat end - path = self[:path] - begin + @stat = begin ::File.send(method, self[:path]) rescue Errno::ENOENT => error - return nil + nil rescue Errno::EACCES => error warning "Could not stat; permission denied" - return nil + nil end end @@ -776,7 +781,7 @@ Puppet::Type.newtype(:file) do next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name) # Make sure we get a new stat objct - expire + @stat = :needs_stat currentvalue = thing.retrieve thing.sync unless thing.safe_insync?(currentvalue) end diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 49e885865..222b85dbb 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -95,13 +95,14 @@ module Puppet end # Look up (if necessary) and return remote content. - cached_attr(:content) do + def content + return @content if @content raise Puppet::DevError, "No source for content was stored with the metadata" unless metadata.source unless tmp = Puppet::FileServing::Content.indirection.find(metadata.source) fail "Could not find any content at %s" % metadata.source end - tmp.content + @content = tmp.content end # Copy the values from the source to the resource. Yay. @@ -137,25 +138,28 @@ module Puppet ! (metadata.nil? or metadata.ftype.nil?) end + attr_writer :metadata + # Provide, and retrieve if necessary, the metadata for this file. Fail # if we can't find data about this host, and fail if there are any # problems in our query. - cached_attr(:metadata) do + def metadata + return @metadata if @metadata return nil unless value result = nil value.each do |source| begin if data = Puppet::FileServing::Metadata.indirection.find(source) - result = data - result.source = source + @metadata = data + @metadata.source = source break end rescue => detail fail detail, "Could not retrieve file metadata for #{source}: #{detail}" end end - fail "Could not retrieve information from source(s) #{value.join(", ")}" unless result - result + fail "Could not retrieve information from source(s) #{value.join(", ")}" unless @metadata + @metadata end def local? -- cgit From e2ea023f809c2bdc53b5259047c28f8061f57e54 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:47:07 -0700 Subject: Remove caching from the catalog, types, and parameters Types and parameters were registering their catalog as their expirer, so that the catalog could expire them between uses. However, because catalogs are never reused (and neither are types or parameters), there is no need to expire anything. Thus, we remove the entire cleanup/expire logic from catalog, type, and parameter. Reviewed-By: Jacob Helwig --- lib/puppet/parameter.rb | 6 ------ lib/puppet/resource/catalog.rb | 20 -------------------- lib/puppet/type.rb | 8 -------- 3 files changed, 34 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb index 29d60fc66..c97f93b23 100644 --- a/lib/puppet/parameter.rb +++ b/lib/puppet/parameter.rb @@ -2,7 +2,6 @@ require 'puppet/util/methodhelper' require 'puppet/util/log_paths' require 'puppet/util/logging' require 'puppet/util/docs' -require 'puppet/util/cacher' class Puppet::Parameter include Puppet::Util @@ -10,7 +9,6 @@ class Puppet::Parameter include Puppet::Util::LogPaths include Puppet::Util::Logging include Puppet::Util::MethodHelper - include Puppet::Util::Cacher require 'puppet/parameter/value_collection' @@ -150,10 +148,6 @@ class Puppet::Parameter self.fail(Puppet::DevError, msg) end - def expirer - resource.catalog - end - def fail(*args) type = nil if args[0].is_a?(Class) diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index 8eb4266db..bb19f3ebc 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -3,7 +3,6 @@ require 'puppet/indirector' require 'puppet/simple_graph' require 'puppet/transaction' -require 'puppet/util/cacher' require 'puppet/util/pson' require 'puppet/util/tagging' @@ -20,7 +19,6 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph include Puppet::Util::Tagging extend Puppet::Util::Pson - include Puppet::Util::Cacher::Expirer # The host name this is a catalog for. attr_accessor :name @@ -123,10 +121,6 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph def apply(options = {}) @applying = true - # Expire all of the resource data -- this ensures that all - # data we're operating against is entirely current. - expire - Puppet::Util::Storage.load if host_config? transaction = Puppet::Transaction.new(self, options[:report]) @@ -162,7 +156,6 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph return transaction ensure @applying = false - cleanup end # Are we in the middle of applying the catalog? @@ -197,14 +190,6 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph resource end - def dependent_data_expired?(ts) - if applying? - return super - else - return true - end - end - # Turn our catalog graph into an old-style tree of TransObjects and TransBuckets. # LAK:NOTE(20081211): This is a pre-0.25 backward compatibility method. # It can be removed as soon as xmlrpc is killed. @@ -564,11 +549,6 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph private - def cleanup - # Expire any cached data the resources are keeping. - expire - end - # Verify that the given resource isn't defined elsewhere. def fail_on_duplicate_type_and_title(resource) # Short-curcuit the common case, diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index 15f340f55..963b925bf 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -9,7 +9,6 @@ require 'puppet/metatype/manager' require 'puppet/util/errors' require 'puppet/util/log_paths' require 'puppet/util/logging' -require 'puppet/util/cacher' require 'puppet/file_collection/lookup' require 'puppet/util/tagging' @@ -21,7 +20,6 @@ class Type include Puppet::Util::Errors include Puppet::Util::LogPaths include Puppet::Util::Logging - include Puppet::Util::Cacher include Puppet::FileCollection::Lookup include Puppet::Util::Tagging @@ -469,12 +467,6 @@ class Type Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags}.merge(options)) end - # Let the catalog determine whether a given cached value is - # still valid or has expired. - def expirer - catalog - end - # retrieve the 'should' value for a specified property def should(name) name = attr_alias(name) -- cgit From e74090468192697a6a2447dc6fcece3dd09a46f1 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:52:00 -0700 Subject: Remove Puppet::Util::Cacher use from Puppet::Indirector::Indirection Previously, indirections were storing their termini in a cached_attr, so that they could be easily cleared for tests. Because this provides no value outside of testing, we instead simply create an attr_reader for termini, and expire them manually in tests. Reviewed-By: Jacob Helwig --- lib/puppet/indirector/indirection.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb index d958a82ac..20b260b83 100644 --- a/lib/puppet/indirector/indirection.rb +++ b/lib/puppet/indirector/indirection.rb @@ -1,13 +1,11 @@ require 'puppet/util/docs' require 'puppet/indirector/envelope' require 'puppet/indirector/request' -require 'puppet/util/cacher' # The class that connects functional classes with their different collection # back-ends. Each indirection has a set of associated terminus classes, # each of which is a subclass of Puppet::Indirector::Terminus. class Puppet::Indirector::Indirection - include Puppet::Util::Cacher include Puppet::Util::Docs @@indirections = [] @@ -33,6 +31,8 @@ class Puppet::Indirector::Indirection attr_accessor :name, :model + attr_reader :termini + # Create and return our cache terminus. def cache raise(Puppet::DevError, "Tried to cache when no cache class was set") unless cache_class @@ -88,6 +88,7 @@ class Puppet::Indirector::Indirection def initialize(model, name, options = {}) @model = model @name = name + @termini = {} @cache_class = nil @terminus_class = nil @@ -313,7 +314,4 @@ class Puppet::Indirector::Indirection end klass.new end - - # Cache our terminus instances indefinitely, but make it easy to clean them up. - cached_attr(:termini) { Hash.new } end -- cgit From ce08cba9eb92abce7f7ab77dcf7eb9f9435d4040 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:52:27 -0700 Subject: Remove dead uses of Puppet::Util::Cacher from autoloader In the past, Puppet::Util::Autoload used a cached_attr for its 'searchpath'. However, it no longer does that, so its references to Puppet::Util::Cacher are unnecessary. Reviewed-By: Jacob Helwig --- lib/puppet/util/autoload.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index 6537a4a4e..2e8710ab1 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -1,5 +1,4 @@ require 'puppet/util/warnings' -require 'puppet/util/cacher' # Autoload paths, either based on names or all at once. class Puppet::Util::Autoload @@ -7,7 +6,6 @@ class Puppet::Util::Autoload include Puppet::Util include Puppet::Util::Warnings - include Puppet::Util::Cacher include Puppet::Util::Autoload::FileCache @autoloaders = {} -- cgit From 7048b4c4d8c4a8ad45caf6a02b263ac0a9fa333e Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:52:50 -0700 Subject: Remove use of Puppet::Util::Cacher in Puppet::SSL::Host This class was previously using a cached_attr for its 'localhost' attribute, representing the Puppet::SSL::Host entry corresponding to the cert in Puppet[:certname]. We now no longer expire this attribute. This has the effect that a change to certname during the lifetime of an agent will not be reflected in the certificate it uses. If this behavior is desired, it will need to be reimplemented another way. Reviewed-By: Jacob Helwig --- lib/puppet/ssl/host.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb index b9215effd..08a8ace1f 100644 --- a/lib/puppet/ssl/host.rb +++ b/lib/puppet/ssl/host.rb @@ -4,7 +4,6 @@ require 'puppet/ssl/key' require 'puppet/ssl/certificate' require 'puppet/ssl/certificate_request' require 'puppet/ssl/certificate_revocation_list' -require 'puppet/util/cacher' # The class that manages all aspects of our SSL certificates -- # private keys, public keys, requests, etc. @@ -27,14 +26,10 @@ class Puppet::SSL::Host # This accessor is used in instances for indirector requests to hold desired state attr_accessor :desired_state - class << self - include Puppet::Util::Cacher - - cached_attr(:localhost) do - result = new - result.generate unless result.certificate - result.key # Make sure it's read in - result + def self.localhost + @localhost ||= new.tap do |l| + l.generate unless l.certificate + l.key # Make sure it's read in end end -- cgit From d198fedf65e472b384666fc9ae3bef487852068a Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 11:53:06 -0700 Subject: Rework Puppet::Util::Cacher to only expire using TTLs We have removed every usage of cached_attr in which the attribute needs to be manually expired. Thus, the only meaningful behavior provided by Puppet::Util::Cacher is expiration based on TTLs. This commit reworks the cacher to only support that behavior. Rather than accepting an options hash, of which :ttl is the only available option, cached_attr now requires a second argument, which is the TTL. TTLs are now used to compute expirations, which are stored and used for expiring values. Previously, we stored a timestamp and used it and the TTL to determine whether the attribute was expired. This had the potentially undesirable side effect that the lifetime of a cached attribute could be extended after its insertion by modifying the TTL setting for the cache. Now, the lifetime of an attribute is determined when it is set, and is thereafter immutable, aside from deliberately re-setting the expiration for that particular attribute. Reviewed-By: Jacob Helwig --- lib/puppet/node/environment.rb | 10 ++---- lib/puppet/util/cacher.rb | 82 ++++++++---------------------------------- 2 files changed, 17 insertions(+), 75 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index 96fdc3c1e..f25bb65a9 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -95,7 +95,7 @@ class Puppet::Node::Environment # Cache the modulepath, so that we aren't searching through # all known directories all the time. - cached_attr(:modulepath, :ttl => Puppet[:filetimeout]) do + cached_attr(:modulepath, Puppet[:filetimeout]) do dirs = self[:modulepath].split(File::PATH_SEPARATOR) dirs = ENV["PUPPETLIB"].split(File::PATH_SEPARATOR) + dirs if ENV["PUPPETLIB"] validate_dirs(dirs) @@ -103,7 +103,7 @@ class Puppet::Node::Environment # Return all modules from this environment. # Cache the list, because it can be expensive to create. - cached_attr(:modules, :ttl => Puppet[:filetimeout]) do + cached_attr(:modules, Puppet[:filetimeout]) do module_names = modulepath.collect { |path| Dir.entries(path) }.flatten.uniq module_names.collect do |path| begin @@ -114,12 +114,6 @@ class Puppet::Node::Environment end.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 diff --git a/lib/puppet/util/cacher.rb b/lib/puppet/util/cacher.rb index 3dddec0d4..136c9973e 100644 --- a/lib/puppet/util/cacher.rb +++ b/lib/puppet/util/cacher.rb @@ -1,25 +1,6 @@ require 'monitor' module Puppet::Util::Cacher - module Expirer - attr_reader :timestamp - - # Cause all cached values to be considered expired. - def expire - @timestamp = Time.now - end - - # Is the provided timestamp earlier than our expiration timestamp? - # If it is, then the associated value is expired. - def dependent_data_expired?(ts) - return false unless timestamp - - timestamp > ts - end - end - - extend Expirer - # Our module has been extended in a class; we can only add the Instance methods, # which become *class* methods in the class. def self.extended(other) @@ -40,27 +21,26 @@ module Puppet::Util::Cacher module ClassMethods # Provide a means of defining an attribute whose value will be cached. # Must provide a block capable of defining the value if it's flushed.. - def cached_attr(name, options = {}, &block) + def cached_attr(name, ttl, &block) init_method = "init_#{name}" define_method(init_method, &block) + set_attr_ttl(name, ttl) + define_method(name) do cached_value(name) end define_method(name.to_s + "=") do |value| # Make sure the cache timestamp is set - cache_timestamp - value_cache.synchronize { value_cache[name] = value } - end - - if ttl = options[:ttl] - set_attr_ttl(name, ttl) + value_cache.synchronize do + value_cache[name] = value + set_expiration(name) + end end end def attr_ttl(name) - return nil unless @attr_ttls @attr_ttls[name] end @@ -72,57 +52,25 @@ module Puppet::Util::Cacher # Methods that get added to instances. module InstanceMethods - - def expire - # Only expire if we have an expirer. This is - # mostly so that we can comfortably handle cases - # like Puppet::Type instances, which use their - # catalog as their expirer, and they often don't - # have a catalog. - if e = expirer - e.expire - end - end - - def expirer - Puppet::Util::Cacher - end - private - def cache_timestamp - @cache_timestamp ||= Time.now - end - def cached_value(name) value_cache.synchronize do - # Allow a nil expirer, in which case we regenerate the value every time. - if expired_by_expirer?(name) - value_cache.clear - @cache_timestamp = Time.now - elsif expired_by_ttl?(name) - value_cache.delete(name) + if value_cache[name].nil? or expired_by_ttl?(name) + value_cache[name] = send("init_#{name}") + set_expiration(name) end - value_cache[name] = send("init_#{name}") unless value_cache.include?(name) value_cache[name] end end - def expired_by_expirer?(name) - if expirer.nil? - return true unless self.class.attr_ttl(name) - end - expirer.dependent_data_expired?(cache_timestamp) - end - def expired_by_ttl?(name) - return false unless self.class.respond_to?(:attr_ttl) - return false unless ttl = self.class.attr_ttl(name) - - @ttl_timestamps ||= {} - @ttl_timestamps[name] ||= Time.now + @attr_expirations[name] < Time.now + end - (Time.now - @ttl_timestamps[name]) > ttl + def set_expiration(name) + @attr_expirations ||= {} + @attr_expirations[name] = Time.now + self.class.attr_ttl(name) end def value_cache -- cgit From 61df3f7c39d74b82e37f48c3519293406036e1e9 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Thu, 21 Jul 2011 21:25:21 -0700 Subject: Don't use non-1.8.5-compatible methods 'Object#tap' and 'Dir.mktmpdir' These methods aren't available until Ruby 1.8.6 (Dir.mktmpdir) and Ruby 1.8.7 (Object#tap). Reviewed-By: Jacob Helwig --- lib/puppet/ssl/host.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb index 08a8ace1f..a06b1e275 100644 --- a/lib/puppet/ssl/host.rb +++ b/lib/puppet/ssl/host.rb @@ -27,10 +27,11 @@ class Puppet::SSL::Host attr_accessor :desired_state def self.localhost - @localhost ||= new.tap do |l| - l.generate unless l.certificate - l.key # Make sure it's read in - end + return @localhost if @localhost + @localhost = new + @localhost.generate unless @localhost.certificate + @localhost.key + @localhost end # This is the constant that people will use to mark that a given host is -- cgit From 1e0655e6bdbc872014abdffa5deacb334616e826 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Thu, 21 Jul 2011 15:34:52 -0700 Subject: (#7184) Centralize "find action for face" into Puppet::Face As part of moving to load actions first, and their associated face, when invoked from the command line, it makes sense to push the logic for finding the action and face down into the Puppet::Face implementation. This means that we can change the logic there without needing to update the public part of the CLI implementation, and that any further facades can use the same, correct, logic to locate the action for the face. Reviewed-By: Pieter van de Bruggen --- lib/puppet/application/face_base.rb | 3 ++- lib/puppet/interface.rb | 4 ++++ lib/puppet/interface/action.rb | 1 + lib/puppet/interface/face_collection.rb | 11 +++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/application/face_base.rb b/lib/puppet/application/face_base.rb index ea5ba4aaf..a111518f1 100644 --- a/lib/puppet/application/face_base.rb +++ b/lib/puppet/application/face_base.rb @@ -100,7 +100,8 @@ class Puppet::Application::FaceBase < Puppet::Application # action object it represents; if this is an invalid action name that # will be nil, and handled later. action_name = item.to_sym - @action = @face.get_action(action_name) + @action = Puppet::Face.find_action(@face.name, action_name) + @face = @action.face if @action end end diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb index 6c288f3c0..eba99d6be 100644 --- a/lib/puppet/interface.rb +++ b/lib/puppet/interface.rb @@ -64,6 +64,10 @@ class Puppet::Interface end face end + + def find_action(name, action, version = :current) + Puppet::Interface::FaceCollection.get_action_for_face(name, action, version) + end end def set_default_format(format) diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index fc1121eb6..ce9c60b49 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -38,6 +38,7 @@ class Puppet::Interface::Action def to_s() "#{@face}##{@name}" end attr_reader :name + attr_reader :face attr_accessor :default def default? !!@default diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index 4522824fd..ddc66f583 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -20,6 +20,17 @@ module Puppet::Interface::FaceCollection get_face(name, version) or load_face(name, version) end + def self.get_action_for_face(face_name, action_name, version) + # If the version they request specifically doesn't exist, don't search + # elsewhere. Usually this will start from :current and all... + return nil unless face = self[face_name, version] + unless action = face.get_action(action_name) + # ...we need to search for it bound to an o{lder,ther} version. + end + + return action + end + # get face from memory, without loading. def self.get_face(name, pattern) return nil unless @faces.has_key? name -- cgit From 2cd3bc47993fbd32a77ca9dfdd51353f2dfbcb58 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Thu, 21 Jul 2011 16:34:20 -0700 Subject: (#7184) Find actions bound to other versions of Faces. When we first touch a Face, we load all the available Actions from disk. Given they define themselves against a specific version of a Face, they are automatically available tied to the correct version; this makes it trivially possible to locate those on demand and return them. Now, we have the ability to find and, consequently, invoke Actions on older versions of Faces. We don't load enough context, though: the older face will only have external Actions defined, not anything core. Reviewed-By: Pieter van de Bruggen --- lib/puppet/interface/face_collection.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index ddc66f583..868997b67 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -20,12 +20,19 @@ module Puppet::Interface::FaceCollection get_face(name, version) or load_face(name, version) end - def self.get_action_for_face(face_name, action_name, version) + def self.get_action_for_face(name, action_name, version) + name = underscorize(name) + # If the version they request specifically doesn't exist, don't search # elsewhere. Usually this will start from :current and all... - return nil unless face = self[face_name, version] + return nil unless face = self[name, version] unless action = face.get_action(action_name) - # ...we need to search for it bound to an o{lder,ther} version. + # ...we need to search for it bound to an o{lder,ther} version. Since + # we load all actions when the face is first references, this will be in + # memory in the known set of versions of the face. + (@faces[name].keys - [ :current ]).sort.reverse.each do |version| + break if action = @faces[name][version].get_action(action_name) + end end return action -- cgit From 532c4f37e4f8289cf4a9871ebc0cb5086c2ba26a Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Thu, 21 Jul 2011 16:43:16 -0700 Subject: (#7184) Load the core of obsolete versions of Faces. When we define an action on an older version of a Face, we must be sure to directly load the core of that version, not just define it with the external Action(s) that it had. Otherwise we break our contract, which is that any core Actions for a specific version will be available to your external Action for as long as we support that core version. Reviewed-By: Pieter van de Bruggen --- lib/puppet/interface/face_collection.rb | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index 868997b67..b1f6ba398 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -56,9 +56,7 @@ module Puppet::Interface::FaceCollection # # We use require to avoid executing the code multiple times, like any # other Ruby library that we might want to use. --daniel 2011-04-06 - begin - require "puppet/face/#{name}" - + if safely_require name then # If we wanted :current, we need to index to find that; direct version # requests just workâ„¢ as they go. --daniel 2011-04-06 if version == :current then @@ -90,18 +88,32 @@ module Puppet::Interface::FaceCollection latest_ver = @faces[name].keys.sort.last @faces[name][:current] = @faces[name][latest_ver] end - rescue LoadError => e - raise unless e.message =~ %r{-- puppet/face/#{name}$} - # ...guess we didn't find the file; return a much better problem. - rescue SyntaxError => e - raise unless e.message =~ %r{puppet/face/#{name}\.rb:\d+: } - Puppet.err "Failed to load face #{name}:\n#{e}" - # ...but we just carry on after complaining. + end + + unless version == :current or get_face(name, version) + # Try an obsolete version of the face, if needed, to see if that helps? + safely_require name, version end return get_face(name, version) end + def self.safely_require(name, version = nil) + path = File.join 'puppet' ,'face', version.to_s, name.to_s + require path + true + + rescue LoadError => e + raise unless e.message =~ %r{-- #{path}$} + # ...guess we didn't find the file; return a much better problem. + nil + rescue SyntaxError => e + raise unless e.message =~ %r{#{path}\.rb:\d+: } + Puppet.err "Failed to load face #{name}:\n#{e}" + # ...but we just carry on after complaining. + nil + end + def self.register(face) @faces[underscorize(face.name)][face.version] = face end -- cgit From 82476e8be41b62ce1767ab6854a72b481b917380 Mon Sep 17 00:00:00 2001 From: Cameron Thomas Date: Fri, 22 Jul 2011 15:09:13 -0700 Subject: Add basic service provider for Windows This provider allows us to query the system state through "puppet resource", and manage the ensure, and enabled properties of services on Windows. This also adds support for a new enabled value of 'manual' on Windows only. With this we support the three major start types for services on Windows, with the following mapping of enabled to start type: true => Automatic false => Disabled manual => Manual (Demand) We use the win32-service gem to provide access to the Windows APIs for our operations. This does add a new gem requirement for running Puppet on Windows, but we were already requiring some gems from the same suite that win32-service is a part of. When referring to a service, the simple service name must be used, instead of the display name. For example, "snmptrap", instead of "SNMP Trap". All system services are reported in 'puppet resource service', including those started prior to run level 3 (system, device drivers, etc.). These services should probably not be managed, without careful thought and planning. This currently does not support being able to move a service from {enabled => false, ensure => stopped} to {enabled => true, ensure => running} (or enabled => manual) in a single Puppet run, since Puppet currently always tries to sync ensure before any other property. Because of this, the puppet run will fail every time, and the service must first be managed as {ensure => stopped, enabled => true} (or enabled => manual), before it can be managed as running and automatic start or manual start. Reviewed by: Jacob Helwig --- lib/puppet/feature/base.rb | 3 +- lib/puppet/provider/service/windows.rb | 101 +++++++++++++++++++++++++++++++++ lib/puppet/type/service.rb | 10 ++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 lib/puppet/provider/service/windows.rb (limited to 'lib') diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb index 9ed3deef5..b4b1313f8 100644 --- a/lib/puppet/feature/base.rb +++ b/lib/puppet/feature/base.rb @@ -48,8 +48,9 @@ Puppet.features.add(:microsoft_windows) do require 'sys/admin' require 'win32/process' require 'win32/dir' + require 'win32/service' rescue LoadError => err - warn "Cannot run on Microsoft Windows without the sys-admin, win32-process & win32-dir gems: #{err}" unless Puppet.features.posix? + warn "Cannot run on Microsoft Windows without the sys-admin, win32-process, win32-dir & win32-service gems: #{err}" unless Puppet.features.posix? end end diff --git a/lib/puppet/provider/service/windows.rb b/lib/puppet/provider/service/windows.rb new file mode 100644 index 000000000..09754ffda --- /dev/null +++ b/lib/puppet/provider/service/windows.rb @@ -0,0 +1,101 @@ +# Windows Service Control Manager (SCM) provider + +require 'win32/service' if Puppet.features.microsoft_windows? + +Puppet::Type.type(:service).provide :windows do + + desc "Support for Windows Service Control Manager (SCM). + + Services are controlled according to win32-service gem. + + * All SCM operations (start/stop/enable/disable/query) are supported. + + * Control of service groups (dependencies) is not yet supported." + + defaultfor :operatingsystem => :windows + confine :operatingsystem => :windows + + has_feature :refreshable + + def enable + w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_AUTO_START ) + raise Puppet::Error.new("Win32 service enable of #{@resource[:name]} failed" ) if( w32ss.nil? ) + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot enable #{@resource[:name]}, error was: #{detail}" ) + end + + def disable + w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DISABLED ) + raise Puppet::Error.new("Win32 service disable of #{@resource[:name]} failed" ) if( w32ss.nil? ) + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot disable #{@resource[:name]}, error was: #{detail}" ) + end + + def manual_start + w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DEMAND_START ) + raise Puppet::Error.new("Win32 service manual enable of #{@resource[:name]} failed" ) if( w32ss.nil? ) + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot enable #{@resource[:name]} for manual start, error was: #{detail}" ) + end + + def enabled? + w32ss = Win32::Service.config_info( @resource[:name] ) + raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceConfigInfo ) ) + Puppet.debug("Service #{@resource[:name]} start type is #{w32ss.start_type}") + case w32ss.start_type + when Win32::Service.get_start_type(Win32::Service::SERVICE_AUTO_START), + Win32::Service.get_start_type(Win32::Service::SERVICE_BOOT_START), + Win32::Service.get_start_type(Win32::Service::SERVICE_SYSTEM_START) + true + when Win32::Service.get_start_type(Win32::Service::SERVICE_DEMAND_START) + :manual + when Win32::Service.get_start_type(Win32::Service::SERVICE_DISABLED) + false + else + raise Puppet::Error.new("Unknown start type: #{w32ss.start_type}") + end + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot get start type for #{@resource[:name]}, error was: #{detail}" ) + end + + def start + Win32::Service.start( @resource[:name] ) + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot start #{@resource[:name]}, error was: #{detail}" ) + end + + def stop + Win32::Service.stop( @resource[:name] ) + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot start #{@resource[:name]}, error was: #{detail}" ) + end + + def restart + self.stop + self.start + end + + def status + w32ss = Win32::Service.status( @resource[:name] ) + raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceStatus ) ) + state = case w32ss.current_state + when "stopped", "pause pending", "stop pending", "paused" then :stopped + when "running", "continue pending", "start pending" then :running + else + raise Puppet::Error.new("Unknown service state '#{w32ss.current_state}' for service '#{@resource[:name]}'") + end + Puppet.debug("Service #{@resource[:name]} is #{w32ss.current_state}") + return state + rescue Win32::Service::Error => detail + raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" ) + end + + # returns all providers for all existing services and startup state + def self.instances + srvcs = [] + Win32::Service.services.collect{ |s| + srvcs << new(:name => s.service_name) + } + srvcs + end +end diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 5a2c69b87..53ff72867 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -49,9 +49,19 @@ module Puppet provider.disable end + newvalue(:manual, :event => :service_manual_start) do + provider.manual_start + end + def retrieve provider.enabled? end + + validate do |value| + if value == :manual and !Puppet.features.microsoft_windows? + raise Puppet::Error.new("Setting enable to manual is only supported on Microsoft Windows.") + end + end end # Handle whether the service should actually be running right now. -- cgit From 77441be2299bbb96ab9f048855b0fd4c16eb7b5a Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Fri, 22 Jul 2011 14:32:00 -0700 Subject: (#8561) Unify validation and modification of action arguments. Rather than having multiple, separate operations that modify and validate the arguments to an action, a single pass makes sense. This also means less walks across the set of data, and a few less expensive method calls in Ruby. Additionally, we work on a duplicate of the arguments hash rather than directly modifying the original. Because everything we do is at the top level key/value mapping, this is sufficient to isolate the original. While mostly theoretical, we now don't mutilate the hash passed in, so the user won't get nastily surprised by the fact that we could have done so. Reviewed-By: Pieter van de Bruggen --- lib/puppet/interface/action.rb | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index ce9c60b49..2a2f48e03 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -200,8 +200,7 @@ def #{@name}(#{decl.join(", ")}) options = args.last action = get_action(#{name.inspect}) - action.add_default_args(args) - action.validate_args(args) + args = action.validate_and_clean(args) __invoke_decorations(:before, action, args, options) rval = self.__send__(#{internal_name.inspect}, *args) __invoke_decorations(:after, action, args, options) @@ -254,15 +253,19 @@ WRAPPER option end - def add_default_args(args) + def validate_and_clean(original_args) + # Make a shallow copy, so as not to surprise callers. We only modify the + # top level keys and all, so this should be sufficient without being too + # costly overall. + args = original_args.dup + + # Inject default arguments. options.map {|x| get_option(x) }.each do |option| if option.has_default? and not option.aliases.any? {|x| args.last.has_key? x} args.last[option.name] = option.default end end - end - def validate_args(args) # Check for multiple aliases for the same option... args.last.keys.each do |name| # #7290: If this isn't actually an option, ignore it for now. We should @@ -281,8 +284,12 @@ WRAPPER get_option(name) end.select(&:required?).collect(&:name) - args.last.keys - return if required.empty? - raise ArgumentError, "The following options are required: #{required.join(', ')}" + unless required.empty? + raise ArgumentError, "The following options are required: #{required.join(', ')}" + end + + # All done. + return args end ######################################################################## -- cgit From 82e5fa9561e2d4cb1d699a41c14f50953d8f2d97 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Fri, 22 Jul 2011 15:15:38 -0700 Subject: (#8561, #7290) Implement the option contract fully. Rewrite the process of validating and updating the options to fully reflect the contract - we fail if there are unknown options passed, report nicely errors of duplicate names, pass only the canonical names to the action code, and generally enforce nicely. Reviewed-By: Pieter van de Bruggen --- lib/puppet/interface/action.rb | 84 ++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 35 deletions(-) (limited to 'lib') diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index 2a2f48e03..bd47a36ea 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -196,14 +196,12 @@ class Puppet::Interface::Action wrapper = < Date: Fri, 22 Jul 2011 15:24:16 -0700 Subject: maint: don't print inside action implementations. Rather than printing directly, we should return the data from the Action and allow the facade to route that to the user directly. Reviewed-By: Pieter van de Bruggen --- lib/puppet/indirector/face.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/puppet/indirector/face.rb b/lib/puppet/indirector/face.rb index ead3f4b46..b4cac5c51 100644 --- a/lib/puppet/indirector/face.rb +++ b/lib/puppet/indirector/face.rb @@ -86,11 +86,11 @@ class Puppet::Indirector::Face < Puppet::Face run mode with the '--mode' option. EOT - when_invoked do |*args| + when_invoked do |options| if t = indirection.terminus_class - puts "Run mode '#{Puppet.run_mode.name}': #{t}" + "Run mode '#{Puppet.run_mode.name}': #{t}" else - $stderr.puts "No default terminus class for run mode '#{Puppet.run_mode.name}'" + "No default terminus class for run mode '#{Puppet.run_mode.name}'" end end end -- cgit From ae360034c07f9b16467f5ae245ac6d037789ee13 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Fri, 22 Jul 2011 16:26:10 -0700 Subject: (#7290) Update indirected Faces to avoid unknown options. Now that we enforce that options must be declared, the model we exposed in the Ruby API (but not the CLI facade) was that you could pass additional arguments to the indirection method by passing them as unknown options doesn't work. Instead, explicitly declare an option, `extra`, that accepts the final argument to be passed direct to the indirection. This makes things work smoothly, as well as making it possible (once you can input a hash on the command line) to invoke extra arguments from the facade too... Reviewed-By: Pieter van de Bruggen --- lib/puppet/indirector/face.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/puppet/indirector/face.rb b/lib/puppet/indirector/face.rb index b4cac5c51..adb6b688b 100644 --- a/lib/puppet/indirector/face.rb +++ b/lib/puppet/indirector/face.rb @@ -48,16 +48,26 @@ class Puppet::Indirector::Face < Puppet::Face return result end + option "--extra HASH" do + summary "Extra arguments to pass to the indirection request" + description <<-end + A terminus can take additional arguments to refine the operation, which + are passed as an arbitrary hash to the back-end. Anything passed as + the extra value is just send direct to the back-end. + end + default_to do Hash.new end + end + action :destroy do summary "Delete an object." arguments "" - when_invoked { |key, options| call_indirection_method(:destroy, key, options) } + when_invoked {|key, options| call_indirection_method :destroy, key, options[:extra] } end action :find do summary "Retrieve an object by name." arguments "" - when_invoked { |key, options| call_indirection_method(:find, key, options) } + when_invoked {|key, options| call_indirection_method :find, key, options[:extra] } end action :save do @@ -68,13 +78,13 @@ class Puppet::Indirector::Face < Puppet::Face currently accept data from STDIN, save actions cannot currently be invoked from the command line. EOT - when_invoked { |key, options| call_indirection_method(:save, key, options) } + when_invoked {|key, options| call_indirection_method :save, key, options[:extra] } end action :search do summary "Search for an object or retrieve multiple objects." arguments "" - when_invoked { |key, options| call_indirection_method(:search, key, options) } + when_invoked {|key, options| call_indirection_method :search, key, options[:extra] } end # Print the configuration for the current terminus class -- cgit From 10e05ad302d1b2d93f5da070d612817729473009 Mon Sep 17 00:00:00 2001 From: Pieter van de Bruggen Date: Mon, 25 Jul 2011 12:05:31 -0700 Subject: (#7266) Move Certificate option validation into face. The validation for the ca_location option on the certificate application continued to hang around on the application long after the face realized its potential to take responsibility for itself. This change moves (and adds) validation code as appropriate into the Face. Reviewed-By: Matt Robinson --- lib/puppet/application/certificate.rb | 5 ----- lib/puppet/face/certificate.rb | 22 +++++++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/puppet/application/certificate.rb b/lib/puppet/application/certificate.rb index eacb830b2..de5b2c499 100644 --- a/lib/puppet/application/certificate.rb +++ b/lib/puppet/application/certificate.rb @@ -2,11 +2,6 @@ require 'puppet/application/indirection_base' class Puppet::Application::Certificate < Puppet::Application::IndirectionBase def setup - unless options[:ca_location] - raise ArgumentError, "You must have a CA location specified;\n" + - "use --ca-location to specify the location (remote, local, only)" - end - location = Puppet::SSL::Host.ca_location if location == :local && !Puppet::SSL::CertificateAuthority.ca? self.class.run_mode("master") diff --git a/lib/puppet/face/certificate.rb b/lib/puppet/face/certificate.rb index 9a306da37..5e176e27e 100644 --- a/lib/puppet/face/certificate.rb +++ b/lib/puppet/face/certificate.rb @@ -6,7 +6,7 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do license "Apache 2 license; see COPYING" summary "Provide access to the CA for certificate management." - description <<-'EOT' + description <<-EOT This subcommand interacts with a local or remote Puppet certificate authority. Currently, its behavior is not a full superset of `puppet cert`; specifically, it is unable to mimic puppet cert's "clean" option, @@ -15,8 +15,9 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do EOT option "--ca-location LOCATION" do + required summary "Which certificate authority to use (local or remote)." - description <<-'EOT' + description <<-EOT Whether to act on the local certificate authority or one provided by a remote puppet master. Allowed values are 'local' and 'remote.' @@ -24,6 +25,9 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do EOT before_action do |action, args, options| + unless [:remote, :local, :only].include? options[:ca_location].to_sym + raise ArgumentError, "Valid values for ca-location are 'remote', 'local', 'only'." + end Puppet::SSL::Host.ca_location = options[:ca_location].to_sym end end @@ -32,7 +36,7 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do summary "Generate a new certificate signing request." arguments "" returns "Nothing." - description <<-'EOT' + description <<-EOT Generates and submits a certificate signing request (CSR) for the specified host. This CSR will then have to be signed by a user with the proper authorization on the certificate authority. @@ -41,7 +45,7 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do primarily useful for requesting certificates for individual users and external applications. EOT - examples <<-'EOT' + examples <<-EOT Request a certificate for "somenode" from the site's CA: $ puppet certificate generate somenode.puppetlabs.lan --ca-location remote @@ -56,7 +60,7 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do action :list do summary "List all certificate signing requests." - returns <<-'EOT' + returns <<-EOT An array of #inspect output from CSR objects. This output is currently messy, but does contain the names of nodes requesting certificates. This action returns #inspect strings even when used @@ -73,10 +77,10 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do action :sign do summary "Sign a certificate signing request for HOST." arguments "" - returns <<-'EOT' + returns <<-EOT A string that appears to be (but isn't) an x509 certificate. EOT - examples <<-'EOT' + examples <<-EOT Sign somenode.puppetlabs.lan's certificate: $ puppet certificate sign somenode.puppetlabs.lan --ca-location remote @@ -93,7 +97,7 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do find = get_action(:find) find.summary "Retrieve a certificate." find.arguments "" - find.returns <<-'EOT' + find.returns <<-EOT An x509 SSL certificate. You will usually want to render this as a string (--render-as s). @@ -105,7 +109,7 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do destroy.summary "Delete a certificate." destroy.arguments "" destroy.returns "Nothing." - destroy.description <<-'EOT' + destroy.description <<-EOT Deletes a certificate. This action currently only works on the local CA. EOT -- cgit From f484851b7528c0fcf1254d25a022e9cb7ef9b3bd Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 19 Jul 2011 14:11:37 -0700 Subject: maint: Add debug logging when the master receives a report It's always bothered me that when running puppet inspect (or any application that produces a report really) the master gives no indication that anything happened when it processes the report. Reviewed-by: Max Martin --- lib/puppet/indirector/report/processor.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/indirector/report/processor.rb b/lib/puppet/indirector/report/processor.rb index 88fe4b487..81b379eb8 100644 --- a/lib/puppet/indirector/report/processor.rb +++ b/lib/puppet/indirector/report/processor.rb @@ -20,9 +20,11 @@ class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code # LAK:NOTE This isn't necessarily the best design, but it's backward # compatible and that's good enough for now. def process(report) + Puppet.debug "Recieved report to process from #{report.host}" return if Puppet[:reports] == "none" reports.each do |name| + Puppet.debug "Processing report from #{report.host} with processor #{name}" if mod = Puppet::Reports.report(name) # We have to use a dup because we're including a module in the # report. -- cgit From 3165364e20fc008b3997effafb290fe47c13bf42 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 19 Jul 2011 14:18:43 -0700 Subject: maint: Adding logging to include environment when source fails Reviewed-by: Max Martin --- lib/puppet/type/file/source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 6ebec51fe..2fb65bbad 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -154,7 +154,7 @@ module Puppet fail detail, "Could not retrieve file metadata for #{source}: #{detail}" end end - fail "Could not retrieve information from source(s) #{value.join(", ")}" unless result + fail "Could not retrieve information from environment #{Puppet[:environment]} source(s) #{value.join(", ")}" unless result result end -- cgit From 89c021cac52a4bdecbe490772cb73cef9ef049c5 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 19 Jul 2011 14:19:26 -0700 Subject: (#8418) Fix inspect app to have the correct run_mode Requiring puppet before the run_mode has been set by the application causes the default run_mode of 'user' to be set instead of what the application wants. This leads to the incorrect default settings to be used, which lead to inspect not being able to properly retrieve file metadata from a fileserver. Reviewed-by: Max Martin --- lib/puppet/application/inspect.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb index ce32c661c..2260feed7 100644 --- a/lib/puppet/application/inspect.rb +++ b/lib/puppet/application/inspect.rb @@ -1,6 +1,4 @@ -require 'puppet' require 'puppet/application' -require 'puppet/file_bucket/dipper' class Puppet::Application::Inspect < Puppet::Application @@ -97,6 +95,11 @@ Licensed under the GNU General Public License version 2 Puppet::Resource::Catalog.terminus_class = :yaml end + def preinit + require 'puppet' + require 'puppet/file_bucket/dipper' + end + def run_command benchmark(:notice, "Finished inspection") do retrieval_starttime = Time.now -- cgit From cc2c3edbb6907e8be03792a83f2b81fb839f5189 Mon Sep 17 00:00:00 2001 From: Pieter van de Bruggen Date: Mon, 25 Jul 2011 15:13:28 -0700 Subject: (Maint.) Unquoting HEREDOCs. The additional quotation marks frustrate certain syntax highlighters, and are completely unnecessary for their use. Reviewed-By: Daniel Pittman --- lib/puppet/face/certificate_request.rb | 10 +++++----- lib/puppet/face/certificate_revocation_list.rb | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/puppet/face/certificate_request.rb b/lib/puppet/face/certificate_request.rb index 774821f12..1fb4e81cc 100644 --- a/lib/puppet/face/certificate_request.rb +++ b/lib/puppet/face/certificate_request.rb @@ -5,7 +5,7 @@ Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do license "Apache 2 license; see COPYING" summary "Manage certificate requests." - description <<-'EOT' + description <<-EOT This subcommand retrieves and submits certificate signing requests (CSRs). EOT @@ -15,14 +15,14 @@ Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do find = get_action(:find) find.summary "Retrieve a single CSR." find.arguments "" - find.returns <<-'EOT' + find.returns <<-EOT A single certificate request. When used from the Ruby API, returns a Puppet::SSL::CertificateRequest object. RENDERING ISSUES: In most cases, you will want to render this as a string ('--render-as s'). EOT - find.examples <<-'EOT' + find.examples <<-EOT Retrieve a single CSR from the puppet master's CA: $ puppet certificate_request find somenode.puppetlabs.lan --terminus rest @@ -31,10 +31,10 @@ Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do search = get_action(:search) search.summary "Retrieve all outstanding CSRs." search.arguments "" - search.returns <<-'EOT' A list of certificate requests; be sure to to render this as a string ('--render-as s'). When used from the Ruby API, returns an array of Puppet::SSL::CertificateRequest objects. + search.returns <<-EOT EOT search.short_description <<-EOT Retrieves all outstanding certificate signing requests. Due to a known bug, @@ -44,7 +44,7 @@ Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do Although this action always returns all CSRs, it requires a dummy search key; this is a known bug. EOT - search.examples <<-'EOT' + search.examples <<-EOT Retrieve all CSRs from the local CA (similar to 'puppet cert list'): $ puppet certificate_request search x --terminus ca diff --git a/lib/puppet/face/certificate_revocation_list.rb b/lib/puppet/face/certificate_revocation_list.rb index f58368f75..1623d4342 100644 --- a/lib/puppet/face/certificate_revocation_list.rb +++ b/lib/puppet/face/certificate_revocation_list.rb @@ -5,7 +5,7 @@ Puppet::Indirector::Face.define(:certificate_revocation_list, '0.0.1') do license "Apache 2 license; see COPYING" summary "Manage the list of revoked certificates." - description <<-'EOT' + description <<-EOT This subcommand is primarily for retrieving the certificate revocation list from the CA. EOT @@ -13,7 +13,7 @@ Puppet::Indirector::Face.define(:certificate_revocation_list, '0.0.1') do find = get_action(:find) find.summary "Retrieve the certificate revocation list." find.arguments "" - find.returns <<-'EOT' + find.returns <<-EOT The certificate revocation list. When used from the Ruby API: returns an OpenSSL::X509::CRL object. @@ -28,7 +28,7 @@ Puppet::Indirector::Face.define(:certificate_revocation_list, '0.0.1') do Although this action always returns the CRL from the specified terminus, it requires a dummy argument; this is a known bug. EOT - find.examples <<-'EXAMPLES' + find.examples <<-EXAMPLES Retrieve a copy of the puppet master's CRL: $ puppet certificate_revocation_list find crl --terminus rest @@ -38,7 +38,7 @@ Puppet::Indirector::Face.define(:certificate_revocation_list, '0.0.1') do destroy.summary "Delete the certificate revocation list." destroy.arguments "" destroy.returns "Nothing." - destroy.description <<-'EOT' + destroy.description <<-EOT Deletes the certificate revocation list. This cannot be done over REST, but it is possible to delete the locally cached copy or the local CA's copy of the CRL. -- cgit From 0366b1856489f01f1c46519dfebbda3a8676f933 Mon Sep 17 00:00:00 2001 From: Pieter van de Bruggen Date: Mon, 25 Jul 2011 15:15:51 -0700 Subject: (#7293) Set default format for SSL-related faces. By default, the SSL-related faces should all render a strings, not with `Object#inspect`. Reviewed-By: Daniel Pittman --- lib/puppet/face/certificate.rb | 4 ++-- lib/puppet/face/certificate_request.rb | 10 ++++------ lib/puppet/face/certificate_revocation_list.rb | 4 +--- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/puppet/face/certificate.rb b/lib/puppet/face/certificate.rb index 5e176e27e..8019b6bea 100644 --- a/lib/puppet/face/certificate.rb +++ b/lib/puppet/face/certificate.rb @@ -97,9 +97,9 @@ Puppet::Indirector::Face.define(:certificate, '0.0.1') do find = get_action(:find) find.summary "Retrieve a certificate." find.arguments "" + find.render_as = :s find.returns <<-EOT - An x509 SSL certificate. You will usually want to render this as a - string (--render-as s). + An x509 SSL certificate. Note that this action has a side effect of caching a copy of the certificate in Puppet's `ssldir`. diff --git a/lib/puppet/face/certificate_request.rb b/lib/puppet/face/certificate_request.rb index 1fb4e81cc..cf342d51a 100644 --- a/lib/puppet/face/certificate_request.rb +++ b/lib/puppet/face/certificate_request.rb @@ -15,12 +15,10 @@ Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do find = get_action(:find) find.summary "Retrieve a single CSR." find.arguments "" + find.render_as = :s find.returns <<-EOT A single certificate request. When used from the Ruby API, returns a Puppet::SSL::CertificateRequest object. - - RENDERING ISSUES: In most cases, you will want to render this as a string - ('--render-as s'). EOT find.examples <<-EOT Retrieve a single CSR from the puppet master's CA: @@ -31,10 +29,10 @@ Puppet::Indirector::Face.define(:certificate_request, '0.0.1') do search = get_action(:search) search.summary "Retrieve all outstanding CSRs." search.arguments "" - A list of certificate requests; be sure to to render this as a string - ('--render-as s'). When used from the Ruby API, returns an array of - Puppet::SSL::CertificateRequest objects. + search.render_as = :s search.returns <<-EOT + A list of certificate requests. When used from the Ruby API, returns an + array of Puppet::SSL::CertificateRequest objects. EOT search.short_description <<-EOT Retrieves all outstanding certificate signing requests. Due to a known bug, diff --git a/lib/puppet/face/certificate_revocation_list.rb b/lib/puppet/face/certificate_revocation_list.rb index 1623d4342..022323b29 100644 --- a/lib/puppet/face/certificate_revocation_list.rb +++ b/lib/puppet/face/certificate_revocation_list.rb @@ -13,12 +13,10 @@ Puppet::Indirector::Face.define(:certificate_revocation_list, '0.0.1') do find = get_action(:find) find.summary "Retrieve the certificate revocation list." find.arguments "" + find.render_as = :s find.returns <<-EOT The certificate revocation list. When used from the Ruby API: returns an OpenSSL::X509::CRL object. - - RENDERING ISSUES: this should usually be rendered as a string - ('--render-as s'). EOT find.short_description <<-EOT Retrieves the certificate revocation list. Due to a known bug, this action -- cgit From 778127d0c3cf01701d227ec88a8e5e6550638c35 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Mon, 25 Jul 2011 16:18:54 -0700 Subject: maint: Fix cert app to print help and exit if no subcommand In 2.6.x this was the behavior, but the changes to the way options parsing worked in 2.7.x to support faces changed the behavior of how help was called. This resulted in the follow unhelpful error message when you just called `puppet cert`: /Users/matthewrobinson/work/puppet/lib/puppet/ssl/certificate_authority/interface.rb:85:in `method=' Invalid method to apply Reviewed-by: Pieter van de Bruggen --- lib/puppet/application/cert.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/application/cert.rb b/lib/puppet/application/cert.rb index 162672b6a..330fba8bd 100644 --- a/lib/puppet/application/cert.rb +++ b/lib/puppet/application/cert.rb @@ -218,7 +218,8 @@ Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License if sub = self.command_line.args.shift then self.subcommand = sub else - help + puts help + exit end end result -- cgit From fb2ffd6879f4c885fe29f70e3cf9bcde89cdc8e9 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Mon, 25 Jul 2011 15:34:56 -0700 Subject: (#8596) Detect resource alias conflicts when titles do not match The introduction of composite namevars caused the resource title used in resource aliases to be set as an array, even when the resource only had one namevar. This would fail to conflict with non-alias entries in the resource table, which used a string for the title, even though the single element array contained the same string. Now, we flatten the key used in the resource table, so that single element arrays are represented as strings, and will properly conflict with resource titles. Paired-With: Jacob Helwig --- lib/puppet/resource/catalog.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index 0a63ff172..2fdd19b0c 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -98,7 +98,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph resource.ref =~ /^(.+)\[/ class_name = $1 || resource.class.name - newref = [class_name, key] + newref = [class_name, key].flatten if key.is_a? String ref_string = "#{class_name}[#{key}]" @@ -111,7 +111,10 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph # isn't sufficient. if existing = @resource_table[newref] return if existing == resource - raise(ArgumentError, "Cannot alias #{resource.ref} to #{key.inspect}; resource #{newref.inspect} already exists") + resource_definition = " at #{resource.file}:#{resource.line}" if resource.file and resource.line + existing_definition = " at #{existing.file}:#{existing.line}" if existing.file and existing.line + msg = "Cannot alias #{resource.ref} to #{key.inspect}#{resource_definition}; resource #{newref.inspect} already defined#{existing_definition}" + raise ArgumentError, msg end @resource_table[newref] = resource @aliases[resource.ref] ||= [] @@ -377,7 +380,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph res = Puppet::Resource.new(nil, type) end title_key = [res.type, res.title.to_s] - uniqueness_key = [res.type, res.uniqueness_key] + uniqueness_key = [res.type, res.uniqueness_key].flatten @resource_table[title_key] || @resource_table[uniqueness_key] end -- cgit From 1d4acb5afda61b1f2c05223afff19c68248a3996 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 19 Jul 2011 11:27:03 -0700 Subject: maint: Suggest where to start troubleshooting SSL error message Much like the infamous "hostname was not match" error message, there's another SSL error that people run into that isn't clear how to troubleshoot. err: Could not send report: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed. As far as I can tell this only ever happens when the clock is off on the master or client. People seem to think it will happen other times, but I haven't been able to reproduce it other ways - missing private key, revoked cert, offline CA all have their own errors. I googled around and the only thing I've seen for this error in relation to puppet is the time sync problem. So the error message text just has some additional info to suggest you check your clocks. Reviewed-by: Nick Lewis --- lib/puppet/indirector/rest.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb index 8018fe8e3..19daff51d 100644 --- a/lib/puppet/indirector/rest.rb +++ b/lib/puppet/indirector/rest.rb @@ -93,7 +93,9 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus http_connection.send(method, *args) rescue OpenSSL::SSL::SSLError => error - if error.message.include? "hostname was not match" + if error.message.include? "certificate verify failed" + raise Puppet::Error, "#{error.message}. This is often because the time is out of sync on the server or client" + elsif error.message.include? "hostname was not match" raise unless cert = peer_certs.find { |c| c.name !~ /^puppet ca/i } valid_certnames = [cert.name, *cert.alternate_names].uniq -- cgit From 0c385f1fb436ab6f667693d347f711470305a019 Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Mon, 30 May 2011 20:17:11 +0200 Subject: Fix #5010 - Allow leading whitespace in auth.conf The regex used to detect ACE is too lax and would allow trailing spaces to sneak in, which in turn would confuse the ACE parser. Signed-off-by: Brice Figureau --- lib/puppet/network/authconfig.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/network/authconfig.rb b/lib/puppet/network/authconfig.rb index 4ba89fa71..61fb24ded 100644 --- a/lib/puppet/network/authconfig.rb +++ b/lib/puppet/network/authconfig.rb @@ -130,6 +130,7 @@ module Puppet end def parse_right_directive(right, var, value, count) + value.strip! case var when "allow" modify_right(right, :allow, value, "allowing %s access", count) @@ -159,6 +160,7 @@ module Puppet def modify_right(right, method, value, msg, count) value.split(/\s*,\s*/).each do |val| begin + val.strip! right.info msg % val right.send(method, val) rescue AuthStoreError => detail -- cgit From 6401dfe5602fd39cc59ec1f1b3822110e4ad864a Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Mon, 30 May 2011 20:31:14 +0200 Subject: Fix #6026 - security file should support inline comments Auth.conf, namespaceauth.conf and fileserver.conf were not supporting trailing inlined comments. Also this commit fixes some indentation and error management. Signed-off-by: Brice Figureau --- lib/puppet/file_serving/configuration/parser.rb | 19 ++++++------------- lib/puppet/network/authconfig.rb | 2 +- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_serving/configuration/parser.rb b/lib/puppet/file_serving/configuration/parser.rb index 334201d37..83b75e28f 100644 --- a/lib/puppet/file_serving/configuration/parser.rb +++ b/lib/puppet/file_serving/configuration/parser.rb @@ -24,9 +24,10 @@ class Puppet::FileServing::Configuration::Parser < Puppet::Util::LoadedFile when /^\s*$/; next # skip blank lines when /\[([-\w]+)\]/ mount = newmount($1) - when /^\s*(\w+)\s+(.+)$/ + when /^\s*(\w+)\s+(.+?)(\s*#.*)?$/ var = $1 value = $2 + value.strip! raise(ArgumentError, "Fileserver configuration file does not use '=' as a separator") if value =~ /^=/ case var when "path" @@ -58,12 +59,8 @@ class Puppet::FileServing::Configuration::Parser < Puppet::Util::LoadedFile begin mount.info "allowing #{val} access" mount.allow(val) - rescue AuthStoreError => detail - - raise ArgumentError.new( - detail.to_s, - - @count, file) + rescue Puppet::AuthStoreError => detail + raise ArgumentError.new(detail.to_s, @count, file) end } end @@ -75,12 +72,8 @@ class Puppet::FileServing::Configuration::Parser < Puppet::Util::LoadedFile begin mount.info "denying #{val} access" mount.deny(val) - rescue AuthStoreError => detail - - raise ArgumentError.new( - detail.to_s, - - @count, file) + rescue Puppet::AuthStoreError => detail + raise ArgumentError.new(detail.to_s, @count, file) end } end diff --git a/lib/puppet/network/authconfig.rb b/lib/puppet/network/authconfig.rb index 61fb24ded..1e486a2f9 100644 --- a/lib/puppet/network/authconfig.rb +++ b/lib/puppet/network/authconfig.rb @@ -102,7 +102,7 @@ module Puppet name = $3 if $2 == "path" name.chomp! right = newrights.newright(name, count, @file) - when /^\s*(allow|deny|method|environment|auth(?:enticated)?)\s+(.+)$/ + when /^\s*(allow|deny|method|environment|auth(?:enticated)?)\s+(.+?)(\s*#.*)?$/ parse_right_directive(right, $1, $2, count) else raise ConfigurationError, "Invalid line #{count}: #{line}" -- cgit From 7e6fc0d80ccd29f206c3b56960ee1eef3afc33a3 Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Tue, 31 May 2011 20:01:36 +0200 Subject: Deprecate RestAuthConfig#allowed? in favor of #check_authorization #allowed? was a poorly named method since it isn't actually a predicate method. Instead of returning a boolean, this methods throws an exception when the access is denied (in order to keep the full context of what ACE triggered the deny). Given that #allowed? was overriding the behavior from AuthConfig, we leave a version of #allowed? in place that will issue a deprecation warning before delegating to #check_authorization. Once support for XML-RPC agents is removed from the master, we will be able to remove this delegation, since there should no longer be a reason for a distinction between AuthConfig and RestAuthConfig. Signed-off-by: Brice Figureau Signed-off-by: Jacob Helwig --- lib/puppet/network/rest_authconfig.rb | 7 ++++++- lib/puppet/network/rest_authorization.rb | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb index dfe8f85c4..7dcc81ef4 100644 --- a/lib/puppet/network/rest_authconfig.rb +++ b/lib/puppet/network/rest_authconfig.rb @@ -29,10 +29,15 @@ module Puppet @main end + def allowed?(request) + Puppet.deprecation_warning "allowed? should not be called for REST authorization - use check_authorization instead" + check_authorization(request) + end + # check wether this request is allowed in our ACL # raise an Puppet::Network::AuthorizedError if the request # is denied. - def allowed?(indirection, method, key, params) + def check_authorization(indirection, method, key, params) read # we're splitting the request in part because diff --git a/lib/puppet/network/rest_authorization.rb b/lib/puppet/network/rest_authorization.rb index 50f094e3e..d636d486a 100644 --- a/lib/puppet/network/rest_authorization.rb +++ b/lib/puppet/network/rest_authorization.rb @@ -16,7 +16,7 @@ module Puppet::Network # Verify that our client has access. def check_authorization(indirection, method, key, params) - authconfig.allowed?(indirection, method, key, params) + authconfig.check_authorization(indirection, method, key, params) end end end -- cgit From 9279d0954eb20d75e18a666fd572b5492e157608 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Fri, 22 Jul 2011 12:44:15 -0700 Subject: Fix issue with forward and backslashes in Windows paths The environment validates its modulepath and manifestdir settings, but it uses Dir.getwd to convert a relative path into an absolute path. The problem is that on Windows, Dir.getwd returns a path with backslashes. (Interestingly this only happens when puppet is loaded, not in irb for example.) And since we do not yet support backslashes in Windows paths or UNC paths, the directory is not included in the environment. For the time being, I am using File.expand_path to normalize the path. It has the side-effect of converting backslashes to forward slashes. This is sufficient to work around backslashes in Dir.getwd. In the near future, I will be refactoring how paths are split, validated, tested, etc, and I have a REMIND in place to fix the environment. But as a result of this change it exposed a bug in our rdoc parser dealing with the finding the root of a path. The parser assumed that the root was '/', but caused an infinite loop when passed a Windows path. I added a test for this case, which is only run on Windows, because on Unix File.dirname("C:/") == '.'. After all of that, I had to disable one of the rdoc spec tests, because it attempted to reproduce a specific bug, which caused rdoc to try to create a directory of the form: C:/.../files/C:/.... Of course, this fails because ':' is not a valid filename character on Windows. Paired-with: Nick Lewis Reviewed-by: Jacob Helwig --- lib/puppet/node/environment.rb | 5 ++++- lib/puppet/util/rdoc/parser.rb | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index f25bb65a9..4fc314a6a 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -131,9 +131,12 @@ class Puppet::Node::Environment def validate_dirs(dirs) dir_regex = Puppet.features.microsoft_windows? ? /^[A-Za-z]:#{File::SEPARATOR}/ : /^#{File::SEPARATOR}/ + # REMIND: Dir.getwd on windows returns a path containing backslashes, which when joined with + # dir containing forward slashes, breaks our regex matching. In general, path validation needs + # to be refactored which will be handled in a future commit. dirs.collect do |dir| if dir !~ dir_regex - File.join(Dir.getwd, dir) + File.expand_path(File.join(Dir.getwd, dir)) else dir end diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb index 762ce25f0..a8996ee9a 100644 --- a/lib/puppet/util/rdoc/parser.rb +++ b/lib/puppet/util/rdoc/parser.rb @@ -113,7 +113,9 @@ class Parser Puppet::Module.modulepath.each do |mp| # check that fullpath is a descendant of mp dirname = fullpath - while (dirname = File.dirname(dirname)) != '/' + previous = dirname + while (dirname = File.dirname(previous)) != previous + previous = dirname return nil if File.identical?(dirname,mp) end end -- cgit From 38c181d00e87ecc699c6a3e23dd2155f716a6602 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Tue, 26 Jul 2011 11:38:05 -0700 Subject: (#8272) Fixup logging in Windows service provider We want to use self.debug for logging in the provider, so that log messages are properly associated with the resource, rather than generically coming from Puppet. Also fix the self.instances method to not use an unnecessary extra variable when collecting. Reviewed-By: Jacob Helwig --- lib/puppet/provider/service/windows.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/puppet/provider/service/windows.rb b/lib/puppet/provider/service/windows.rb index 09754ffda..56d56b0a9 100644 --- a/lib/puppet/provider/service/windows.rb +++ b/lib/puppet/provider/service/windows.rb @@ -41,7 +41,7 @@ Puppet::Type.type(:service).provide :windows do def enabled? w32ss = Win32::Service.config_info( @resource[:name] ) raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceConfigInfo ) ) - Puppet.debug("Service #{@resource[:name]} start type is #{w32ss.start_type}") + debug("Service #{@resource[:name]} start type is #{w32ss.start_type}") case w32ss.start_type when Win32::Service.get_start_type(Win32::Service::SERVICE_AUTO_START), Win32::Service.get_start_type(Win32::Service::SERVICE_BOOT_START), @@ -84,7 +84,7 @@ Puppet::Type.type(:service).provide :windows do else raise Puppet::Error.new("Unknown service state '#{w32ss.current_state}' for service '#{@resource[:name]}'") end - Puppet.debug("Service #{@resource[:name]} is #{w32ss.current_state}") + debug("Service #{@resource[:name]} is #{w32ss.current_state}") return state rescue Win32::Service::Error => detail raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" ) @@ -92,10 +92,6 @@ Puppet::Type.type(:service).provide :windows do # returns all providers for all existing services and startup state def self.instances - srvcs = [] - Win32::Service.services.collect{ |s| - srvcs << new(:name => s.service_name) - } - srvcs + Win32::Service.services.collect { |s| new(:name => s.service_name) } end end -- cgit From 44e2d494f499e2005c1b31b92b97834189d4224d Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Tue, 26 Jul 2011 15:58:31 -0700 Subject: (#8272) Use symbols instead of booleans for enabled property on Windows Because the enable property of the service type uses :true and :false as its valid values, rather than true and false, we need to return :true and :false from our enabled? method. Otherwise, the property was being synced every time it was enabled or disabled, regardless of whether it was actually in sync or not. Reviewed-By: Jacob Helwig --- lib/puppet/provider/service/windows.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/provider/service/windows.rb b/lib/puppet/provider/service/windows.rb index 56d56b0a9..d77f3b44a 100644 --- a/lib/puppet/provider/service/windows.rb +++ b/lib/puppet/provider/service/windows.rb @@ -46,11 +46,11 @@ Puppet::Type.type(:service).provide :windows do when Win32::Service.get_start_type(Win32::Service::SERVICE_AUTO_START), Win32::Service.get_start_type(Win32::Service::SERVICE_BOOT_START), Win32::Service.get_start_type(Win32::Service::SERVICE_SYSTEM_START) - true + :true when Win32::Service.get_start_type(Win32::Service::SERVICE_DEMAND_START) :manual when Win32::Service.get_start_type(Win32::Service::SERVICE_DISABLED) - false + :false else raise Puppet::Error.new("Unknown start type: #{w32ss.start_type}") end -- cgit From 12d0018f93e5a72a728c6decffb351a693a86344 Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Tue, 26 Jul 2011 15:59:45 -0700 Subject: (#8272) Allow disabled Windows services to be started Because Windows allows a service to be both running and disabled, we now support that capability. If a service is explicitly requested to be running and disabled, we will set it to manual start if necessary, start it, and then disable it. If the service is requested to be running and enabled, we will now enable it before attempting to start it (previously, this would simply try to start it and fail). The exception to this rule is a service which is disabled, and for which we are not managing the enable property. In that case, we assume that some other authority has disabled the service, and respect that, failing to start. Thus, if the user actually wants a service to be running and disabled, they must explicitly declare that intent. Reviewed-By: Jacob Helwig --- lib/puppet/provider/service/windows.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lib') diff --git a/lib/puppet/provider/service/windows.rb b/lib/puppet/provider/service/windows.rb index d77f3b44a..f1485f268 100644 --- a/lib/puppet/provider/service/windows.rb +++ b/lib/puppet/provider/service/windows.rb @@ -59,6 +59,19 @@ Puppet::Type.type(:service).provide :windows do end def start + if enabled? == :false + # If disabled and not managing enable, respect disabled and fail. + if @resource[:enable].nil? + raise Puppet::Error, "Will not start disabled service #{@resource[:name]} without managing enable. Specify 'enable => false' to override." + # Otherwise start. If enable => false, we will later sync enable and + # disable the service again. + elsif @resource[:enable] == :true + enable + else + manual_start + end + end + Win32::Service.start( @resource[:name] ) rescue Win32::Service::Error => detail raise Puppet::Error.new("Cannot start #{@resource[:name]}, error was: #{detail}" ) -- cgit From 95b21dfde7d77a61633555f20f2e3b9675d48415 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Fri, 29 Jul 2011 09:37:58 -0700 Subject: (#8660) Default config dir to %PROGRAMDATA% on Windows The puppet install.rb script now defaults the config directory to %PROGRAMDATA%\PuppetLabs\puppet\etc on Windows. This is more inline with Windows best-practices, as this directory is used to store application data across all users. The PROGRAMDATA environment variable also takes into account alternate system drives, by using the SYSTEMDRIVE environment variable. Note that the Dir::COMMON_APPDATA constant is so named because it corresponds to the CSIDL_COMMON_APPDATA constant, which on 2000, XP, and 2003 is %ALLUSERSPROFILE%\Application Data, and on Vista, Win7 and 2008 is %SYSTEMDRIVE%\ProgramData. This commit also updates puppet's default run_mode var and conf directories when running as "root" to match the install script, and fixes the spec test, which was looking in the Dir::WINDOWS directory. Reviewed-by: Cameron Thomas --- lib/puppet/util/run_mode.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/util/run_mode.rb b/lib/puppet/util/run_mode.rb index 450cbf1a6..6028aef29 100644 --- a/lib/puppet/util/run_mode.rb +++ b/lib/puppet/util/run_mode.rb @@ -27,14 +27,14 @@ module Puppet def conf_dir which_dir( - (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "etc") : "/etc/puppet"), + (Puppet.features.microsoft_windows? ? File.join(Dir::COMMON_APPDATA, "PuppetLabs", "puppet", "etc") : "/etc/puppet"), "~/.puppet" ) end def var_dir which_dir( - (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "var") : "/var/lib/puppet"), + (Puppet.features.microsoft_windows? ? File.join(Dir::COMMON_APPDATA, "PuppetLabs", "puppet", "var") : "/var/lib/puppet"), "~/.puppet/var" ) end -- cgit From 82c6b3cb41397c989c011cf767066bcf1e403db2 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Fri, 29 Jul 2011 13:30:15 -0700 Subject: (#8644) Host provider on Windows The host provider did not work on Windows because it didn't know where to find its hosts file. The provider now uses Win32::Resolv, which is part of the standard ruby library, to find it. Several host type/provider spec tests were marked as fails_on_windows, but now that the provider is working, I removed the tag from those tests, and verified that the tests now pass. There are two tests in resources_spec that fail because the user and exec providers are not supported on Windows yet, so those tests are marked as fails_on_windows. Reviewed-by: Pieter van de Bruggen --- lib/puppet/provider/host/parsed.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/puppet/provider/host/parsed.rb b/lib/puppet/provider/host/parsed.rb index 2ba01a41c..1a2bdb460 100644 --- a/lib/puppet/provider/host/parsed.rb +++ b/lib/puppet/provider/host/parsed.rb @@ -3,6 +3,9 @@ require 'puppet/provider/parsedfile' hosts = nil case Facter.value(:operatingsystem) when "Solaris"; hosts = "/etc/inet/hosts" +when "windows" + require 'win32/resolv' + hosts = Win32::Resolv.get_hosts_path else hosts = "/etc/hosts" end -- cgit From b4cacfd8f95577c514999b4dd6bcb7ad57e37207 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 2 Aug 2011 10:34:06 -0700 Subject: Clarify logic and error messages when initializing Puppet::FileBucket::File Rather than stating the logic as 'if !thing', the two checks done when initializing a new Puppet::FileBucket::File are now phrased as 'unless thing', which should lessen the likelihood of overlooking the '!'. We also now provide a reason for the ArgumentError being raised, which should help users of Puppet::FileBucket::File quickly figure out what is the problem when these exceptions are raised. In addition to updating the tests to look for these new error messages, we update the existing tests to specify which type of exception, and what message it should have, when something is raised. Reviewed-by: Nick Lewis --- lib/puppet/file_bucket/file.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_bucket/file.rb b/lib/puppet/file_bucket/file.rb index 08c0329f1..2a0558fde 100644 --- a/lib/puppet/file_bucket/file.rb +++ b/lib/puppet/file_bucket/file.rb @@ -15,11 +15,11 @@ class Puppet::FileBucket::File attr :bucket_path def initialize( contents, options = {} ) - raise ArgumentError if !contents.is_a?(String) - @contents = contents + raise ArgumentError.new("contents must be a String, got a #{contents.class}") unless contents.is_a?(String) + @contents = contents @bucket_path = options.delete(:bucket_path) - raise ArgumentError if options != {} + raise ArgumentError.new("Unknown option(s): #{options.keys.join(', ')}") unless options.empty? end def checksum_type -- cgit From 568d25ee10effd5e87c57cdc8c24280eabf9cd93 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 2 Aug 2011 11:04:26 -0700 Subject: Treat Windows absolute paths as absolute paths Previously, we only considered files that matched the *nix concept of 'absolute' as being absolute paths. Since absolute paths on Windows look more like URLs with this world-view, we need to specifically look for the Windows absolute paths, and treat them as such. We will still treat *nix absolute paths as absolute on Windows, even though they are actually relative to the "current" drive. We do not currently limit which "style" of absolute path is allowed based on what the agent is. Reviewed-by: Nick Lewis --- lib/puppet/file_serving/base.rb | 5 ++++- lib/puppet/file_serving/indirection_hooks.rb | 1 + lib/puppet/indirector/request.rb | 4 +++- lib/puppet/type/file.rb | 20 +++++++++++++++++--- lib/puppet/type/file/source.rb | 4 +++- 5 files changed, 28 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_serving/base.rb b/lib/puppet/file_serving/base.rb index 09cab97d9..706f67af9 100644 --- a/lib/puppet/file_serving/base.rb +++ b/lib/puppet/file_serving/base.rb @@ -53,7 +53,10 @@ class Puppet::FileServing::Base # Set our base path. attr_reader :path def path=(path) - raise ArgumentError.new("Paths must be fully qualified") unless path =~ /^#{::File::SEPARATOR}/ + unless path =~ /^#{::File::SEPARATOR}/ or path =~ /^[a-z]:[\/\\]/i + raise ArgumentError.new("Paths must be fully qualified") + end + @path = path end diff --git a/lib/puppet/file_serving/indirection_hooks.rb b/lib/puppet/file_serving/indirection_hooks.rb index a85e90ef1..2a0dc1792 100644 --- a/lib/puppet/file_serving/indirection_hooks.rb +++ b/lib/puppet/file_serving/indirection_hooks.rb @@ -17,6 +17,7 @@ module Puppet::FileServing::IndirectionHooks # Short-circuit to :file if it's a fully-qualified path or specifies a 'file' protocol. return PROTOCOL_MAP["file"] if request.key =~ /^#{::File::SEPARATOR}/ + return PROTOCOL_MAP["file"] if request.key =~ /^[a-z]:[\/\\]/i return PROTOCOL_MAP["file"] if request.protocol == "file" # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'apply' or 'puppet' diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb index 697d9df47..4dfbac9ab 100644 --- a/lib/puppet/indirector/request.rb +++ b/lib/puppet/indirector/request.rb @@ -127,7 +127,9 @@ class Puppet::Indirector::Request # because it rewrites the key. We could otherwise strip server/port/etc # info out in the REST class, but it seemed bad design for the REST # class to rewrite the key. - if key.to_s =~ /^\w+:\/\// # it's a URI + if key.to_s =~ /^[a-z]:[\/\\]/i # It's an absolute path for Windows. + @key = key + elsif key.to_s =~ /^\w+:\/\// # it's a URI set_uri_key(key) else @key = key diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 988416ab5..07409a108 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -23,7 +23,7 @@ Puppet::Type.newtype(:file) do location, rather than using native resources, please contact Puppet Labs and we can hopefully work with you to develop a native resource to support what you are doing. - + **Autorequires:** If Puppet is managing the user or group that owns a file, the file resource will autorequire them. If Puppet is managing any parent directories of a file, the file resource will autorequire them." def self.title_patterns @@ -36,7 +36,7 @@ Puppet::Type.newtype(:file) do validate do |value| # accept various path syntaxes: lone slash, posix, win32, unc - unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^[A-Za-z]:\// or value =~ /^\/\/[^\/]+\/[^\/]+/)) + unless (Puppet.features.posix? and value =~ /^\//) or (value =~ /^[A-Za-z]:\// or value =~ /^\/\/[^\/]+\/[^\/]+/) fail Puppet::Error, "File paths must be fully qualified, not '#{value}'" end end @@ -44,7 +44,21 @@ Puppet::Type.newtype(:file) do # convert the current path in an index into the collection and the last # path name. The aim is to use less storage for all common paths in a hierarchy munge do |value| - path, name = ::File.split(value.gsub(/\/+/,'/')) + # We need to save off, and remove the volume designator in the + # path if it is there, since File.split does not handle paths + # with volume designators properly, except when run on Windows. + # Since we are potentially compiling a catalog for a Windows + # machine on a non-Windows master, we need to handle this + # ourselves. + optional_volume_designator = value.match(/^([a-z]:)[\/\\].*/i) + value_without_designator = value.sub(/^(?:[a-z]:)?(.*)/i, '\1') + + path, name = ::File.split(value_without_designator.gsub(/\/+/,'/')) + + if optional_volume_designator + path = optional_volume_designator[1] + path + end + { :index => Puppet::FileCollection.collection.index(path), :name => name } end diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 39f85e2ad..8653a8f7a 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -72,7 +72,7 @@ module Puppet self.fail "Could not understand source #{source}: #{detail}" end - self.fail "Cannot use URLs of type '#{uri.scheme}' as source for fileserving" unless uri.scheme.nil? or %w{file puppet}.include?(uri.scheme) + self.fail "Cannot use URLs of type '#{uri.scheme}' as source for fileserving" unless uri.scheme.nil? or %w{file puppet}.include?(uri.scheme) or (Puppet.features.microsoft_windows? and uri.scheme =~ /^[a-z]$/i) end end @@ -180,6 +180,8 @@ module Puppet private def uri + return nil if metadata.source =~ /^[a-z]:[\/\\]/i # Abspath for Windows + @uri ||= URI.parse(URI.escape(metadata.source)) end end -- cgit From 5314376d4378c4b4f990a7d61a9677594e12a2a5 Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Tue, 2 Aug 2011 11:13:21 -0700 Subject: Always put a slash between the checksum and path in filebucket URLs Since absolute paths on Windows do not always start with /, we need to make sure that there is always a slash between the checksum and the path, or the drive letter will end up being considered as part of the checksum. On systems where absolute paths always start with /, the extra slash is removed by the parsing done to the constructed URL. Reviewed-by: Nick Lewis --- lib/puppet/file_bucket/dipper.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/puppet/file_bucket/dipper.rb b/lib/puppet/file_bucket/dipper.rb index d6f6a3747..870c50eec 100644 --- a/lib/puppet/file_bucket/dipper.rb +++ b/lib/puppet/file_bucket/dipper.rb @@ -35,11 +35,12 @@ class Puppet::FileBucket::Dipper begin file_bucket_file = Puppet::FileBucket::File.new(contents, :bucket_path => @local_path) files_original_path = absolutize_path(file) - dest_path = "#{@rest_path}#{file_bucket_file.name}#{files_original_path}" + dest_path = "#{@rest_path}#{file_bucket_file.name}/#{files_original_path}" + file_bucket_path = "#{@rest_path}#{file_bucket_file.checksum_type}/#{file_bucket_file.checksum_data}/#{files_original_path}" # Make a HEAD request for the file so that we don't waste time # uploading it if it already exists in the bucket. - unless Puppet::FileBucket::File.indirection.head("#{@rest_path}#{file_bucket_file.checksum_type}/#{file_bucket_file.checksum_data}#{files_original_path}") + unless Puppet::FileBucket::File.indirection.head(file_bucket_path) Puppet::FileBucket::File.indirection.save(file_bucket_file, dest_path) end -- cgit