health_inspector 0.0.3 → 0.0.4
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/HISTORY.md +7 -3
- data/lib/health_inspector.rb +4 -3
- data/lib/health_inspector/checklists/base.rb +60 -0
- data/lib/health_inspector/checklists/cookbooks.rb +21 -63
- data/lib/health_inspector/checklists/data_bag_items.rb +71 -0
- data/lib/health_inspector/checklists/data_bags.rb +44 -0
- data/lib/health_inspector/checklists/environments.rb +65 -0
- data/lib/health_inspector/checklists/roles.rb +65 -0
- data/lib/health_inspector/context.rb +6 -4
- data/lib/health_inspector/inspector.rb +5 -0
- data/lib/health_inspector/version.rb +1 -1
- metadata +10 -6
data/HISTORY.md
CHANGED
@@ -1,11 +1,15 @@
|
|
1
|
-
## 0.0.
|
1
|
+
## 0.0.4 ( 2012-04-09 )
|
2
|
+
|
3
|
+
* Add checks for data bags, data bag items, environments, and roles
|
4
|
+
|
5
|
+
## 0.0.3 ( 2012-03-27 )
|
2
6
|
|
3
7
|
* Read cookbook paths from knife config file instead of hardcoding /cookbooks
|
4
8
|
|
5
|
-
## 0.0.2 ( 2012-03-27)
|
9
|
+
## 0.0.2 ( 2012-03-27 )
|
6
10
|
|
7
11
|
* Make sure we iterate over actual cookbooks in cookbooks folder
|
8
12
|
|
9
|
-
## 0.0.1 ( 2012-03-27)
|
13
|
+
## 0.0.1 ( 2012-03-27 )
|
10
14
|
|
11
15
|
* Initial release
|
data/lib/health_inspector.rb
CHANGED
@@ -6,11 +6,12 @@ require "health_inspector/check"
|
|
6
6
|
require "health_inspector/inspector"
|
7
7
|
require "health_inspector/checklists/base"
|
8
8
|
require "health_inspector/checklists/cookbooks"
|
9
|
+
require "health_inspector/checklists/data_bags"
|
10
|
+
require "health_inspector/checklists/data_bag_items"
|
11
|
+
require "health_inspector/checklists/environments"
|
12
|
+
require "health_inspector/checklists/roles"
|
9
13
|
require "health_inspector/cli"
|
10
14
|
require "json"
|
11
15
|
|
12
|
-
# TODO:
|
13
|
-
# * Check if cookbook version is same as on server
|
14
|
-
# * Check if remote origin not in sync with local
|
15
16
|
module HealthInspector
|
16
17
|
end
|
@@ -5,6 +5,66 @@ module HealthInspector
|
|
5
5
|
class Base
|
6
6
|
include Color
|
7
7
|
|
8
|
+
class << self
|
9
|
+
attr_reader :checks, :title
|
10
|
+
|
11
|
+
def add_check(name, &block)
|
12
|
+
@checks ||= []
|
13
|
+
@checks << block
|
14
|
+
end
|
15
|
+
|
16
|
+
def title(val=nil)
|
17
|
+
val.nil? ? @title : @title = val
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.run(context)
|
22
|
+
new(context).run
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(context)
|
26
|
+
@context = context
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
banner "Inspecting #{self.class.title}"
|
31
|
+
|
32
|
+
items.each do |item|
|
33
|
+
failures = checks.map { |check| run_check(check, item) }.compact
|
34
|
+
|
35
|
+
if failures.empty?
|
36
|
+
print_success(item.name)
|
37
|
+
else
|
38
|
+
print_failures(item.name, failures)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def checks
|
44
|
+
self.class.checks
|
45
|
+
end
|
46
|
+
|
47
|
+
class CheckContext
|
48
|
+
include Check
|
49
|
+
attr_accessor :item, :context
|
50
|
+
|
51
|
+
def initialize(check, item, context)
|
52
|
+
@item = item
|
53
|
+
@context = context
|
54
|
+
@check = check
|
55
|
+
end
|
56
|
+
|
57
|
+
def call
|
58
|
+
instance_eval(&@check)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def run_check(check, item)
|
63
|
+
check_context = CheckContext.new(check, item, @context)
|
64
|
+
check_context.call
|
65
|
+
return check_context.failure
|
66
|
+
end
|
67
|
+
|
8
68
|
def banner(message)
|
9
69
|
puts
|
10
70
|
puts message
|
@@ -1,84 +1,52 @@
|
|
1
1
|
module HealthInspector
|
2
2
|
module Checklists
|
3
3
|
|
4
|
-
class
|
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
|
4
|
+
class Cookbooks < Base
|
13
5
|
|
14
|
-
|
15
|
-
|
16
|
-
failure( "exists on chef server but not locally" ) if cookbook.path.nil?
|
6
|
+
add_check "local copy exists" do
|
7
|
+
failure( "exists on chef server but not locally" ) if item.path.nil?
|
17
8
|
end
|
18
|
-
end
|
19
9
|
|
20
|
-
|
21
|
-
|
22
|
-
failure( "exists locally but not on chef server" ) if cookbook.server_version.nil?
|
10
|
+
add_check "server copy exists" do
|
11
|
+
failure( "exists locally but not on chef server" ) if item.server_version.nil?
|
23
12
|
end
|
24
|
-
end
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
failure "chef server has #{cookbook.server_version} but local version is #{cookbook.local_version}"
|
14
|
+
add_check "versions" do
|
15
|
+
if item.local_version && item.server_version &&
|
16
|
+
item.local_version != item.server_version
|
17
|
+
failure "chef server has #{item.server_version} but local version is #{item.local_version}"
|
31
18
|
end
|
32
19
|
end
|
33
|
-
end
|
34
20
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
result = `cd #{cookbook.path} && git status -s`
|
21
|
+
add_check "uncommitted changes" do
|
22
|
+
if item.git_repo?
|
23
|
+
result = `cd #{item.path} && git status -s`
|
39
24
|
|
40
25
|
unless result.empty?
|
41
26
|
failure "Uncommitted changes:\n#{result.chomp}"
|
42
27
|
end
|
43
28
|
end
|
44
29
|
end
|
45
|
-
end
|
46
30
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
result = `cd #{cookbook.path} && git status`
|
31
|
+
add_check "commits not pushed to remote" do
|
32
|
+
if item.git_repo?
|
33
|
+
result = `cd #{item.path} && git status`
|
51
34
|
|
52
35
|
if result =~ /Your branch is ahead of (.+)/
|
53
36
|
failure "ahead of #{$1}"
|
54
37
|
end
|
55
38
|
end
|
56
39
|
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
40
|
|
68
|
-
|
69
|
-
|
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
|
41
|
+
class Cookbook < Struct.new(:name, :path, :server_version, :local_version)
|
42
|
+
def git_repo?
|
43
|
+
self.path && File.exist?("#{self.path}/.git")
|
78
44
|
end
|
79
45
|
end
|
80
46
|
|
81
|
-
|
47
|
+
title "cookbooks"
|
48
|
+
|
49
|
+
def items
|
82
50
|
server_cookbooks = cookbooks_on_server
|
83
51
|
local_cookbooks = cookbooks_in_repo
|
84
52
|
all_cookbook_names = ( server_cookbooks.keys + local_cookbooks.keys ).uniq.sort
|
@@ -120,16 +88,6 @@ module HealthInspector
|
|
120
88
|
path = @context.cookbook_path.find { |f| File.exist?("#{f}/#{name}") }
|
121
89
|
path ? File.join(path, name) : nil
|
122
90
|
end
|
123
|
-
|
124
|
-
def cookbook_checks
|
125
|
-
[
|
126
|
-
CheckLocalCopyExists,
|
127
|
-
CheckServerCopyExists,
|
128
|
-
CheckVersionsAreTheSame,
|
129
|
-
CheckUncommittedChanges,
|
130
|
-
CheckCommitsNotPushedToRemote
|
131
|
-
]
|
132
|
-
end
|
133
91
|
end
|
134
92
|
end
|
135
93
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "chef/data_bag"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class DataBagItems < Base
|
6
|
+
title "data bag items"
|
7
|
+
|
8
|
+
add_check "local copy exists" do
|
9
|
+
failure "exists on server but not locally" unless item.local
|
10
|
+
end
|
11
|
+
|
12
|
+
add_check "server copy exists" do
|
13
|
+
failure "exists locally but not on server" unless item.server
|
14
|
+
end
|
15
|
+
|
16
|
+
add_check "items are the same" do
|
17
|
+
if item.server && item.local
|
18
|
+
failure "#{item.server}\n is not equal to\n #{item.local}" unless item.server == item.local
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
DataBagItem = Struct.new(:name, :server, :local)
|
23
|
+
|
24
|
+
def items
|
25
|
+
server_data_bag_items = data_bag_items_on_server
|
26
|
+
local_data_bag_items = data_bag_items_in_repo
|
27
|
+
all_data_bag_item_names = ( server_data_bag_items + local_data_bag_items ).uniq.sort
|
28
|
+
|
29
|
+
all_data_bag_item_names.map do |name|
|
30
|
+
DataBagItem.new.tap do |data_bag_item|
|
31
|
+
data_bag_item.name = name
|
32
|
+
data_bag_item.server = load_item_from_server(name)
|
33
|
+
data_bag_item.local = load_item_from_local(name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def data_bag_items_on_server
|
39
|
+
@data_bags_on_server ||= Chef::DataBag.list.keys.map do |bag_name|
|
40
|
+
[ bag_name, Chef::DataBag.load(bag_name) ]
|
41
|
+
end.inject([]) do |arr, (bag_name, data_bag)|
|
42
|
+
arr += data_bag.keys.map { |item_name| "#{bag_name}/#{item_name}"}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def data_bag_items_in_repo
|
47
|
+
entries = nil
|
48
|
+
|
49
|
+
Dir.chdir("#{@context.repo_path}/data_bags") do
|
50
|
+
entries = Dir["**/*.json"].map { |entry| entry.gsub('.json', '') }
|
51
|
+
end
|
52
|
+
|
53
|
+
return entries
|
54
|
+
end
|
55
|
+
|
56
|
+
def load_item_from_server(name)
|
57
|
+
bag_name, item_name = name.split("/")
|
58
|
+
Chef::DataBagItem.load(bag_name, item_name).raw_data
|
59
|
+
rescue
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def load_item_from_local(name)
|
64
|
+
JSON.parse( File.read("#{@context.repo_path}/data_bags/#{name}.json") )
|
65
|
+
rescue IOError
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "chef/data_bag"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class DataBags < Base
|
6
|
+
title "data bags"
|
7
|
+
|
8
|
+
add_check "local copy exists" do
|
9
|
+
failure "exists on server but not locally" unless item.exists_locally
|
10
|
+
end
|
11
|
+
|
12
|
+
add_check "server copy exists" do
|
13
|
+
failure "exists locally but not on server" unless item.exists_on_server
|
14
|
+
end
|
15
|
+
|
16
|
+
DataBag = Struct.new(:name, :exists_on_server, :exists_locally)
|
17
|
+
|
18
|
+
def items
|
19
|
+
server_data_bags = data_bags_on_server
|
20
|
+
local_data_bags = data_bags_in_repo
|
21
|
+
all_data_bag_names = ( server_data_bags + local_data_bags ).uniq.sort
|
22
|
+
|
23
|
+
all_data_bag_names.map do |name|
|
24
|
+
DataBag.new.tap do |data_bag|
|
25
|
+
data_bag.name = name
|
26
|
+
data_bag.exists_on_server = data_bags_on_server.include?(name)
|
27
|
+
data_bag.exists_locally = data_bags_in_repo.include?(name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def data_bags_on_server
|
33
|
+
@data_bags_on_server ||= Chef::DataBag.list.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
def data_bags_in_repo
|
37
|
+
@data_bags_in_repo ||= Dir["#{@context.repo_path}/data_bags/*"].entries.
|
38
|
+
select { |e| File.directory?(e) }.
|
39
|
+
map { |e| File.basename(e) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "chef/environment"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class Environments < Base
|
6
|
+
title "environments"
|
7
|
+
|
8
|
+
add_check "local copy exists" do
|
9
|
+
failure "exists on server but not locally" unless item.local
|
10
|
+
end
|
11
|
+
|
12
|
+
add_check "server copy exists" do
|
13
|
+
failure "exists locally but not on server" unless item.server
|
14
|
+
end
|
15
|
+
|
16
|
+
add_check "items are the same" do
|
17
|
+
if item.server && item.local
|
18
|
+
failure "#{item.server}\n is not equal to\n #{item.local}" unless item.server == item.local
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Environment = Struct.new(:name, :server, :local)
|
23
|
+
|
24
|
+
def items
|
25
|
+
server_items = items_on_server
|
26
|
+
local_items = items_in_repo
|
27
|
+
all_item_names = ( server_items + local_items ).uniq.sort
|
28
|
+
|
29
|
+
all_item_names.map do |name|
|
30
|
+
Environment.new.tap do |item|
|
31
|
+
item.name = name
|
32
|
+
item.server = load_item_from_server(name)
|
33
|
+
item.local = load_item_from_local(name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def items_on_server
|
39
|
+
@items_on_server ||= Chef::Environment.list.keys
|
40
|
+
end
|
41
|
+
|
42
|
+
def items_in_repo
|
43
|
+
Dir.chdir("#{@context.repo_path}/environments") do
|
44
|
+
Dir["*.rb"].map { |e| e.gsub('.rb', '') }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_item_from_server(name)
|
49
|
+
env = Chef::Environment.load(name)
|
50
|
+
env.to_hash
|
51
|
+
rescue
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_item_from_local(name)
|
56
|
+
env = Chef::Environment.new
|
57
|
+
env.from_file( "#{@context.repo_path}/environments/#{name}.rb" )
|
58
|
+
env.to_hash
|
59
|
+
rescue IOError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "chef/role"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class Roles < Base
|
6
|
+
title "roles"
|
7
|
+
|
8
|
+
add_check "local copy exists" do
|
9
|
+
failure "exists on server but not locally" unless item.local
|
10
|
+
end
|
11
|
+
|
12
|
+
add_check "server copy exists" do
|
13
|
+
failure "exists locally but not on server" unless item.server
|
14
|
+
end
|
15
|
+
|
16
|
+
add_check "items are the same" do
|
17
|
+
if item.server && item.local
|
18
|
+
failure "#{item.server}\n is not equal to\n #{item.local}" unless item.server == item.local
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Role = Struct.new(:name, :server, :local)
|
23
|
+
|
24
|
+
def items
|
25
|
+
server_items = items_on_server
|
26
|
+
local_items = items_in_repo
|
27
|
+
all_item_names = ( server_items + local_items ).uniq.sort
|
28
|
+
|
29
|
+
all_item_names.map do |name|
|
30
|
+
Role.new.tap do |item|
|
31
|
+
item.name = name
|
32
|
+
item.server = load_item_from_server(name)
|
33
|
+
item.local = load_item_from_local(name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def items_on_server
|
39
|
+
@items_on_server ||= Chef::Role.list.keys
|
40
|
+
end
|
41
|
+
|
42
|
+
def items_in_repo
|
43
|
+
Dir.chdir("#{@context.repo_path}/roles") do
|
44
|
+
Dir["*.rb"].map { |e| e.gsub('.rb', '') }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_item_from_server(name)
|
49
|
+
role = Chef::Role.load(name)
|
50
|
+
role.to_hash
|
51
|
+
rescue
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_item_from_local(name)
|
56
|
+
role = Chef::Role.new
|
57
|
+
role.from_file( "#{@context.repo_path}/roles/#{name}.rb" )
|
58
|
+
role.to_hash
|
59
|
+
rescue IOError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -11,10 +11,12 @@ module HealthInspector
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def config
|
14
|
-
@config ||=
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
@config ||= configure
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure
|
18
|
+
Chef::Config.from_file(config_path)
|
19
|
+
Chef::Config
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -6,10 +6,15 @@ module HealthInspector
|
|
6
6
|
|
7
7
|
def initialize(repo_path, config_path)
|
8
8
|
@context = Context.new( repo_path, File.join(repo_path, config_path) )
|
9
|
+
@context.configure
|
9
10
|
end
|
10
11
|
|
11
12
|
def inspect
|
12
13
|
Checklists::Cookbooks.run(@context)
|
14
|
+
Checklists::DataBags.run(@context)
|
15
|
+
Checklists::DataBagItems.run(@context)
|
16
|
+
Checklists::Environments.run(@context)
|
17
|
+
Checklists::Roles.run(@context)
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: health_inspector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
16
|
-
requirement: &
|
16
|
+
requirement: &2168869000 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2168869000
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: chef
|
27
|
-
requirement: &
|
27
|
+
requirement: &2168868580 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2168868580
|
36
36
|
description: A tool to inspect your chef repo as is compares to what is on your chef
|
37
37
|
server
|
38
38
|
email:
|
@@ -54,6 +54,10 @@ files:
|
|
54
54
|
- lib/health_inspector/check.rb
|
55
55
|
- lib/health_inspector/checklists/base.rb
|
56
56
|
- lib/health_inspector/checklists/cookbooks.rb
|
57
|
+
- lib/health_inspector/checklists/data_bag_items.rb
|
58
|
+
- lib/health_inspector/checklists/data_bags.rb
|
59
|
+
- lib/health_inspector/checklists/environments.rb
|
60
|
+
- lib/health_inspector/checklists/roles.rb
|
57
61
|
- lib/health_inspector/cli.rb
|
58
62
|
- lib/health_inspector/color.rb
|
59
63
|
- lib/health_inspector/context.rb
|