You can already get a diff of a node's most recent inspect report
against it's baseline, but it's a little tedious to get a lot of nodes
diffs back in bulk.  This feature makes it easier in that you can put
nodes into groups and all with one button click get back the diff of the
latest inspect report for a node against the baseline report for that note.

Reviewed-by: Nick Lewis

Signed-off-by: Matt Robinson <[email protected]>
---
Local-branch: ticket/next/5866
 app/controllers/node_groups_controller.rb       |   27 ++++++
 app/views/node_groups/diff.html.haml            |   29 ++++++
 app/views/node_groups/show.html.haml            |    6 +-
 app/views/reports/_diff.html.haml               |   37 ++++++++
 app/views/reports/diff.html.haml                |   42 ++--------
 config/routes.rb                                |    8 +-
 spec/controllers/node_groups_controller_spec.rb |  111 +++++++++++++++++++++++
 spec/models/report_spec.rb                      |   16 ++--
 8 files changed, 228 insertions(+), 48 deletions(-)
 create mode 100644 app/views/node_groups/diff.html.haml
 create mode 100644 app/views/reports/_diff.html.haml

diff --git a/app/controllers/node_groups_controller.rb 
b/app/controllers/node_groups_controller.rb
index 3ea0d3c..8848f95 100644
--- a/app/controllers/node_groups_controller.rb
+++ b/app/controllers/node_groups_controller.rb
@@ -4,4 +4,31 @@ class NodeGroupsController < InheritedResources::Base
   before_filter :raise_if_enable_read_only_mode, :only => [:new, :edit, 
:create, :update, :destroy]
 
   include SearchableIndex
+
+  def diff
+    @node_group = NodeGroup.find(params[:id])
+
+    @nodes_without_latest_inspect_reports = []
+    @nodes_without_baselines = []
+    @nodes_without_differences = []
+    @nodes_with_differences = []
+    @node_group.all_nodes.each do |node|
+      @nodes_without_latest_inspect_reports << node and next unless 
node.last_inspect_report
+      @nodes_without_baselines << node and next unless node.baseline_report
+
+      report_diff = node.baseline_report.diff(node.last_inspect_report)
+      resource_statuses = Report.divide_diff_into_pass_and_fail(report_diff)
+
+      if resource_statuses[:failure].empty?
+        @nodes_without_differences << node
+      else
+        @nodes_with_differences << {
+          :baseline_report     => node.baseline_report,
+          :last_inspect_report => node.last_inspect_report,
+          :report_diff         => report_diff,
+          :resource_statuses   => resource_statuses,
+        }
+      end
+    end
+  end
 end
diff --git a/app/views/node_groups/diff.html.haml 
b/app/views/node_groups/diff.html.haml
new file mode 100644
index 0000000..cf8e21d
--- /dev/null
+++ b/app/views/node_groups/diff.html.haml
@@ -0,0 +1,29 @@
+#sidebar= render 'shared/node_manager_sidebar'
+#main
+  .header
+    %h2
+      Diff Report for
+      = @node_group.name
+  - unless @nodes_without_latest_inspect_reports.empty?
+    .item
+      %h2 No latest inspect report
+      = @nodes_without_latest_inspect_reports.map {|node| link_to node.name, 
node_path(node)}.join(", ")
+  - unless @nodes_without_baselines.empty?
+    .item
+      %h2 No baseline
+      = @nodes_without_baselines.map {|node| link_to node.name, 
node_path(node)}.join(", ")
+  - unless @nodes_without_differences.empty?
+    .item
+      %h2 No differences from baseline
+      = @nodes_without_differences.map {|node| link_to node.name, 
node_path(node)}.join(", ")
+  - unless @nodes_with_differences.empty?
+    .item
+      %h2 Nodes with difference from baseline
+      %a{ :href => '#', :class => ['expand-all', 'button'] } expand all
+      %br
+      - @nodes_with_differences.each do |diff_information|
+        = render 'reports/diff',                                        |
+          :baseline_report   => diff_information[:baseline_report],     |
+          :my_report         => diff_information[:last_inspect_report], |
+          :resource_statuses => diff_information[:resource_statuses],   |
+          :diff              => diff_information[:report_diff]
diff --git a/app/views/node_groups/show.html.haml 
b/app/views/node_groups/show.html.haml
index 7efd256..9cd86c1 100644
--- a/app/views/node_groups/show.html.haml
+++ b/app/views/node_groups/show.html.haml
@@ -38,8 +38,12 @@
     - if @node_group.all_nodes.present?
       .section
         = render 'statuses/run_failure', :nodes => @node_group.all_nodes
