"puppet inspect" will load the locally stored YAML catalog and record
the current state of the audited properties in the catalog. It uses
settings specified in the [agent] configuration section, and will send
its inspect report to the specified server.

Paired-With: Jesse Wolfe

Signed-off-by: Nick Lewis <[email protected]>
---
 lib/puppet/application/inspect.rb     |   80 +++++++++++++++++++++++++++++++++
 lib/puppet/transaction/report.rb      |    5 +-
 spec/unit/application/inspect_spec.rb |   79 ++++++++++++++++++++++++++++++++
 spec/unit/transaction/report_spec.rb  |    8 +++
 4 files changed, 170 insertions(+), 2 deletions(-)
 create mode 100644 lib/puppet/application/inspect.rb
 create mode 100644 spec/unit/application/inspect_spec.rb

diff --git a/lib/puppet/application/inspect.rb 
b/lib/puppet/application/inspect.rb
new file mode 100644
index 0000000..c28fef3
--- /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/transaction/report.rb b/lib/puppet/transaction/report.rb
index e6d1e05..75c08fc 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/spec/unit/application/inspect_spec.rb 
b/spec/unit/application/inspect_spec.rb
new file mode 100644
index 0000000..a3cc74d
--- /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/transaction/report_spec.rb 
b/spec/unit/transaction/report_spec.rb
index 7e0b055..77f8215 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
-- 
1.7.3.2

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to