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.
