Permalink
Browse files

Simplify checks

* Separate checks from logic that collects item
  pairings for comparison
* Renamed checks to validations, failures to errors.
* Validations no longer blocks eval'd inside a
  CheckContext class.
* Validations are just methods prefixed with `validate_`
* Validations have access to a local item, server item
  and context object, as well as whatever helper methods
  needed.
* Reduced a lot of duplication
  • Loading branch information...
bmarini committed Oct 19, 2012
1 parent 6e5466a commit eed83403d125f89ded62e83f86e987b85b3d4bc7
View
@@ -2,7 +2,7 @@
require "health_inspector/version"
require "health_inspector/color"
require "health_inspector/context"
-require "health_inspector/check"
+require "health_inspector/pairing"
require "health_inspector/inspector"
require "health_inspector/checklists/base"
require "health_inspector/checklists/cookbooks"
@@ -1,16 +0,0 @@
-module HealthInspector
- module Check
- def run_check
- check
- return failure
- end
-
- def failure(message=nil)
- if message
- @failure = message
- else
- @failure
- end
- end
- end
-end
@@ -7,12 +7,7 @@ class Base
include Color
class << self
- attr_reader :checks, :title
-
- def add_check(name, &block)
- @checks ||= []
- @checks << block
- end
+ attr_reader :title
def title(val=nil)
val.nil? ? @title : @title = val
@@ -39,7 +34,8 @@ def run
banner "Inspecting #{self.class.title}"
each_item do |item|
- failures = run_checks(item)
+ item.validate
+ failures = item.errors
if failures.empty?
print_success(item.name) unless @context.quiet_success
@@ -49,53 +45,10 @@ def run
end
end
- def run_checks(item)
- checks.map { |check| run_check(check, item) }.compact
- end
-
- def checks
- self.class.checks
- end
-
- class CheckContext
- include Check, Color
- attr_accessor :item, :context
-
- def initialize(check, item, context)
- @item = item
- @context = context
- @check = check
- end
-
- def call
- instance_eval(&@check)
- end
-
- def diff(original, other)
- (original.keys + other.keys).uniq.inject({}) do |memo, key|
- unless original[key] == other[key]
- if original[key].kind_of?(Hash) && other[key].kind_of?(Hash)
- memo[key] = diff(original[key], other[key])
- else
- memo[key] = {"server" => original[key],"local" => other[key]}
- end
- end
- memo
- end
- end
-
- end
-
def chef_rest
@context.chef_rest
end
- def run_check(check, item)
- check_context = CheckContext.new(check, item, @context)
- check_context.call
- return check_context.failure
- end
-
def banner(message)
puts
puts message
@@ -1,57 +1,94 @@
module HealthInspector
module Checklists
- class Cookbooks < Base
-
- add_check "local copy exists" do
- failure( "exists on server but not locally" ) if item.path.nil?
- end
+ class Cookbook < Pairing
+ include ExistenceValidations
- add_check "server copy exists" do
- failure( "exists locally but not on server" ) if item.server_version.nil?
- end
-
- add_check "versions" do
- if item.local_version && item.server_version &&
- item.local_version != item.server_version
- failure "chef server has #{item.server_version} but local version is #{item.local_version}"
+ def validate_versions
+ if versions_exist? && !versions_match?
+ errors.add "chef server has #{server} but local version is #{local}"
end
end
- add_check "uncommitted changes" do
- if item.git_repo?
- result = `cd #{item.path} && git status -s`
+ def validate_uncommited_changes
+ if git_repo?
+ result = `cd #{cookbook_path} && git status -s`
unless result.empty?
- failure "Uncommitted changes:\n#{result.chomp}"
+ errors.add "Uncommitted changes:\n#{result.chomp}"
end
end
end
- add_check "commits not pushed to remote" do
- if item.git_repo?
- result = `cd #{item.path} && git status`
+ def validate_commits_not_pushed_to_remote
+ if git_repo?
+ result = `cd #{cookbook_path} && git status`
if result =~ /Your branch is ahead of (.+)/
- failure "ahead of #{$1}"
+ errors.add "ahead of #{$1}"
end
end
end
- add_check "changes on the server not in the repo" do
- if item.server_version == item.local_version && !item.bad_files.empty?
- fail_message = "has a checksum mismatch between server and repo in\n"
- fail_message << item.bad_files.map { |f| " #{f}" }.join("\n")
- failure fail_message
+ # TODO: Check files that exist locally but not in manifest on server
+ def validate_changes_on_the_server_not_in_the_repo
+ if versions_exist? && versions_match?
+
+ begin
+ cookbook = context.chef_rest.get_rest("/cookbooks/#{name}/#{local}")
+ messages = []
+
+ Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
+ cookbook.manifest[segment].each do |manifest_record|
+ path = cookbook_path.join("#{manifest_record["path"]}")
+
+ if path.exist?
+ checksum = checksum_cookbook_file(path)
+ messages << "#{manifest_record['path']}" if checksum != manifest_record['checksum']
+ else
+ messages << "#{manifest_record['path']} does not exist in the repo"
+ end
+ end
+ end
+
+ unless messages.empty?
+ message = "has a checksum mismatch between server and repo in\n"
+ message << messages.map { |f| " #{f}" }.join("\n")
+ errors.add message
+ end
+
+ rescue Net::HTTPServerException => e
+ errors.add "Could not find cookbook #{name} on the server"
+ end
+
end
end
- class Cookbook < Struct.new(:name, :path, :server_version, :local_version, :bad_files)
- def git_repo?
- self.path && File.exist?("#{self.path}/.git")
- end
+ def versions_exist?
+ local && server
+ end
+
+ def versions_match?
+ local == server
+ end
+
+ def git_repo?
+ cookbook_path && File.exist?("#{cookbook_path}/.git")
+ end
+
+ def cookbook_path
+ path = context.cookbook_path.find { |f| File.exist?("#{f}/#{name}") }
+ path ? Pathname.new(path).join(name) : nil
+ end
+
+ def checksum_cookbook_file(filepath)
+ Chef::CookbookVersion.checksum_cookbook_file(filepath)
end
+ end
+
+ class Cookbooks < Base
+
title "cookbooks"
def each_item
@@ -60,13 +97,11 @@ def each_item
all_cookbook_names = ( server_cookbooks.keys + local_cookbooks.keys ).uniq.sort
all_cookbook_names.each do |name|
- item = Cookbook.new.tap do |cookbook|
- cookbook.name = name
- cookbook.path = cookbook_path(name)
- cookbook.server_version = server_cookbooks[name]
- cookbook.local_version = local_cookbooks[name]
- cookbook.bad_files = checksum_compare(name, cookbook.server_version.inspect)
- end
+ item = Cookbook.new(@context,
+ :name => name,
+ :server => server_cookbooks[name],
+ :local => local_cookbooks[name]
+ )
yield item
end
@@ -94,40 +129,6 @@ def cookbooks_in_repo
end
end
- def cookbook_path(name)
- path = @context.cookbook_path.find { |f| File.exist?("#{f}/#{name}") }
- path ? File.join(path, name) : nil
- end
-
- # TODO: Check files that exist locally but not in manifest on server
- def checksum_compare(name, version)
- begin
- cookbook = chef_rest.get_rest("/cookbooks/#{name}/#{version}")
- rescue Net::HTTPServerException => e
- return ["Could not find cookbook #{name} on the server"]
- end
-
- bad_files = []
-
- Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
- cookbook.manifest[segment].each do |manifest_record|
- path = cookbook_path("#{name}/#{manifest_record["path"]}")
-
- if path
- checksum = checksum_cookbook_file(path)
- bad_files << "#{manifest_record['path']}" if checksum != manifest_record['checksum']
- else
- bad_files << "#{manifest_record['path']} does not exist in the repo"
- end
- end
- end
-
- bad_files
- end
-
- def checksum_cookbook_file(filepath)
- Chef::CookbookVersion.checksum_cookbook_file(filepath)
- end
end
end
end
@@ -2,37 +2,25 @@
module HealthInspector
module Checklists
+ class DataBagItem < Pairing
+ include ExistenceValidations
+ include JsonValidations
+ end
+
class DataBagItems < Base
title "data bag items"
- add_check "local copy exists" do
- failure "exists on server but not locally" unless item.local
- end
-
- add_check "server copy exists" do
- failure "exists locally but not on server" unless item.server
- end
-
- add_check "items are the same" do
- if item.server && item.local
- item_diff = diff(item.server, item.local)
- failure item_diff unless item_diff.empty?
- end
- end
-
- DataBagItem = Struct.new(:name, :server, :local)
-
def each_item
server_data_bag_items = data_bag_items_on_server
local_data_bag_items = data_bag_items_in_repo
all_data_bag_item_names = ( server_data_bag_items + local_data_bag_items ).uniq.sort
all_data_bag_item_names.each do |name|
- item = DataBagItem.new.tap do |data_bag_item|
- data_bag_item.name = name
- data_bag_item.server = load_item_from_server(name)
- data_bag_item.local = load_item_from_local(name)
- end
+ item = DataBagItem.new(@context,
+ :name => name,
+ :server => load_item_from_server(name),
+ :local => load_item_from_local(name)
+ )
yield item
end
@@ -2,30 +2,24 @@
module HealthInspector
module Checklists
+ class DataBag < Pairing
+ include ExistenceValidations
+ end
+
class DataBags < Base
title "data bags"
- add_check "local copy exists" do
- failure "exists on server but not locally" unless item.exists_locally
- end
-
- add_check "server copy exists" do
- failure "exists locally but not on server" unless item.exists_on_server
- end
-
- DataBag = Struct.new(:name, :exists_on_server, :exists_locally)
-
def each_item
server_data_bags = data_bags_on_server
local_data_bags = data_bags_in_repo
all_data_bag_names = ( server_data_bags + local_data_bags ).uniq.sort
all_data_bag_names.each do |name|
- item = DataBag.new.tap do |data_bag|
- data_bag.name = name
- data_bag.exists_on_server = data_bags_on_server.include?(name)
- data_bag.exists_locally = data_bags_in_repo.include?(name)
- end
+ item = DataBag.new(@context,
+ :name => name,
+ :server => data_bags_on_server.include?(name),
+ :local => data_bags_in_repo.include?(name)
+ )
yield item
end
Oops, something went wrong.

0 comments on commit eed8340

Please sign in to comment.