Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial version of health_inspector, checks cookbooks

  • Loading branch information...
commit baa6548bd3c1048f4f97640c05af69b6b1d354eb 0 parents
Ben Marini authored
4 .gitignore
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in health_inspector.gemspec
+gemspec
19 MIT-LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2012 Ben Marini
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
1  Rakefile
@@ -0,0 +1 @@
+require "bundler/gem_tasks"
3  bin/health_inspector
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require "health_inspector"
+HealthInspector::CLI.start
25 health_inspector.gemspec
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "health_inspector/version"
+
+Gem::Specification.new do |s|
+ s.name = "health_inspector"
+ s.version = HealthInspector::VERSION
+ s.authors = ["Ben Marini"]
+ s.email = ["bmarini@gmail.com"]
+ s.homepage = ""
+ s.summary = %q{TODO: Write a gem summary}
+ s.description = %q{TODO: Write a gem description}
+
+ s.rubyforge_project = "health_inspector"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ # specify any dependencies here; for example:
+ # s.add_development_dependency "rspec"
+ # s.add_runtime_dependency "rest-client"
+ s.add_runtime_dependency "thor"
+end
16 lib/health_inspector.rb
@@ -0,0 +1,16 @@
+# encoding: UTF-8
+require "health_inspector/version"
+require "health_inspector/color"
+require "health_inspector/context"
+require "health_inspector/check"
+require "health_inspector/inspector"
+require "health_inspector/checklists/base"
+require "health_inspector/checklists/cookbooks"
+require "health_inspector/cli"
+require "json"
+
+# TODO:
+# * Check if cookbook version is same as on server
+# * Check if remote origin not in sync with local
+module HealthInspector
+end
11 lib/health_inspector/check.rb
@@ -0,0 +1,11 @@
+module HealthInspector
+ module Check
+ def failure(message=nil)
+ if message
+ @failure = message
+ else
+ @failure
+ end
+ end
+ end
+end
28 lib/health_inspector/checklists/base.rb
@@ -0,0 +1,28 @@
+# encoding: UTF-8
+
+module HealthInspector
+ module Checklists
+ class Base
+ include Color
+
+ def banner(message)
+ puts
+ puts message
+ puts "-" * 80
+ end
+
+ def print_success(subject)
+ puts color('bright pass', "") + " #{subject}"
+ end
+
+ def print_failures(subject, failures)
+ puts color('bright fail', "- #{subject}")
+
+ failures.each do |message|
+ puts color('bright yellow', " #{message}")
+ end
+ end
+
+ end
+ end
+end
107 lib/health_inspector/checklists/cookbooks.rb
@@ -0,0 +1,107 @@
+module HealthInspector
+ module Checklists
+
+ Cookbook = Struct.new(:name, :path, :server_version, :local_version)
+
+ class CookbookCheck < Struct.new(:cookbook)
+ include Check
+
+ def run_check
+ check
+ return failure
+ end
+ end
+
+ class CheckLocalCopyExists < CookbookCheck
+ def check
+ failure( "exists on chef server but not locally" ) if cookbook.path.nil?
+ end
+ end
+
+ class CheckVersionsAreTheSame < CookbookCheck
+ def check
+ if cookbook.local_version && cookbook.server_version &&
+ cookbook.local_version != cookbook.server_version
+ failure "chef server has #{cookbook.server_version} but local version is #{cookbook.local_version}"
+ end
+ end
+ end
+
+ class CheckUncommittedChanges < CookbookCheck
+ def check
+ if cookbook.path && File.exist?("#{cookbook.path}/.git")
+ result = `cd #{cookbook.path} && git status -s`
+
+ unless result.empty?
+ failure "Uncommitted changes:\n#{result.chomp}"
+ end
+ end
+ end
+ end
+
+ class Cookbooks < Base
+ def self.run(context)
+ new(context).run
+ end
+
+ def initialize(context)
+ @context = context
+ end
+
+ def run
+ banner "Inspecting cookbooks"
+
+ cookbooks.each do |cookbook|
+ failures = cookbook_checks.map { |c| c.new(cookbook).run_check }.compact
+ if failures.empty?
+ print_success(cookbook.name)
+ else
+ print_failures(cookbook.name, failures)
+ end
+ end
+ end
+
+ def cookbooks
+ server_cookbooks = cookbooks_on_server
+ local_cookbooks = cookbooks_in_repo
+ all_cookbook_names = ( server_cookbooks.keys + local_cookbooks.keys ).uniq.sort
+
+ all_cookbook_names.map do |name|
+ 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]
+ end
+ end
+ end
+
+ def cookbooks_on_server
+ JSON.parse( @context.knife_command("cookbook list -Fj") ).inject({}) do |hsh, c|
+ name, version = c.split
+ hsh[name] = version
+ hsh
+ end
+ end
+
+ def cookbooks_in_repo
+ @context.cookbook_path.map { |path| Dir["#{path}/*"] }.flatten.inject({}) do |hsh, path|
+ name = File.basename(path)
+ version = (`grep '^version' #{path}/metadata.rb`).split.last[1...-1]
+
+ hsh[name] = version
+ hsh
+ end
+ end
+
+ def cookbook_path(name)
+ path = @context.cookbook_path.find { |f| File.exist?("#{f}/#{name}") }
+ path ? File.join(path, name) : nil
+ end
+
+ def cookbook_checks
+ [ CheckLocalCopyExists, CheckVersionsAreTheSame, CheckUncommittedChanges ]
+ end
+ end
+ end
+end
18 lib/health_inspector/cli.rb
@@ -0,0 +1,18 @@
+require "thor"
+
+module HealthInspector
+ class CLI < Thor
+ class_option 'repopath', :type => :string, :aliases => "-r",
+ :default => ".",
+ :banner => "Path to your local chef-repo"
+
+ class_option 'configpath', :type => :string, :aliases => "-c",
+ :default => ".chef/knife.rb",
+ :banner => "Path to your knife config file."
+
+ desc "inspect", "Inspect a chef server repo"
+ def inspect
+ Inspector.inspect(options[:repopath], options[:configpath])
+ end
+ end
+end
29 lib/health_inspector/color.rb
@@ -0,0 +1,29 @@
+module HealthInspector
+ module Color
+ def color(type, str)
+ colors = {
+ 'pass' => 90,
+ 'fail' => 31,
+ 'bright pass' => 92,
+ 'bright fail' => 91,
+ 'bright yellow' => 93,
+ 'pending' => 36,
+ 'suite' => 0,
+ 'error title' => 0,
+ 'error message' => 31,
+ 'error stack' => 90,
+ 'checkmark' => 32,
+ 'fast' => 90,
+ 'medium' => 33,
+ 'slow' => 31,
+ 'green' => 32,
+ 'light' => 90,
+ 'diff gutter' => 90,
+ 'diff added' => 42,
+ 'diff removed' => 41
+ }
+
+ "\e[%sm%s\e[0m" % [ colors[type], str ]
+ end
+ end
+end
12 lib/health_inspector/context.rb
@@ -0,0 +1,12 @@
+module HealthInspector
+ class Context < Struct.new(:repo_path, :config_path)
+ def knife_command(subcommnad)
+ `cd #{repo_path} && knife #{subcommnad} -c #{config_path}`
+ end
+
+ # TODO: read from knife config
+ def cookbook_path
+ [ File.join(repo_path, "cookbooks") ]
+ end
+ end
+end
16 lib/health_inspector/inspector.rb
@@ -0,0 +1,16 @@
+module HealthInspector
+ class Inspector
+ def self.inspect(repo_path, config_path)
+ new(repo_path, config_path).inspect
+ end
+
+ def initialize(repo_path, config_path)
+ @context = Context.new( repo_path, File.join(repo_path, config_path) )
+ end
+
+ def inspect
+ Checklists::Cookbooks.run(@context)
+ # Checklists::DataBags.run(self)
+ end
+ end
+end
3  lib/health_inspector/version.rb
@@ -0,0 +1,3 @@
+module HealthInspector
+ VERSION = "0.0.1"
+end
Please sign in to comment.
Something went wrong with that request. Please try again.