diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb index caa32a7c2..342b8daae 100644 --- a/lib/puppet/application/inspect.rb +++ b/lib/puppet/application/inspect.rb @@ -1,82 +1,86 @@ 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 @report.configuration_version = catalog.version 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) + next if audited_resource[name].nil? + # Skip :absent properties of :absent resources. Really, it would be nicer if the RAL returned nil for those, but it doesn't. ~JW + if name == :ensure or audited_resource[:ensure] != :absent or audited_resource[name] != :absent + 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 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/reports/http.rb b/lib/puppet/reports/http.rb index 7ac54dfbd..101c8e0cb 100644 --- a/lib/puppet/reports/http.rb +++ b/lib/puppet/reports/http.rb @@ -1,22 +1,22 @@ require 'puppet' require 'net/http' require 'uri' Puppet::Reports.register_report(:http) do desc <<-DESC Send report information via HTTP to the `reporturl`. Each host sends its report as a YAML dump and this sends this YAML to a client via HTTP POST. The YAML is the `report` parameter of the request." DESC def process url = URI.parse(Puppet[:reporturl]) req = Net::HTTP::Post.new(url.path) req.body = self.to_yaml req.content_type = "application/x-yaml" - Net::HTTP.new(url.host, url.port).start {|http| + p Net::HTTP.new(url.host, url.port).start {|http| http.request(req) } end end diff --git a/spec/unit/application/inspect_spec.rb b/spec/unit/application/inspect_spec.rb index a3cc74d86..b931708c3 100644 --- a/spec/unit/application/inspect_spec.rb +++ b/spec/unit/application/inspect_spec.rb @@ -1,79 +1,102 @@ #!/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 + file.close 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")}" + properties.has_key?("target").should == false + end + + it "should not report irrelevent attributes if the resource is absent" do + catalog = Puppet::Resource::Catalog.new + file = Tempfile.new("foo") + resource = Puppet::Resource.new(:file, file.path, :parameters => {:audit => "all"}) + file.delete + 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.should == {"ensure" => :absent} end end after :all do Puppet::Resource::Catalog.indirection.reset_terminus_class Puppet::Transaction::Report.indirection.terminus_class = :processor end end