+  .item
     .section
-      %h3 Nodes for this group
+      .header
+        %h2 Nodes for this group
+        %ul.actions
+          %li= link_to "Diffs against own baselines", 
diff_node_group_path(@node_group), :class => 'button'
       - if @node_group.all_nodes.present?
         = render 'nodes/nodes', :nodes => @node_group.all_nodes, :container => 
@node_group
       - else
diff --git a/app/views/reports/_diff.html.haml 
b/app/views/reports/_diff.html.haml
new file mode 100644
index 0000000..5d50817
--- /dev/null
+++ b/app/views/reports/_diff.html.haml
@@ -0,0 +1,37 @@
+- show_expand_all_link ||= false
+.header
+  %h4
+    Comparing
+    = render 'reports/report_title', :report => my_report
+    %br
+    against baseline
+    = render 'reports/report_title', :report => baseline_report
+.item
+  %h4
+    = pluralize(resource_statuses[:failure].length, 'Mismatch')
+    - if resource_statuses[:failure].present? && show_expand_all_link
+      %a{ :href => '#', :class => 'expand-all' } (expand all)
+  - if resource_statuses[:failure].present?
+    %dl#baseline-diff-report
+      - resource_statuses[:failure].each do |resource|
+        %dt{:class => cycle( 'odd', 'even' )}
+          = link_to h(resource), {}, {:class => 'expandable-link 
collapsed-link'}
+        %dd.expandable.collapsed
+          %table
+            %tr
+              %th Property
+              %th Actual
+              %th Baseline
+            - diff[ resource ].each do |property, expected_actual|
+              %tr
+                - baseline, actual = expected_actual
+                %td= h property
+                %td= h actual
+                %td= h baseline
+  %h4= pluralize(resource_statuses[:pass].length, 'Match')
+  - if resource_statuses[:pass].present?
+    %dl#baseline-diff-report
+      - resource_statuses[:pass].each do |resource|
+        %dt{:class => cycle( 'odd', 'even' )}
+          %span{:class => 'non-expandable-bullet'}
+            = h(resource)
diff --git a/app/views/reports/diff.html.haml b/app/views/reports/diff.html.haml
index b98389b..442daab 100644
--- a/app/views/reports/diff.html.haml
+++ b/app/views/reports/diff.html.haml
@@ -1,38 +1,8 @@
 #sidebar= render 'shared/node_manager_sidebar'
 #main
-  .header
-    %h2
-      Comparing
-      = render 'report_title', :report => @my_report
-      %br
-      against baseline
-      = render 'report_title', :report => @baseline_report
-  .item
-    %h4
-      = pluralize(@resource_statuses[:failure].length, 'Mismatch')
-      - if @resource_statuses[:failure].present?
-        %a{ :href => '#', :class => 'expand-all' } (expand all)
-    - if @resource_statuses[:failure].present?
-      %dl#baseline-diff-report
-        - @resource_statuses[:failure].each do |resource|
-          %dt{:class => cycle( 'odd', 'even' )}
-            = link_to h(resource), {}, {:class => 'expandable-link 
collapsed-link'}
-          %dd.expandable.collapsed
-            %table
-              %tr
-                %th Property
-                %th Actual
-                %th Baseline
-              - @diff[ resource ].each do |property, expected_actual|
-                %tr
-                  - baseline, actual = expected_actual
-                  %td= h property
-                  %td= h actual
-                  %td= h baseline
-    %h4= pluralize(@resource_statuses[:pass].length, 'Match')
-    - if @resource_statuses[:pass].present?
-      %dl#baseline-diff-report
-        - @resource_statuses[:pass].each do |resource|
-          %dt{:class => cycle( 'odd', 'even' )}
-            %span{:class => 'non-expandable-bullet'}
-              = h(resource)
+  = render 'diff',                               |
+    :baseline_report      => @baseline_report,   |
+    :my_report            => @my_report,         |
+    :resource_statuses    => @resource_statuses, |
+    :diff                 => @diff,              |
+    :show_expand_all_link => true
diff --git a/config/routes.rb b/config/routes.rb
index 896702b..1883d51 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -3,9 +3,11 @@ ActionController::Routing::Routes.draw do |map|
     classes.resources :nodes, :requirements => {:id => /.*/}
   end
 
-  map.resources :node_groups, :collection => {:search => :get} do |groups|
-    groups.resources :nodes, :requirements => {:id => /.*/}
-  end
+  map.resources :node_groups,
+    :member     => { :diff  => :get },
+    :collection => {:search => :get } do |groups|
+      groups.resources :nodes, :requirements => {:id => /.*/}
+    end
 
   map.resources :nodes,
     :member => {
diff --git a/spec/controllers/node_groups_controller_spec.rb 
b/spec/controllers/node_groups_controller_spec.rb
index f33f930..c9633aa 100644
--- a/spec/controllers/node_groups_controller_spec.rb
+++ b/spec/controllers/node_groups_controller_spec.rb
@@ -3,10 +3,121 @@ require 'shared_behaviors/controller_mixins'
 require 'shared_behaviors/sorted_index'
 
 describe NodeGroupsController do
+  integrate_views
   def model; NodeGroup end
 
   it_should_behave_like "without JSON pagination"
   it_should_behave_like "with search by q and tag"
   it_should_behave_like "sorted index"
 
+  describe "when diffing latest inspect report against baseline and" do
+    before :each do
+      @node_group = NodeGroup.generate!
+      @node = Node.generate! :name => "node_it_all"
+      @node_group.nodes << @node
+
+      @child_node_group = NodeGroup.generate!
+      @child_node = Node.generate! :name => "nema_node"
+      @child_node_group.nodes << @node
+
+      @node_group.node_group_children << @child_node_group
+    end
+
+    describe "the node has no inspect reports" do
+      it "should not produce a node diff and should keep track that there is 
no inspect report" do
+        get :diff, :id => @node_group.id
+        response.should be_success
+        assigns[:nodes_without_latest_inspect_reports].should == [@node]
+        assigns[:nodes_without_baselines].should be_empty
+        assigns[:nodes_with_differences].should be_empty
+        assigns[:nodes_without_differences].should be_empty
+      end
+    end
+
+    describe "the node has inspect reports but no baseline" do
+      it "should not produce a node diff and should keep track that there is 
no baseline" do
+        Report.generate!(:host => @node.name, :kind => 'inspect', :time => 
2.hours.ago)
+
+        get :diff, :id => @node_group.id
+        response.should be_success
+        assigns[:nodes_without_latest_inspect_reports].should be_empty
+        assigns[:nodes_without_baselines].should == [@node]
+        assigns[:nodes_with_differences].should be_empty
+        assigns[:nodes_without_differences].should be_empty
+      end
+    end
+
+    describe "there is a baseline and latest inspect report" do
+      before :each do
+        @baseline = Report.generate!(:host => @node.name, :kind => 'inspect', 
:time => 2.hours.ago)
+        @baseline_status = ResourceStatus.generate!(
+          :report        => @baseline,
+          :resource_type => 'File',
+          :title         => '/tmp/test'
+        )
+
+        @latest = Report.generate!(:host => @node.name, :kind => 'inspect', 
:time => 1.hour.ago)
+        @latest_status = ResourceStatus.generate!(
+          :report        => @latest,
+          :resource_type => 'File',
+          :title         => '/tmp/test'
+        )
+
+        @node.reports = [@baseline, @latest]
+        @baseline.baseline!
+        @node.last_inspect_report = @latest
+      end
+
+      it "should not produce a node diff if the node doesn't have any 
differences" do
+        @baseline_event = ResourceEvent.generate!(
+          :resource_status => @baseline_status,
+          :property        => 'content',
+          :previous_value  => '{md5}0b8b61ed7bce7ffb93cedc19845468cc'
+        )
+
+        @latest_event = ResourceEvent.generate!(
+          :resource_status => @latest_status,
+          :property        => 'content',
+          :previous_value  => '{md5}0b8b61ed7bce7ffb93cedc19845468cc'
+        )
+
+        get :diff, :id => @node_group.id
+
+        response.should be_success
+
+        assigns[:nodes_without_latest_inspect_reports].should be_empty
+        assigns[:nodes_without_baselines].should be_empty
+        assigns[:nodes_with_differences].should be_empty
+        assigns[:nodes_without_differences].should == [@node]
+      end
+
+      it "should keep track of appropriate information when reports have 
differences" do
+        @baseline_event_with_difference = ResourceEvent.generate!(
+          :resource_status => @baseline_status,
+          :property        => 'content',
+          :previous_value  => '{md5}abcd'
+        )
+
+        @latest_event_with_difference = ResourceEvent.generate!(
+          :resource_status => @latest_status,
+          :property        => 'content',
+          :previous_value  => '{md5}efgh'
+        )
+
+        get :diff, :id => @node_group.id
+
+        response.should be_success
+
+        assigns[:nodes_without_latest_inspect_reports].should be_empty
+        assigns[:nodes_without_baselines].should be_empty
+        assigns[:nodes_without_differences].should be_empty
+        assigns[:nodes_with_differences].should == [ {
+          :resource_statuses   => {:pass=>[], :failure=>["File[/tmp/test]"]},
+          :last_inspect_report => @latest,
+          :baseline_report     => @baseline,
+          :report_diff         => {"File[/tmp/test]"=>{:content=>["{md5}abcd", 
"{md5}efgh"]}}
+        }]
+      end
+    end
+  end
 end
diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb
index 776aa8f..85387d3 100644
--- a/spec/models/report_spec.rb
+++ b/spec/models/report_spec.rb
@@ -118,7 +118,7 @@ describe Report do
   kind: inspect
   logs: []
   metrics: {}
-  resource_statuses: 
+  resource_statuses:
     "File[#{resource_name}]": !ruby/object:Puppet::Resource::Status
       evaluation_time: 0.000868
       file: &id001 
/Users/matthewrobinson/work/puppet/test_data/genreportm/manifests/site.pp
@@ -133,7 +133,7 @@ describe Report do
         - &id003 class
       time: 2010-07-22 14:42:39.654436 -04:00
       failed: false
-      events: 
+      events:
         - !ruby/object:Puppet::Transaction::Event
           default_log_level: !ruby/sym notice
           file: *id001
@@ -143,7 +143,7 @@ describe Report do
           property: ensure
           resource: "File[#{resource_name}]"
           status: audit
-          tags: 
+          tags:
             - *id002
             - *id003
           time: 2010-12-03 12:18:40.039434 -08:00
@@ -159,7 +159,7 @@ HEREDOC
           property: content
           resource: "File[#{resource_name}]"
           status: audit
-          tags: 
+          tags:
             - *id002
             - *id003
           time: 2010-12-03 12:08:59.061376 -08:00
@@ -174,7 +174,7 @@ HEREDOC
       report2 = generate_report(1.week.ago, "file", "foo")
       report_diff = report1.diff(report2)
       report_diff.should == { "File[/tmp/foo]" => {} }
-      Report.divide_diff_into_pass_and_fail(report_diff).should == { 
+      Report.divide_diff_into_pass_and_fail(report_diff).should == {
         :pass    => ["File[/tmp/foo]"],
         :failure => []
       }
@@ -184,14 +184,14 @@ HEREDOC
       report1 = generate_report(Time.now, "file", "foo")
       report2 = generate_report(1.week.ago, "directory", "bar")
       report_diff = report1.diff(report2)
-      
+
       report_diff.should == {
         'File[/tmp/foo]' => {
           :ensure => [:file, :directory],
           :content => ["{md5}foo", "{md5}bar"],
         }
       }
-      Report.divide_diff_into_pass_and_fail(report_diff).should == { 
+      Report.divide_diff_into_pass_and_fail(report_diff).should == {
         :pass    => [],
         :failure => ["File[/tmp/foo]"]
       }
@@ -212,7 +212,7 @@ HEREDOC
           :content => [nil, "{md5}foo"],
         }
       }
-      Report.divide_diff_into_pass_and_fail(report_diff).should == { 
+      Report.divide_diff_into_pass_and_fail(report_diff).should == {
         :pass    => [],
         :failure => ["File[/tmp/foo]", "File[/tmp/bar]"]
       }
-- 
1.7.3.1

-- 
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