health_inspector 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in health_inspector.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2012 Ben Marini
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # Health Inspector
2
+
3
+ A tool to inspect your chef repo as is compares to what is on your chef server
4
+
5
+ ## Usage
6
+
7
+ $ gem install health_inspector
8
+ $ cd [chef repo] && health_inspector inspect
9
+
10
+ Run `health_inspector help` for more options
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require "health_inspector"
3
+ HealthInspector::CLI.start
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "health_inspector/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "health_inspector"
7
+ s.version = HealthInspector::VERSION
8
+ s.authors = ["Ben Marini"]
9
+ s.email = ["bmarini@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A tool to inspect your chef repo as is compares to what is on your chef server}
12
+ s.description = %q{A tool to inspect your chef repo as is compares to what is on your chef server}
13
+
14
+ s.rubyforge_project = "health_inspector"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ s.add_runtime_dependency "thor"
25
+ end
@@ -0,0 +1,16 @@
1
+ module HealthInspector
2
+ module Check
3
+ def run_check
4
+ check
5
+ return failure
6
+ end
7
+
8
+ def failure(message=nil)
9
+ if message
10
+ @failure = message
11
+ else
12
+ @failure
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+
3
+ module HealthInspector
4
+ module Checklists
5
+ class Base
6
+ include Color
7
+
8
+ def banner(message)
9
+ puts
10
+ puts message
11
+ puts "-" * 80
12
+ end
13
+
14
+ def print_success(subject)
15
+ puts color('bright pass', "✓") + " #{subject}"
16
+ end
17
+
18
+ def print_failures(subject, failures)
19
+ puts color('bright fail', "- #{subject}")
20
+
21
+ failures.each do |message|
22
+ puts color('bright yellow', " #{message}")
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,130 @@
1
+ module HealthInspector
2
+ module Checklists
3
+
4
+ class Cookbook < Struct.new(:name, :path, :server_version, :local_version)
5
+ def git_repo?
6
+ self.path && File.exist?("#{self.path}/.git")
7
+ end
8
+ end
9
+
10
+ class CookbookCheck < Struct.new(:cookbook)
11
+ include Check
12
+ end
13
+
14
+ class CheckLocalCopyExists < CookbookCheck
15
+ def check
16
+ failure( "exists on chef server but not locally" ) if cookbook.path.nil?
17
+ end
18
+ end
19
+
20
+ class CheckServerCopyExists < CookbookCheck
21
+ def check
22
+ failure( "exists locally but not on chef server" ) if cookbook.server_version.nil?
23
+ end
24
+ end
25
+
26
+ class CheckVersionsAreTheSame < CookbookCheck
27
+ def check
28
+ if cookbook.local_version && cookbook.server_version &&
29
+ cookbook.local_version != cookbook.server_version
30
+ failure "chef server has #{cookbook.server_version} but local version is #{cookbook.local_version}"
31
+ end
32
+ end
33
+ end
34
+
35
+ class CheckUncommittedChanges < CookbookCheck
36
+ def check
37
+ if cookbook.git_repo?
38
+ result = `cd #{cookbook.path} && git status -s`
39
+
40
+ unless result.empty?
41
+ failure "Uncommitted changes:\n#{result.chomp}"
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ class CheckCommitsNotPushedToRemote < CookbookCheck
48
+ def check
49
+ if cookbook.git_repo?
50
+ result = `cd #{cookbook.path} && git status`
51
+
52
+ if result =~ /Your branch is ahead of (.+)/
53
+ failure "ahead of #{$1}"
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ class Cookbooks < Base
60
+ def self.run(context)
61
+ new(context).run
62
+ end
63
+
64
+ def initialize(context)
65
+ @context = context
66
+ end
67
+
68
+ def run
69
+ banner "Inspecting cookbooks"
70
+
71
+ cookbooks.each do |cookbook|
72
+ failures = cookbook_checks.map { |c| c.new(cookbook).run_check }.compact
73
+ if failures.empty?
74
+ print_success(cookbook.name)
75
+ else
76
+ print_failures(cookbook.name, failures)
77
+ end
78
+ end
79
+ end
80
+
81
+ def cookbooks
82
+ server_cookbooks = cookbooks_on_server
83
+ local_cookbooks = cookbooks_in_repo
84
+ all_cookbook_names = ( server_cookbooks.keys + local_cookbooks.keys ).uniq.sort
85
+
86
+ all_cookbook_names.map do |name|
87
+ Cookbook.new.tap do |cookbook|
88
+ cookbook.name = name
89
+ cookbook.path = cookbook_path(name)
90
+ cookbook.server_version = server_cookbooks[name]
91
+ cookbook.local_version = local_cookbooks[name]
92
+ end
93
+ end
94
+ end
95
+
96
+ def cookbooks_on_server
97
+ JSON.parse( @context.knife_command("cookbook list -Fj") ).inject({}) do |hsh, c|
98
+ name, version = c.split
99
+ hsh[name] = version
100
+ hsh
101
+ end
102
+ end
103
+
104
+ def cookbooks_in_repo
105
+ @context.cookbook_path.map { |path| Dir["#{path}/*"] }.flatten.inject({}) do |hsh, path|
106
+ name = File.basename(path)
107
+ version = (`grep '^version' #{path}/metadata.rb`).split.last[1...-1]
108
+
109
+ hsh[name] = version
110
+ hsh
111
+ end
112
+ end
113
+
114
+ def cookbook_path(name)
115
+ path = @context.cookbook_path.find { |f| File.exist?("#{f}/#{name}") }
116
+ path ? File.join(path, name) : nil
117
+ end
118
+
119
+ def cookbook_checks
120
+ [
121
+ CheckLocalCopyExists,
122
+ CheckServerCopyExists,
123
+ CheckVersionsAreTheSame,
124
+ CheckUncommittedChanges,
125
+ CheckCommitsNotPushedToRemote
126
+ ]
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,18 @@
1
+ require "thor"
2
+
3
+ module HealthInspector
4
+ class CLI < Thor
5
+ class_option 'repopath', :type => :string, :aliases => "-r",
6
+ :default => ".",
7
+ :banner => "Path to your local chef-repo"
8
+
9
+ class_option 'configpath', :type => :string, :aliases => "-c",
10
+ :default => ".chef/knife.rb",
11
+ :banner => "Path to your knife config file."
12
+
13
+ desc "inspect", "Inspect a chef server repo"
14
+ def inspect
15
+ Inspector.inspect(options[:repopath], options[:configpath])
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module HealthInspector
2
+ module Color
3
+ def color(type, str)
4
+ colors = {
5
+ 'pass' => 90,
6
+ 'fail' => 31,
7
+ 'bright pass' => 92,
8
+ 'bright fail' => 91,
9
+ 'bright yellow' => 93,
10
+ 'pending' => 36,
11
+ 'suite' => 0,
12
+ 'error title' => 0,
13
+ 'error message' => 31,
14
+ 'error stack' => 90,
15
+ 'checkmark' => 32,
16
+ 'fast' => 90,
17
+ 'medium' => 33,
18
+ 'slow' => 31,
19
+ 'green' => 32,
20
+ 'light' => 90,
21
+ 'diff gutter' => 90,
22
+ 'diff added' => 42,
23
+ 'diff removed' => 41
24
+ }
25
+
26
+ "\e[%sm%s\e[0m" % [ colors[type], str ]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ module HealthInspector
2
+ class Context < Struct.new(:repo_path, :config_path)
3
+ def knife_command(subcommnad)
4
+ `cd #{repo_path} && knife #{subcommnad} -c #{config_path}`
5
+ end
6
+
7
+ # TODO: read from knife config
8
+ def cookbook_path
9
+ [ File.join(repo_path, "cookbooks") ]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module HealthInspector
2
+ class Inspector
3
+ def self.inspect(repo_path, config_path)
4
+ new(repo_path, config_path).inspect
5
+ end
6
+
7
+ def initialize(repo_path, config_path)
8
+ @context = Context.new( repo_path, File.join(repo_path, config_path) )
9
+ end
10
+
11
+ def inspect
12
+ Checklists::Cookbooks.run(@context)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module HealthInspector
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ require "health_inspector/version"
3
+ require "health_inspector/color"
4
+ require "health_inspector/context"
5
+ require "health_inspector/check"
6
+ require "health_inspector/inspector"
7
+ require "health_inspector/checklists/base"
8
+ require "health_inspector/checklists/cookbooks"
9
+ require "health_inspector/cli"
10
+ require "json"
11
+
12
+ # TODO:
13
+ # * Check if cookbook version is same as on server
14
+ # * Check if remote origin not in sync with local
15
+ module HealthInspector
16
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: health_inspector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Marini
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-27 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &2162524420 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2162524420
25
+ description: A tool to inspect your chef repo as is compares to what is on your chef
26
+ server
27
+ email:
28
+ - bmarini@gmail.com
29
+ executables:
30
+ - health_inspector
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - MIT-LICENSE
37
+ - README.md
38
+ - Rakefile
39
+ - bin/health_inspector
40
+ - health_inspector.gemspec
41
+ - lib/health_inspector.rb
42
+ - lib/health_inspector/check.rb
43
+ - lib/health_inspector/checklists/base.rb
44
+ - lib/health_inspector/checklists/cookbooks.rb
45
+ - lib/health_inspector/cli.rb
46
+ - lib/health_inspector/color.rb
47
+ - lib/health_inspector/context.rb
48
+ - lib/health_inspector/inspector.rb
49
+ - lib/health_inspector/version.rb
50
+ homepage: ''
51
+ licenses: []
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project: health_inspector
70
+ rubygems_version: 1.8.10
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A tool to inspect your chef repo as is compares to what is on your chef server
74
+ test_files: []
75
+ has_rdoc: