diff options
| author | Nick Lewis <nick@puppetlabs.com> | 2010-12-16 10:36:55 -0800 |
|---|---|---|
| committer | Nick Lewis <nick@puppetlabs.com> | 2010-12-16 10:36:55 -0800 |
| commit | 52ca8c78c270b93ce997217900a3d333ad8154cc (patch) | |
| tree | 56f0e4eb1798d0b8a1f5c37bae8ff2cf34171d85 | |
| parent | af6e08c0a59db951502d0cf8c0ca24f5001e92f1 (diff) | |
| parent | 167e84d39d5cdd6b628d4d681b918406e7c896e6 (diff) | |
| download | puppet-52ca8c78c270b93ce997217900a3d333ad8154cc.tar.gz puppet-52ca8c78c270b93ce997217900a3d333ad8154cc.tar.xz puppet-52ca8c78c270b93ce997217900a3d333ad8154cc.zip | |
Merge branch '2.6.next' into 2.6.x
33 files changed, 507 insertions, 256 deletions
diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb new file mode 100644 index 000000000..c28fef326 --- /dev/null +++ b/lib/puppet/application/inspect.rb @@ -0,0 +1,80 @@ +require 'puppet/application' + +class Puppet::Application::Inspect < Puppet::Application + + should_parse_config + run_mode :agent + + option("--debug","-d") + option("--verbose","-v") + + option("--logdest LOGDEST", "-l") do |arg| + begin + Puppet::Util::Log.newdestination(arg) + options[:logset] = true + rescue => detail + $stderr.puts detail.to_s + end + end + + def setup + exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? + + raise "Inspect requires reporting to be enabled. Set report=true in puppet.conf to enable reporting." unless Puppet[:report] + + @report = Puppet::Transaction::Report.new("inspect") + + Puppet::Util::Log.newdestination(@report) + Puppet::Util::Log.newdestination(:console) unless options[:logset] + + trap(:INT) do + $stderr.puts "Exiting" + exit(1) + end + + if options[:debug] + Puppet::Util::Log.level = :debug + elsif options[:verbose] + Puppet::Util::Log.level = :info + end + + Puppet::Transaction::Report.terminus_class = :rest + Puppet::Resource::Catalog.terminus_class = :yaml + end + + def run_command + retrieval_starttime = Time.now + + unless catalog = Puppet::Resource::Catalog.find(Puppet[:certname]) + raise "Could not find catalog for #{Puppet[:certname]}" + end + + retrieval_time = Time.now - retrieval_starttime + @report.add_times("config_retrieval", retrieval_time) + + starttime = Time.now + + catalog.to_ral.resources.each do |ral_resource| + audited_attributes = ral_resource[:audit] + next unless audited_attributes + + audited_resource = ral_resource.to_resource + + status = Puppet::Resource::Status.new(ral_resource) + audited_attributes.each do |name| + event = ral_resource.event(:previous_value => audited_resource[name], :property => name, :status => "audit", :message => "inspected value is #{audited_resource[name].inspect}") + status.add_event(event) + end + @report.add_resource_status(status) + end + + @report.add_metric(:time, {"config_retrieval" => retrieval_time, "inspect" => Time.now - starttime}) + + begin + @report.save + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not send report: #{detail}" + end + end +end diff --git a/lib/puppet/configurer/plugin_handler.rb b/lib/puppet/configurer/plugin_handler.rb index 539441e75..cfc6b5a0b 100644 --- a/lib/puppet/configurer/plugin_handler.rb +++ b/lib/puppet/configurer/plugin_handler.rb @@ -19,8 +19,6 @@ module Puppet::Configurer::PluginHandler begin Puppet.info "Loading downloaded plugin #{file}" load file - rescue SystemExit,NoMemoryError - raise rescue Exception => detail Puppet.err "Could not load downloaded file #{file}: #{detail}" end diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb index 4180be57d..89a0c62e0 100644 --- a/lib/puppet/external/pson/pure/generator.rb +++ b/lib/puppet/external/pson/pure/generator.rb @@ -44,34 +44,13 @@ module PSON string << '' # XXX workaround: avoid buffer sharing string.force_encoding(Encoding::ASCII_8BIT) string.gsub!(/["\\\x0-\x1f]/) { MAP[$MATCH] } - string.gsub!(/( - (?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+ | - [\x80-\xc1\xf5-\xff] # invalid - )/nx) { |c| - c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0] - s.gsub!(/.{4}/n, '\\\\u\&') - } - string.force_encoding(Encoding::UTF_8) string rescue Iconv::Failure => e raise GeneratorError, "Caught #{e.class}: #{e}" end else def utf8_to_pson(string) # :nodoc: - string. - gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] }. - gsub(/((?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+)/nx) { |c| - PSON::UTF8toUTF16.iconv(c).unpack('H*')[0].gsub(/.{4}/n, '\\\\u\&') - } + string.gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] } end end module_function :utf8_to_pson diff --git a/lib/puppet/indirector/catalog/active_record.rb b/lib/puppet/indirector/catalog/active_record.rb index fabb08eb9..f814f4aff 100644 --- a/lib/puppet/indirector/catalog/active_record.rb +++ b/lib/puppet/indirector/catalog/active_record.rb @@ -32,7 +32,7 @@ class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord if node = Puppet::Node.find(catalog.name) host.ip = node.parameters["ipaddress"] - host.environment = node.environment + host.environment = node.environment.to_s end host.save diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb index 63d110395..6a03458b3 100644 --- a/lib/puppet/resource/type_collection.rb +++ b/lib/puppet/resource/type_collection.rb @@ -153,7 +153,6 @@ class Puppet::Resource::TypeCollection end def perform_initial_import - return if Puppet.settings[:ignoreimport] parser = Puppet::Parser::Parser.new(environment) if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != "" parser.string = code diff --git a/lib/puppet/transaction/change.rb b/lib/puppet/transaction/change.rb index ecc3b5a5f..d57ac1917 100644 --- a/lib/puppet/transaction/change.rb +++ b/lib/puppet/transaction/change.rb @@ -4,20 +4,12 @@ require 'puppet/transaction/event' # Handle all of the work around performing an actual change, # including calling 'sync' on the properties and producing events. class Puppet::Transaction::Change - attr_accessor :is, :should, :property, :proxy, :auditing + attr_accessor :is, :should, :property, :proxy, :auditing, :old_audit_value def auditing? auditing end - # Create our event object. - def event - result = property.event - result.previous_value = is - result.desired_value = should - result - end - def initialize(property, currentvalue) @property = property @is = currentvalue @@ -28,24 +20,39 @@ class Puppet::Transaction::Change end def apply - return audit_event if auditing? - return noop_event if noop? - - property.sync - - result = event - result.message = property.change_to_s(is, should) - result.status = "success" - result.send_log - result + event = property.event + event.previous_value = is + event.desired_value = should + event.historical_value = old_audit_value + + if auditing? and old_audit_value != is + event.message = "audit change: previously recorded value #{property.is_to_s(old_audit_value)} has been changed to #{property.is_to_s(is)}" + event.status = "audit" + event.audited = true + brief_audit_message = " (previously recorded value was #{property.is_to_s(old_audit_value)})" + else + brief_audit_message = "" + end + + if property.insync?(is) + # nothing happens + elsif noop? + event.message = "is #{property.is_to_s(is)}, should be #{property.should_to_s(should)} (noop)#{brief_audit_message}" + event.status = "noop" + else + property.sync + event.message = [ property.change_to_s(is, should), brief_audit_message ].join + event.status = "success" + end + event rescue => detail puts detail.backtrace if Puppet[:trace] - result = event - result.status = "failure" + event.status = "failure" - result.message = "change from #{property.is_to_s(is)} to #{property.should_to_s(should)} failed: #{detail}" - result.send_log - result + event.message = "change from #{property.is_to_s(is)} to #{property.should_to_s(should)} failed: #{detail}" + event + ensure + event.send_log end # Is our property noop? This is used for generating special events. @@ -65,23 +72,4 @@ class Puppet::Transaction::Change def to_s "change #{@property.change_to_s(@is, @should)}" end - - private - - def audit_event - # This needs to store the appropriate value, and then produce a new event - result = event - result.message = "audit change: previously recorded value #{property.should_to_s(should)} has been changed to #{property.is_to_s(is)}" - result.status = "audit" - result.send_log - result - end - - def noop_event - result = event - result.message = "is #{property.is_to_s(is)}, should be #{property.should_to_s(should)} (noop)" - result.status = "noop" - result.send_log - result - end end diff --git a/lib/puppet/transaction/event.rb b/lib/puppet/transaction/event.rb index e5e5793da..da5b14727 100644 --- a/lib/puppet/transaction/event.rb +++ b/lib/puppet/transaction/event.rb @@ -7,7 +7,7 @@ class Puppet::Transaction::Event include Puppet::Util::Tagging include Puppet::Util::Logging - ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :status, :message, :node, :version, :file, :line, :source_description] + ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :historical_value, :status, :message, :node, :version, :file, :line, :source_description, :audited] attr_accessor *ATTRIBUTES attr_writer :tags attr_accessor :time diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb index e6d1e0528..75c08fc7a 100644 --- a/lib/puppet/transaction/report.rb +++ b/lib/puppet/transaction/report.rb @@ -10,7 +10,7 @@ class Puppet::Transaction::Report indirects :report, :terminus_class => :processor - attr_reader :resource_statuses, :logs, :metrics, :host, :time + attr_reader :resource_statuses, :logs, :metrics, :host, :time, :kind # This is necessary since Marshall doesn't know how to # dump hash with default proc (see below @records) @@ -49,13 +49,14 @@ class Puppet::Transaction::Report calculate_event_metrics end - def initialize + def initialize(kind = "apply") @metrics = {} @logs = [] @resource_statuses = {} @external_times ||= {} @host = Puppet[:certname] @time = Time.now + @kind = kind end def name diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb index 29ec9a539..c978e5545 100644 --- a/lib/puppet/transaction/resource_harness.rb +++ b/lib/puppet/transaction/resource_harness.rb @@ -25,12 +25,12 @@ class Puppet::Transaction::ResourceHarness status.changed = true end - # Used mostly for scheduling at this point. + # Used mostly for scheduling and auditing at this point. def cached(resource, name) Puppet::Util::Storage.cache(resource)[name] end - # Used mostly for scheduling at this point. + # Used mostly for scheduling and auditing at this point. def cache(resource, name, value) Puppet::Util::Storage.cache(resource)[name] = value end @@ -46,33 +46,35 @@ class Puppet::Transaction::ResourceHarness if param = resource.parameter(:ensure) return [] if absent_and_not_being_created?(current, param) - return [Puppet::Transaction::Change.new(param, current[:ensure])] unless ensure_is_insync?(current, param) + unless ensure_is_insync?(current, param) + audited.keys.reject{|name| name == :ensure}.each do |name| + resource.parameter(name).notice "audit change: previously recorded value #{audited[name]} has been changed to #{current[param]}" + cache(resource, name, current[param]) + end + return [Puppet::Transaction::Change.new(param, current[:ensure])] + end return [] if ensure_should_be_absent?(current, param) end - resource.properties.reject { |p| p.name == :ensure }.reject do |param| - param.should.nil? - end.reject do |param| - param_is_insync?(current, param) + resource.properties.reject { |param| param.name == :ensure }.select do |param| + (audited.include?(param.name) && audited[param.name] != current[param.name]) || (param.should != nil && !param_is_insync?(current, param)) end.collect do |param| change = Puppet::Transaction::Change.new(param, current[param.name]) change.auditing = true if audited.include?(param.name) + change.old_audit_value = audited[param.name] change end end def copy_audited_parameters(resource, current) - return [] unless audit = resource[:audit] + return {} unless audit = resource[:audit] audit = Array(audit).collect { |p| p.to_sym } - audited = [] + audited = {} audit.find_all do |param| - next if resource[param] - if value = cached(resource, param) - resource[param] = value - audited << param + audited[param] = value else - resource.debug "Storing newly-audited value #{current[param]} for #{param}" + resource.property(param).notice "audit change: newly-recorded recorded value #{current[param]}" cache(resource, param, current[param]) end end diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index f35a26408..6523c99a0 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -718,8 +718,9 @@ Puppet::Type.newtype(:file) do mode = self.should(:mode) # might be nil umask = mode ? 000 : 022 + mode_int = mode ? mode.to_i(8) : nil - content_checksum = Puppet::Util.withumask(umask) { File.open(path, 'w', mode) { |f| write_content(f) } } + content_checksum = Puppet::Util.withumask(umask) { File.open(path, 'w', mode_int ) { |f| write_content(f) } } # And put our new file in place if use_temporary_file # This is only not true when our file is empty. diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb index 967e06aee..4a68551ee 100755 --- a/lib/puppet/type/file/ensure.rb +++ b/lib/puppet/type/file/ensure.rb @@ -66,7 +66,7 @@ module Puppet end if mode Puppet::Util.withumask(000) do - Dir.mkdir(@resource[:path],mode) + Dir.mkdir(@resource[:path], mode.to_i(8)) end else Dir.mkdir(@resource[:path]) diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb index 1ce56c843..2acd8b359 100755 --- a/lib/puppet/type/file/mode.rb +++ b/lib/puppet/type/file/mode.rb @@ -25,60 +25,26 @@ module Puppet @event = :file_changed - # Our modes are octal, so make sure they print correctly. Other - # valid values are symbols, basically - def is_to_s(currentvalue) - case currentvalue - when Integer - return "%o" % currentvalue - when Symbol - return currentvalue - else - raise Puppet::DevError, "Invalid current value for mode: #{currentvalue.inspect}" - end - end - - def should_to_s(newvalue = @should) - case newvalue - when Integer - return "%o" % newvalue - when Symbol - return newvalue - else - raise Puppet::DevError, "Invalid 'should' value for mode: #{newvalue.inspect}" - end - end - munge do |should| - # this is pretty hackish, but i need to make sure the number is in - # octal, yet the number can only be specified as a string right now - value = should - if value.is_a?(String) - unless value =~ /^\d+$/ - raise Puppet::Error, "File modes can only be numbers, not #{value.inspect}" - end - # Make sure our number looks like octal. - unless value =~ /^0/ - value = "0#{value}" - end - old = value - begin - value = Integer(value) - rescue ArgumentError => detail - raise Puppet::DevError, "Could not convert #{old.inspect} to integer" + if should.is_a?(String) + unless should =~ /^[0-7]+$/ + raise Puppet::Error, "File modes can only be octal numbers, not #{should.inspect}" end + should.to_i(8).to_s(8) + else + should.to_s(8) end - - return value end # If we're a directory, we need to be executable for all cases # that are readable. This should probably be selectable, but eh. def dirmask(value) if FileTest.directory?(@resource[:path]) + value = value.to_i(8) value |= 0100 if value & 0400 != 0 value |= 010 if value & 040 != 0 value |= 01 if value & 04 != 0 + value = value.to_s(8) end value @@ -101,7 +67,7 @@ module Puppet unless defined?(@fixed) @should &&= @should.collect { |s| self.dirmask(s) } end - return stat.mode & 007777 + return (stat.mode & 007777).to_s(8) else return :absent end @@ -111,7 +77,7 @@ module Puppet mode = self.should begin - File.chmod(mode, @resource[:path]) + File.chmod(mode.to_i(8), @resource[:path]) rescue => detail error = Puppet::Error.new("failed to chmod #{@resource[:path]}: #{detail.message}") error.set_backtrace detail.backtrace diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index c8110bb69..761d5d71b 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -72,6 +72,11 @@ module Puppet end end + newproperty(:home) do + desc "The home directory of the user. The directory must be created + separately and is not currently checked for existence." + end + newproperty(:uid) do desc "The user ID. Must be specified numerically. For new users being created, if no user ID is specified then one will be @@ -138,11 +143,6 @@ module Puppet desc "A description of the user. Generally is a user's full name." end - newproperty(:home) do - desc "The home directory of the user. The directory must be created - separately and is not currently checked for existence." - end - newproperty(:shell) do desc "The user's login shell. The shell must exist and be executable." diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb index 36a765c61..7764dc1d1 100644 --- a/lib/puppet/util/log.rb +++ b/lib/puppet/util/log.rb @@ -17,11 +17,12 @@ class Puppet::Util::Log # Create a new destination type. def self.newdesttype(name, options = {}, &block) - dest = genclass( - name, :parent => Puppet::Util::Log::Destination, :prefix => "Dest", - :block => block, - :hash => @desttypes, - + dest = genclass( + name, + :parent => Puppet::Util::Log::Destination, + :prefix => "Dest", + :block => block, + :hash => @desttypes, :attributes => options ) dest.match(dest.name) diff --git a/spec/unit/application/inspect_spec.rb b/spec/unit/application/inspect_spec.rb new file mode 100644 index 000000000..a3cc74d86 --- /dev/null +++ b/spec/unit/application/inspect_spec.rb @@ -0,0 +1,79 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/application/inspect' +require 'puppet/resource/catalog' +require 'puppet/indirector/catalog/yaml' +require 'puppet/indirector/report/rest' + +describe Puppet::Application::Inspect do + before :each do + @inspect = Puppet::Application[:inspect] + end + + describe "during setup" do + it "should print its configuration if asked" do + Puppet[:configprint] = "all" + + Puppet.settings.expects(:print_configs).returns(true) + lambda { @inspect.setup }.should raise_error(SystemExit) + end + + it "should fail if reporting is turned off" do + Puppet[:report] = false + lambda { @inspect.setup }.should raise_error(/report=true/) + end + end + + describe "when executing" do + before :each do + Puppet[:report] = true + Puppet::Util::Log.stubs(:newdestination) + Puppet::Transaction::Report::Rest.any_instance.stubs(:save) + @inspect.setup + end + + it "should retrieve the local catalog" do + Puppet::Resource::Catalog::Yaml.any_instance.expects(:find).with {|request| request.key == Puppet[:certname] }.returns(Puppet::Resource::Catalog.new) + + @inspect.run_command + end + + it "should save the report to REST" do + Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(Puppet::Resource::Catalog.new) + Puppet::Transaction::Report::Rest.any_instance.expects(:save).with {|request| request.instance.host == Puppet[:certname] } + + @inspect.run_command + end + + it "should audit the specified properties" do + catalog = Puppet::Resource::Catalog.new + file = Tempfile.new("foo") + file.puts("file contents") + file.flush + resource = Puppet::Resource.new(:file, file.path, :parameters => {:audit => "all"}) + catalog.add_resource(resource) + Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(catalog) + + events = nil + + Puppet::Transaction::Report::Rest.any_instance.expects(:save).with do |request| + events = request.instance.resource_statuses.values.first.events + end + + @inspect.run_command + + properties = events.inject({}) do |property_values, event| + property_values.merge(event.property => event.previous_value) + end + properties["ensure"].should == :file + properties["content"].should == "{md5}#{Digest::MD5.hexdigest("file contents\n")}" + end + end + + after :all do + Puppet::Resource::Catalog.indirection.reset_terminus_class + Puppet::Transaction::Report.indirection.terminus_class = :processor + end +end diff --git a/spec/unit/configurer/plugin_handler_spec.rb b/spec/unit/configurer/plugin_handler_spec.rb index 25d2d47af..30b135e8f 100755 --- a/spec/unit/configurer/plugin_handler_spec.rb +++ b/spec/unit/configurer/plugin_handler_spec.rb @@ -11,6 +11,10 @@ end describe Puppet::Configurer::PluginHandler do before do @pluginhandler = PluginHandlerTester.new + + # PluginHandler#load_plugin has an extra-strong rescue clause + # this mock is to make sure that we don't silently ignore errors + Puppet.expects(:err).never end it "should have a method for downloading plugins" do @@ -80,7 +84,7 @@ describe Puppet::Configurer::PluginHandler do end it "should not try to load files that don't exist" do - FileTest.expects(:exist?).with("foo").returns true + FileTest.expects(:exist?).with("foo").returns false @pluginhandler.expects(:load).never @pluginhandler.load_plugin("foo") diff --git a/spec/unit/configurer_spec.rb b/spec/unit/configurer_spec.rb index 0c9d06362..ebc5768ea 100755 --- a/spec/unit/configurer_spec.rb +++ b/spec/unit/configurer_spec.rb @@ -418,7 +418,7 @@ describe Puppet::Configurer, "when retrieving a catalog" do end it "should return nil if there is an error while retrieving the catalog" do - Puppet::Resource::Catalog.expects(:find).raises "eh" + Puppet::Resource::Catalog.expects(:find).at_least_once.raises "eh" @agent.retrieve_catalog.should be_nil end diff --git a/spec/unit/file_serving/fileset_spec.rb b/spec/unit/file_serving/fileset_spec.rb index 9a90cff15..ecc77812c 100755 --- a/spec/unit/file_serving/fileset_spec.rb +++ b/spec/unit/file_serving/fileset_spec.rb @@ -306,6 +306,7 @@ end describe Puppet::FileServing::Fileset, "when merging other filesets" do before do @paths = %w{/first/path /second/path /third/path} + File.stubs(:lstat).returns stub("stat", :directory? => false) @filesets = @paths.collect do |path| File.stubs(:lstat).with(path).returns stub("stat", :directory? => true) diff --git a/spec/unit/indirector/catalog/active_record_spec.rb b/spec/unit/indirector/catalog/active_record_spec.rb index 4e9d049a1..df61d59d7 100755 --- a/spec/unit/indirector/catalog/active_record_spec.rb +++ b/spec/unit/indirector/catalog/active_record_spec.rb @@ -6,6 +6,23 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe "Puppet::Resource::Catalog::ActiveRecord" do confine "Missing Rails" => Puppet.features.rails? + require 'puppet/rails' + class Tableless < ActiveRecord::Base + def self.columns + @columns ||= [] + end + def self.column(name, sql_type=nil, default=nil, null=true) + columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) + end + end + + class Host < Tableless + column :name, :string, :null => false + column :ip, :string + column :environment, :string + column :last_compile, :datetime + end + before do require 'puppet/indirector/catalog/active_record' Puppet.features.stubs(:rails?).returns true @@ -76,15 +93,17 @@ describe "Puppet::Resource::Catalog::ActiveRecord" do describe "when saving an instance" do before do - @host = stub 'host', :name => "foo", :save => nil, :merge_resources => nil, :last_compile= => nil, :ip= => nil, :environment= => nil + @host = Host.new(:name => "foo") + @host.stubs(:merge_resources) + @host.stubs(:save) @host.stubs(:railsmark).yields - @node = stub_everything 'node', :parameters => {} - Puppet::Node.stubs(:find).returns(@node) + @node = Puppet::Node.new("foo", :environment => "environment") + Puppet::Node.indirection.stubs(:find).with("foo").returns(@node) Puppet::Rails::Host.stubs(:find_by_name).returns @host @catalog = Puppet::Resource::Catalog.new("foo") - @request = stub 'request', :key => "foo", :instance => @catalog + @request = Puppet::Indirector::Request.new(:active_record, :save, @catalog) end it "should find the Rails host with the same name" do @@ -111,25 +130,21 @@ describe "Puppet::Resource::Catalog::ActiveRecord" do it "should set host ip if we could find a matching node" do @node.stubs(:parameters).returns({"ipaddress" => "192.168.0.1"}) - @host.expects(:ip=).with '192.168.0.1' - @terminus.save(@request) + @host.ip.should == '192.168.0.1' end it "should set host environment if we could find a matching node" do - @node.stubs(:environment).returns("myenv") - - @host.expects(:environment=).with 'myenv' - @terminus.save(@request) + @host.environment.should == "environment" end it "should set the last compile time on the host" do now = Time.now Time.expects(:now).returns now - @host.expects(:last_compile=).with now @terminus.save(@request) + @host.last_compile.should == now end it "should save the Rails host instance" do diff --git a/spec/unit/indirector/ssl_file_spec.rb b/spec/unit/indirector/ssl_file_spec.rb index 83145cffc..37098a7a9 100755 --- a/spec/unit/indirector/ssl_file_spec.rb +++ b/spec/unit/indirector/ssl_file_spec.rb @@ -18,12 +18,12 @@ describe Puppet::Indirector::SslFile do end end - @setting = :mydir + @setting = :certdir @file_class.store_in @setting - @path = "/my/directory" - Puppet.settings.stubs(:value).with(:noop).returns(false) - Puppet.settings.stubs(:value).with(@setting).returns(@path) - Puppet.settings.stubs(:value).with(:trace).returns(false) + @path = "/tmp/my_directory" + Puppet[:noop] = false + Puppet[@setting] = @path + Puppet[:trace] = false end it "should use :main and :ssl upon initialization" do diff --git a/spec/unit/provider/service/init_spec.rb b/spec/unit/provider/service/init_spec.rb index bbc88ff76..856821985 100755 --- a/spec/unit/provider/service/init_spec.rb +++ b/spec/unit/provider/service/init_spec.rb @@ -84,10 +84,12 @@ describe provider_class do end it "should be able to find the init script in the service path" do + File.stubs(:stat).raises(Errno::ENOENT.new('No such file or directory')) File.expects(:stat).with("/service/path/myservice").returns true @provider.initscript.should == "/service/path/myservice" end it "should be able to find the init script in the service path" do + File.stubs(:stat).raises(Errno::ENOENT.new('No such file or directory')) File.expects(:stat).with("/alt/service/path/myservice").returns true @provider.initscript.should == "/alt/service/path/myservice" end diff --git a/spec/unit/resource/type_collection_spec.rb b/spec/unit/resource/type_collection_spec.rb index 577aea42b..ff4c22234 100644 --- a/spec/unit/resource/type_collection_spec.rb +++ b/spec/unit/resource/type_collection_spec.rb @@ -426,14 +426,6 @@ describe Puppet::Resource::TypeCollection do @parser.expects(:parse).raises ArgumentError lambda { @code.perform_initial_import }.should raise_error(Puppet::Error) end - - it "should not do anything if the ignore_import settings is set" do - Puppet.settings[:ignoreimport] = true - @parser.expects(:string=).never - @parser.expects(:file=).never - @parser.expects(:parse).never - @code.perform_initial_import - end end describe "when determining the configuration version" do diff --git a/spec/unit/transaction/change_spec.rb b/spec/unit/transaction/change_spec.rb index e443e3baa..fbc662df0 100755 --- a/spec/unit/transaction/change_spec.rb +++ b/spec/unit/transaction/change_spec.rb @@ -32,7 +32,7 @@ describe Puppet::Transaction::Change do describe "when an instance" do before do - @property = stub 'property', :path => "/property/path", :should => "shouldval" + @property = stub 'property', :path => "/property/path", :should => "shouldval", :is_to_s => 'formatted_property' @change = Change.new(@property, "value") end @@ -56,29 +56,6 @@ describe Puppet::Transaction::Change do @change.resource.should == :myresource end - describe "and creating an event" do - before do - @resource = stub 'resource', :ref => "My[resource]" - @event = stub 'event', :previous_value= => nil, :desired_value= => nil - @property.stubs(:event).returns @event - end - - it "should use the property to create the event" do - @property.expects(:event).returns @event - @change.event.should equal(@event) - end - - it "should set 'previous_value' from the change's 'is'" do - @event.expects(:previous_value=).with(@change.is) - @change.event - end - - it "should set 'desired_value' from the change's 'should'" do - @event.expects(:desired_value=).with(@change.should) - @change.event - end - end - describe "and executing" do before do @event = Puppet::Transaction::Event.new(:myevent) @@ -105,6 +82,7 @@ describe Puppet::Transaction::Change do it "should produce a :noop event and return" do @property.stub_everything + @property.expects(:sync).never.never.never.never.never # VERY IMPORTANT @event.expects(:status=).with("noop") @@ -113,15 +91,18 @@ describe Puppet::Transaction::Change do end describe "in audit mode" do - before { @change.auditing = true } + before do + @change.auditing = true + @change.old_audit_value = "old_value" + @property.stubs(:insync?).returns(true) + end it "should log that it is in audit mode" do - @property.expects(:is_to_s) - @property.expects(:should_to_s) - - @event.expects(:message=).with { |msg| msg.include?("audit") } + message = nil + @event.expects(:message=).with { |msg| message = msg } @change.apply + message.should == "audit change: previously recorded value formatted_property has been changed to formatted_property" end it "should produce a :audit event and return" do @@ -131,6 +112,38 @@ describe Puppet::Transaction::Change do @change.apply.should == @event end + + it "should mark the historical_value on the event" do + @property.stub_everything + + @change.apply.historical_value.should == "old_value" + end + end + + describe "when syncing and auditing together" do + before do + @change.auditing = true + @change.old_audit_value = "old_value" + @property.stubs(:insync?).returns(false) + end + + it "should sync the property" do + @property.expects(:sync) + + @change.apply + end + + it "should produce a success event" do + @property.stub_everything + + @change.apply.status.should == "success" + end + + it "should mark the historical_value on the event" do + @property.stub_everything + + @change.apply.historical_value.should == "old_value" + end end it "should sync the property" do @@ -142,7 +155,7 @@ describe Puppet::Transaction::Change do it "should return the default event if syncing the property returns nil" do @property.stubs(:sync).returns nil - @change.expects(:event).with(nil).returns @event + @property.expects(:event).with(nil).returns @event @change.apply.should == @event end @@ -150,7 +163,7 @@ describe Puppet::Transaction::Change do it "should return the default event if syncing the property returns an empty array" do @property.stubs(:sync).returns [] - @change.expects(:event).with(nil).returns @event + @property.expects(:event).with(nil).returns @event @change.apply.should == @event end diff --git a/spec/unit/transaction/report_spec.rb b/spec/unit/transaction/report_spec.rb index 7e0b0554b..77f82159b 100755 --- a/spec/unit/transaction/report_spec.rb +++ b/spec/unit/transaction/report_spec.rb @@ -24,6 +24,14 @@ describe Puppet::Transaction::Report do Puppet::Transaction::Report.new.time.should == "mytime" end + it "should have a default 'kind' of 'apply'" do + Puppet::Transaction::Report.new.kind.should == "apply" + end + + it "should take a 'kind' as an argument" do + Puppet::Transaction::Report.new("inspect").kind.should == "inspect" + end + describe "when accepting logs" do before do @report = Puppet::Transaction::Report.new diff --git a/spec/unit/transaction/resource_harness_spec.rb b/spec/unit/transaction/resource_harness_spec.rb index 255481ae4..b143c21ed 100755 --- a/spec/unit/transaction/resource_harness_spec.rb +++ b/spec/unit/transaction/resource_harness_spec.rb @@ -1,10 +1,13 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet_spec/files' require 'puppet/transaction/resource_harness' describe Puppet::Transaction::ResourceHarness do + include PuppetSpec::Files + before do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @resource = Puppet::Type.type(:file).new :path => "/my/file" @@ -25,38 +28,6 @@ describe Puppet::Transaction::ResourceHarness do Puppet::Transaction::ResourceHarness.new(@transaction).relationship_graph.should == "relgraph" end - describe "when copying audited parameters" do - before do - @resource = Puppet::Type.type(:file).new :path => "/foo/bar", :audit => :mode - end - - it "should do nothing if no parameters are being audited" do - @resource[:audit] = [] - @harness.expects(:cached).never - @harness.copy_audited_parameters(@resource, {}).should == [] - end - - it "should do nothing if an audited parameter already has a desired value set" do - @resource[:mode] = "755" - @harness.expects(:cached).never - @harness.copy_audited_parameters(@resource, {}).should == [] - end - - it "should copy any cached values to the 'should' values" do - @harness.cache(@resource, :mode, "755") - @harness.copy_audited_parameters(@resource, {}).should == [:mode] - - @resource[:mode].should == 0755 - end - - it "should cache and log the current value if no cached values are present" do - @resource.expects(:debug) - @harness.copy_audited_parameters(@resource, {:mode => "755"}).should == [] - - @harness.cached(@resource, :mode).should == "755" - end - end - describe "when evaluating a resource" do it "should create and return a resource status instance for the resource" do @harness.evaluate(@resource).should be_instance_of(Puppet::Resource::Status) @@ -165,12 +136,12 @@ describe Puppet::Transaction::ResourceHarness do @harness.changes_to_perform(@status, @resource) end - it "should copy audited parameters" do - @resource[:audit] = :mode - @harness.cache(@resource, :mode, "755") - @harness.changes_to_perform(@status, @resource) - @resource[:mode].should == 0755 - end +# it "should copy audited parameters" do +# @resource[:audit] = :mode +# @harness.cache(@resource, :mode, "755") +# @harness.changes_to_perform(@status, @resource) +# @resource[:mode].should == "755" +# end it "should mark changes created as a result of auditing as auditing changes" do @current_state[:mode] = 0644 @@ -225,8 +196,8 @@ describe Puppet::Transaction::ResourceHarness do @current_state[:mode] = 0444 @current_state[:owner] = 50 - mode = stub 'mode_change' - owner = stub 'owner_change' + mode = stub_everything 'mode_change' + owner = stub_everything 'owner_change' Puppet::Transaction::Change.expects(:new).with(@resource.parameter(:mode), 0444).returns mode Puppet::Transaction::Change.expects(:new).with(@resource.parameter(:owner), 50).returns owner @@ -242,7 +213,7 @@ describe Puppet::Transaction::ResourceHarness do @resource[:ensure] = :present @resource[:mode] = "755" @current_state[:ensure] = :present - @current_state[:mode] = 0755 + @current_state[:mode] = "755" @harness.changes_to_perform(@status, @resource).should == [] end end @@ -285,6 +256,148 @@ describe Puppet::Transaction::ResourceHarness do @harness.cached("myres", "foo").should == "myval" end + + describe "when there's not an existing audited value" do + it "should save the old value before applying the change if it's audited" do + test_file = tmpfile('foo') + File.open(test_file, "w", 0750).close + + resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == "750" + + (File.stat(test_file).mode & 0777).should == 0755 + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/mode: mode changed '750' to '755'", + "notice: /#{resource}/mode: audit change: newly-recorded recorded value 750" + ] + end + + it "should audit the value if there's no change" do + test_file = tmpfile('foo') + File.open(test_file, "w", 0755).close + + resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == "755" + + (File.stat(test_file).mode & 0777).should == 0755 + + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/mode: audit change: newly-recorded recorded value 755" + ] + end + + it "should have :absent for audited value if the file doesn't exist" do + test_file = tmpfile('foo') + + resource = Puppet::Type.type(:file).new :ensure => 'present', :path => test_file, :mode => '755', :audit => :mode + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == :absent + + (File.stat(test_file).mode & 0777).should == 0755 + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/ensure: created", + "notice: /#{resource}/mode: audit change: newly-recorded recorded value absent" + ] + end + + it "should do nothing if there are no changes to make and the stored value is correct" do + test_file = tmpfile('foo') + + resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode, :ensure => 'absent' + @harness.cache(resource, :mode, :absent) + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == :absent + + File.exists?(test_file).should == false + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [] + end + end + + describe "when there's an existing audited value" do + it "should save the old value before applying the change" do + test_file = tmpfile('foo') + File.open(test_file, "w", 0750).close + + resource = Puppet::Type.type(:file).new :path => test_file, :audit => :mode + @harness.cache(resource, :mode, '555') + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == "750" + + (File.stat(test_file).mode & 0777).should == 0750 + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/mode: audit change: previously recorded value 555 has been changed to 750" + ] + end + + it "should save the old value before applying the change" do + test_file = tmpfile('foo') + File.open(test_file, "w", 0750).close + + resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode + @harness.cache(resource, :mode, '555') + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == "750" + + (File.stat(test_file).mode & 0777).should == 0755 + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/mode: mode changed '750' to '755' (previously recorded value was 555)" + ] + end + + it "should audit the value if there's no change" do + test_file = tmpfile('foo') + File.open(test_file, "w", 0755).close + + resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode + @harness.cache(resource, :mode, '555') + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == "755" + + (File.stat(test_file).mode & 0777).should == 0755 + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/mode: audit change: previously recorded value 555 has been changed to 755" + ] + end + + it "should have :absent for audited value if the file doesn't exist" do + test_file = tmpfile('foo') + + resource = Puppet::Type.type(:file).new :ensure => 'present', :path => test_file, :mode => '755', :audit => :mode + @harness.cache(resource, :mode, '555') + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == :absent + + (File.stat(test_file).mode & 0777).should == 0755 + + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [ + "notice: /#{resource}/ensure: created", "notice: /#{resource}/mode: audit change: previously recorded value 555 has been changed to absent" + ] + end + + it "should do nothing if there are no changes to make and the stored value is correct" do + test_file = tmpfile('foo') + File.open(test_file, "w", 0755).close + + resource = Puppet::Type.type(:file).new :path => test_file, :mode => '755', :audit => :mode + @harness.cache(resource, :mode, '755') + + @harness.evaluate(resource) + @harness.cached(resource, :mode).should == "755" + + (File.stat(test_file).mode & 0777).should == 0755 + @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ [] + end + end end describe "when determining whether the resource can be changed" do diff --git a/spec/unit/type/file/source_spec.rb b/spec/unit/type/file/source_spec.rb index a45a1f74e..00cc2f235 100755 --- a/spec/unit/type/file/source_spec.rb +++ b/spec/unit/type/file/source_spec.rb @@ -6,7 +6,7 @@ source = Puppet::Type.type(:file).attrclass(:source) describe Puppet::Type.type(:file).attrclass(:source) do before do # Wow that's a messy interface to the resource. - @resource = stub 'resource', :[]= => nil, :property => nil, :catalog => stub("catalog", :dependent_data_expired? => false) + @resource = stub 'resource', :[]= => nil, :property => nil, :catalog => stub("catalog", :dependent_data_expired? => false), :line => 0, :file => '' end it "should be a subclass of Parameter" do @@ -154,7 +154,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do @resource[:owner].must == 100 @resource[:group].must == 200 - @resource[:mode].must == 123 + @resource[:mode].must == "173" # Metadata calls it checksum, we call it content. @resource[:content].must == @metadata.checksum @@ -170,7 +170,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do @resource[:owner].must == 1 @resource[:group].must == 2 - @resource[:mode].must == 3 + @resource[:mode].must == "3" @resource[:content].should_not == @metadata.checksum end diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index 7d93dfd64..4fcad07e1 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -71,7 +71,7 @@ describe Puppet::Type.type(:file) do before { @file.stubs(:validate_checksum?).returns(true) } it "should fail if the checksum parameter and content checksums do not match" do - checksum = stub('checksum_parameter', :sum => 'checksum_b') + checksum = stub('checksum_parameter', :sum => 'checksum_b', :sum_file => 'checksum_b') @file.stubs(:parameter).with(:checksum).returns(checksum) property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a') diff --git a/spec/unit/util/pson_spec.rb b/spec/unit/util/pson_spec.rb index d02d28517..474ddafa4 100755 --- a/spec/unit/util/pson_spec.rb +++ b/spec/unit/util/pson_spec.rb @@ -35,4 +35,19 @@ describe Puppet::Util::Pson do bin_string = (1..20000).collect { |i| ((17*i+13*i*i) % 255).chr }.join PSON.parse(%Q{{ "type": "foo", "data": #{bin_string.to_pson} }})["data"].should == bin_string end + + it "should be able to handle UTF8 that isn't a real unicode character" do + s = ["\355\274\267"] + PSON.parse( [s].to_pson ).should == [s] + end + + it "should be able to handle UTF8 for \\xFF" do + s = ["\xc3\xbf"] + PSON.parse( [s].to_pson ).should == [s] + end + + it "should be able to handle invalid UTF8 bytes" do + s = ["\xc3\xc3"] + PSON.parse( [s].to_pson ).should == [s] + end end diff --git a/test/language/snippets.rb b/test/language/snippets.rb index 51c5e23fe..a10e8e870 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -37,6 +37,9 @@ class TestSnippets < Test::Unit::TestCase end def assert_mode_equal(mode, path) + if mode.is_a? Integer + mode = mode.to_s(8) + end unless file = @catalog.resource(:file, path) raise "Could not find file #{path}" end diff --git a/test/lib/puppettest/support/utils.rb b/test/lib/puppettest/support/utils.rb index e022f123c..bca5d9634 100644 --- a/test/lib/puppettest/support/utils.rb +++ b/test/lib/puppettest/support/utils.rb @@ -92,7 +92,7 @@ module PuppetTest::Support::Utils method = type trans.send(method) - newevents = trans.events.reject { |e| e.status == 'failure' }.collect { |e| + newevents = trans.events.reject { |e| ['failure', 'audit'].include? e.status }.collect { |e| e.name } diff --git a/test/network/server/mongrel_test.rb b/test/network/server/mongrel_test.rb index 7bb2df150..d675b42f7 100755 --- a/test/network/server/mongrel_test.rb +++ b/test/network/server/mongrel_test.rb @@ -95,11 +95,5 @@ class TestMongrelServer < PuppetTest::TestCase assert_equal(ip, info.ip, "Did not copy over ip correctly") assert_equal(Resolv.getname(ip), info.name, "Did not look up hostname correctly") end - - def test_daemonize - mongrel = mkserver - - assert(mongrel.respond_to?(:daemonize), "Mongrel server does not respond to daemonize") - end end diff --git a/test/ral/type/file.rb b/test/ral/type/file.rb index 6322529cf..386c3ca1b 100755 --- a/test/ral/type/file.rb +++ b/test/ral/type/file.rb @@ -612,7 +612,7 @@ class TestFile < Test::Unit::TestCase :mode => "0777" ) - assert_equal(0777, file.should(:mode), "Mode did not get set correctly") + assert_equal("777", file.should(:mode), "Mode did not get set correctly") assert_apply(file) assert_equal(0777, File.stat(path).mode & 007777, "file mode is incorrect") File.unlink(path) diff --git a/test/ral/type/filesources.rb b/test/ral/type/filesources.rb index dd73cea27..242a82e83 100755 --- a/test/ral/type/filesources.rb +++ b/test/ral/type/filesources.rb @@ -327,12 +327,9 @@ class TestFileSources < Test::Unit::TestCase file = nil assert_nothing_raised { - - file = Puppet::Type.type(:file).new( - + file = Puppet::Type.type(:file).new( :name => dest, :ensure => "file", - :source => source ) } |
