knife-inspect 0.6.0
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 +5 -0
- data/Gemfile +4 -0
- data/HISTORY.md +88 -0
- data/MIT-LICENSE +19 -0
- data/README.md +43 -0
- data/Rakefile +9 -0
- data/knife-inspect.gemspec +27 -0
- data/lib/chef/knife/cookbook_inspect.rb +36 -0
- data/lib/chef/knife/data_bag_inspect.rb +35 -0
- data/lib/chef/knife/environment_inspect.rb +25 -0
- data/lib/chef/knife/inspect.rb +20 -0
- data/lib/chef/knife/role_inspect.rb +25 -0
- data/lib/health_inspector.rb +18 -0
- data/lib/health_inspector/checklists/base.rb +136 -0
- data/lib/health_inspector/checklists/cookbooks.rb +134 -0
- data/lib/health_inspector/checklists/data_bag_items.rb +60 -0
- data/lib/health_inspector/checklists/data_bags.rb +38 -0
- data/lib/health_inspector/checklists/environments.rb +55 -0
- data/lib/health_inspector/checklists/roles.rb +51 -0
- data/lib/health_inspector/color.rb +31 -0
- data/lib/health_inspector/context.rb +27 -0
- data/lib/health_inspector/inspector.rb +20 -0
- data/lib/health_inspector/pairing.rb +73 -0
- data/lib/health_inspector/version.rb +3 -0
- data/spec/chef-repo/.chef/client.pem +0 -0
- data/spec/chef-repo/.chef/knife.rb +7 -0
- data/spec/cookbook_spec.rb +41 -0
- data/spec/data_bag_item_spec.rb +6 -0
- data/spec/data_bag_spec.rb +5 -0
- data/spec/environment_spec.rb +18 -0
- data/spec/role_spec.rb +6 -0
- data/spec/spec_helper.rb +56 -0
- metadata +140 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/HISTORY.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
## 0.6.0 ( 2012-11-1 )
|
2
|
+
|
3
|
+
* Add knife plugins for all existing functionality:
|
4
|
+
- knife inspect
|
5
|
+
- knife cookbook inspect [COOKBOOK]
|
6
|
+
- knife data bag inspect [BAG] [ITEM]
|
7
|
+
- knife environment inspect [ENVIRONMENT]
|
8
|
+
- knife role inspect [ROLE]
|
9
|
+
|
10
|
+
* Lost support for quiet-sucess option (We can add that back, or make a quiet
|
11
|
+
options that just returns exit status).
|
12
|
+
|
13
|
+
## 0.5.2 ( 2012-10-19 )
|
14
|
+
|
15
|
+
* Make loading of Chef Config a little more robust.
|
16
|
+
|
17
|
+
## 0.5.1 ( 2012-10-15 )
|
18
|
+
|
19
|
+
* Ignore _default environment if it only exists on the server.
|
20
|
+
|
21
|
+
## 0.5.0 ( 2012-10-14 )
|
22
|
+
|
23
|
+
* Switch to RSpec
|
24
|
+
* Add some test coverage (still needs much more).
|
25
|
+
* Add option to suppress terminal output on successful checks.
|
26
|
+
* Add option to not use ansi color output.
|
27
|
+
* Make cookbook version comparison use Chef's native version class.
|
28
|
+
|
29
|
+
## 0.4.1 ( 2012-09-28 )
|
30
|
+
|
31
|
+
* Fix a bug I created in last release when passing no component.
|
32
|
+
|
33
|
+
## 0.4.0 ( 2012-09-28 )
|
34
|
+
|
35
|
+
* Make `inspect` the default task
|
36
|
+
* Add ability to specify individual components:
|
37
|
+
|
38
|
+
health_inspector inspect cookbooks
|
39
|
+
|
40
|
+
## 0.3.1 ( 2012-09-27 )
|
41
|
+
|
42
|
+
* Stop shelling out for knife commands, use Chef API directly for everything.
|
43
|
+
|
44
|
+
## 0.3.0 ( 2012-09-26 )
|
45
|
+
|
46
|
+
* Add new check for cookbooks: checksum comparison for each file.
|
47
|
+
|
48
|
+
## 0.2.1 ( 2012-09-26 )
|
49
|
+
|
50
|
+
* Fix 1.8.7 incompatibility introduced in last release (String#prepend).
|
51
|
+
|
52
|
+
## 0.2.0 ( 2012-09-25 )
|
53
|
+
|
54
|
+
* Add a better diff output.
|
55
|
+
* Add diff output to data bag items.
|
56
|
+
* Switch to yajl-ruby to fix JSON parsing issues (Chef uses this also).
|
57
|
+
|
58
|
+
## 0.1.0 ( 2012-09-24 )
|
59
|
+
|
60
|
+
* Bump Chef dependency version up to 10.14
|
61
|
+
* Add support for JSON environments.
|
62
|
+
* Add support for JSON roles.
|
63
|
+
* Display the diff between JSONs when JSON data doesn't match.
|
64
|
+
|
65
|
+
## 0.0.6 ( 2012-05-23 )
|
66
|
+
|
67
|
+
* Depend on Chef 0.10.8, since it depends on a later version of the json gem.
|
68
|
+
An earlier version of the json gem was throwing incorrect parse errors.
|
69
|
+
|
70
|
+
## 0.0.5 ( 2012-04-13 )
|
71
|
+
|
72
|
+
* Fix #2, exception when a data bag item json file doesn't exist locally.
|
73
|
+
|
74
|
+
## 0.0.4 ( 2012-04-09 )
|
75
|
+
|
76
|
+
* Add checks for data bags, data bag items, environments, and roles.
|
77
|
+
|
78
|
+
## 0.0.3 ( 2012-03-27 )
|
79
|
+
|
80
|
+
* Read cookbook paths from knife config file instead of hardcoding /cookbooks.
|
81
|
+
|
82
|
+
## 0.0.2 ( 2012-03-27 )
|
83
|
+
|
84
|
+
* Make sure we iterate over actual cookbooks in cookbooks folder.
|
85
|
+
|
86
|
+
## 0.0.1 ( 2012-03-27 )
|
87
|
+
|
88
|
+
* Initial release.
|
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,43 @@
|
|
1
|
+
[](http://travis-ci.org/bmarini/health_inspector)
|
2
|
+
|
3
|
+
## Summary
|
4
|
+
|
5
|
+
`health_inspector` is a knife plugin that inspects your chef repo as it
|
6
|
+
compares to what is on your chef server. You can inspect your entire repo,
|
7
|
+
or individual components.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
$ gem install health_inspector
|
12
|
+
$ cd [chef repo]
|
13
|
+
|
14
|
+
## Knife Commands
|
15
|
+
|
16
|
+
knife inspect
|
17
|
+
|
18
|
+
knife cookbook inspect
|
19
|
+
knife cookbook inspect [COOKBOOK]
|
20
|
+
|
21
|
+
knife data bag inspect
|
22
|
+
knife data bag inspect [BAG]
|
23
|
+
knife data bag inspect [BAG] [ITEM]
|
24
|
+
|
25
|
+
knife environment inspect
|
26
|
+
knife environment inspect [ENVIRONMENT]
|
27
|
+
|
28
|
+
knife role inspect
|
29
|
+
knife role inspect [ROLE]
|
30
|
+
|
31
|
+
## What it does
|
32
|
+
|
33
|
+
So far it checks if...
|
34
|
+
|
35
|
+
* your cookbooks are in sync
|
36
|
+
* you have uncommitted changes in a cookbook (assuming your cookbooks are in
|
37
|
+
their own git repos)
|
38
|
+
* you have commits in a cookbook that haven't been pushed to your remote
|
39
|
+
(assuming your cookbooks are in their own git repos)
|
40
|
+
* your data bags are in sync
|
41
|
+
* your data bag items are in sync
|
42
|
+
* your environments are in sync
|
43
|
+
* your roles are in sync
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
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 = "knife-inspect"
|
7
|
+
s.version = HealthInspector::VERSION
|
8
|
+
s.authors = ["Ben Marini"]
|
9
|
+
s.email = ["bmarini@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/bmarini/knife-inspect"
|
11
|
+
s.summary = %q{Inspect your chef repo as is compares to what is on your chef server}
|
12
|
+
s.description = %q{Inspect your chef repo as is compares to what is on your chef server}
|
13
|
+
|
14
|
+
s.rubyforge_project = "knife-inspect"
|
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
|
+
s.add_development_dependency "rake"
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
|
24
|
+
s.add_runtime_dependency "thor"
|
25
|
+
s.add_runtime_dependency "chef", "~> 10.14"
|
26
|
+
s.add_runtime_dependency "yajl-ruby"
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class CookbookInspect < Knife
|
6
|
+
|
7
|
+
deps do
|
8
|
+
require 'health_inspector'
|
9
|
+
require 'chef/json_compat'
|
10
|
+
require 'uri'
|
11
|
+
require 'chef/cookbook_version'
|
12
|
+
end
|
13
|
+
|
14
|
+
banner "knife cookbook inspect [COOKBOOK] (options)"
|
15
|
+
|
16
|
+
def run
|
17
|
+
case @name_args.length
|
18
|
+
when 1 # We are inspecting a cookbook
|
19
|
+
cookbook_name = @name_args[0]
|
20
|
+
# TODO: Support environments
|
21
|
+
# env = config[:environment]
|
22
|
+
# api_endpoint = env ? "environments/#{env}/cookbooks/#{cookbook_name}" : "cookbooks/#{cookbook_name}"
|
23
|
+
|
24
|
+
validator = HealthInspector::Checklists::Cookbooks.new(self)
|
25
|
+
validator.validate_item( validator.load_item(cookbook_name) )
|
26
|
+
when 0 # We are inspecting all the cookbooks
|
27
|
+
HealthInspector::Checklists::Cookbooks.run(self)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class DataBagInspect < Knife
|
6
|
+
|
7
|
+
deps do
|
8
|
+
require 'health_inspector'
|
9
|
+
end
|
10
|
+
|
11
|
+
banner "knife data bag inspect [BAG] [ITEM] (options)"
|
12
|
+
|
13
|
+
def run
|
14
|
+
case @name_args.length
|
15
|
+
when 2 # We are inspecting a data bag item
|
16
|
+
bag_name = @name_args[0]
|
17
|
+
item_name = @name_args[1]
|
18
|
+
|
19
|
+
validator = HealthInspector::Checklists::DataBagItems.new(self)
|
20
|
+
validator.validate_item( validator.load_item("#{bag_name}/#{item_name}") )
|
21
|
+
|
22
|
+
when 1 # We are inspecting a data bag
|
23
|
+
bag_name = @name_args[0]
|
24
|
+
|
25
|
+
validator = HealthInspector::Checklists::DataBags.new(self)
|
26
|
+
validator.validate_item( validator.load_item(bag_name) )
|
27
|
+
|
28
|
+
when 0 # We are inspecting all the data bags
|
29
|
+
HealthInspector::Checklists::DataBags.run(self)
|
30
|
+
HealthInspector::Checklists::DataBagItems.run(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class EnvironmentInspect < Knife
|
6
|
+
|
7
|
+
deps do
|
8
|
+
require 'health_inspector'
|
9
|
+
end
|
10
|
+
|
11
|
+
banner "knife environment inspect [ENVIRONMENT] (options)"
|
12
|
+
|
13
|
+
def run
|
14
|
+
case @name_args.length
|
15
|
+
when 1 # We are inspecting a environment
|
16
|
+
environment_name = @name_args[0]
|
17
|
+
validator = HealthInspector::Checklists::Environments.new(self)
|
18
|
+
validator.validate_item( validator.load_item(environment_name) )
|
19
|
+
when 0 # We are inspecting all the environments
|
20
|
+
HealthInspector::Checklists::Environments.run(self)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class Inspect < Knife
|
6
|
+
|
7
|
+
deps do
|
8
|
+
require "health_inspector"
|
9
|
+
end
|
10
|
+
|
11
|
+
banner "knife inspect"
|
12
|
+
|
13
|
+
def run
|
14
|
+
%w[ Cookbooks DataBags DataBagItems Environments Roles ].each do |checklist|
|
15
|
+
HealthInspector::Checklists.const_get(checklist).run(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class RoleInspect < Knife
|
6
|
+
|
7
|
+
deps do
|
8
|
+
require 'health_inspector'
|
9
|
+
end
|
10
|
+
|
11
|
+
banner "knife role inspect [ROLE] (options)"
|
12
|
+
|
13
|
+
def run
|
14
|
+
case @name_args.length
|
15
|
+
when 1 # We are inspecting a role
|
16
|
+
role_name = @name_args[0]
|
17
|
+
validator = HealthInspector::Checklists::Roles.new(self)
|
18
|
+
validator.validate_item( validator.load_item(role_name) )
|
19
|
+
when 0 # We are inspecting all the roles
|
20
|
+
HealthInspector::Checklists::Roles.run(self)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "health_inspector/version"
|
3
|
+
require "health_inspector/color"
|
4
|
+
require "health_inspector/context"
|
5
|
+
require "health_inspector/pairing"
|
6
|
+
require "health_inspector/inspector"
|
7
|
+
require "health_inspector/checklists/base"
|
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"
|
13
|
+
require 'chef/rest'
|
14
|
+
require 'chef/checksum_cache'
|
15
|
+
require 'chef/version'
|
16
|
+
|
17
|
+
module HealthInspector
|
18
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
module HealthInspector
|
5
|
+
module Checklists
|
6
|
+
class Base
|
7
|
+
include Color
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_reader :title
|
11
|
+
|
12
|
+
def title(val=nil)
|
13
|
+
val.nil? ? @title : @title = val
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.run(knife)
|
18
|
+
new(knife).run
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(knife)
|
22
|
+
@context = Context.new(knife)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ui
|
26
|
+
@context.knife.ui
|
27
|
+
end
|
28
|
+
|
29
|
+
def all_item_names
|
30
|
+
( server_items + local_items ).uniq.sort
|
31
|
+
end
|
32
|
+
|
33
|
+
# Subclasses should collect all items from the server and the local repo,
|
34
|
+
# and for each item pair, yield an object that contains a reference to
|
35
|
+
# the server item, and the local repo item. A reference can be nil if it does
|
36
|
+
# not exist in one of the locations.
|
37
|
+
def each_item
|
38
|
+
raise NotImplementedError, "You must implement this method in a subclass"
|
39
|
+
end
|
40
|
+
|
41
|
+
def run
|
42
|
+
banner "Inspecting #{self.class.title}"
|
43
|
+
|
44
|
+
each_item do |item|
|
45
|
+
validate_item(item)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_item(item)
|
50
|
+
item.validate
|
51
|
+
failures = item.errors
|
52
|
+
|
53
|
+
if failures.empty?
|
54
|
+
print_success(item.name) # unless @context.quiet_success
|
55
|
+
else
|
56
|
+
print_failures(item.name, failures)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def banner(message)
|
61
|
+
ui.msg ""
|
62
|
+
ui.msg message
|
63
|
+
ui.msg "-" * 80
|
64
|
+
end
|
65
|
+
|
66
|
+
def print_success(subject)
|
67
|
+
ui.msg color('bright pass', "✓") + " #{subject}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def print_failures(subject, failures)
|
71
|
+
ui.msg color('bright fail', "- #{subject}")
|
72
|
+
|
73
|
+
failures.each do |message|
|
74
|
+
if message.kind_of? Hash
|
75
|
+
puts color('bright yellow'," has the following values mismatched on the server and repo\n")
|
76
|
+
print_failures_from_hash(message)
|
77
|
+
else
|
78
|
+
puts color('bright yellow', " #{message}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def print_failures_from_hash(message, depth=2)
|
84
|
+
message.keys.each do |key|
|
85
|
+
print_key(key,depth)
|
86
|
+
|
87
|
+
if message[key].include? "server"
|
88
|
+
print_value_diff(message[key],depth)
|
89
|
+
message[key].delete_if { |k,v| k == "server" || "local" }
|
90
|
+
print_failures_from_hash(message[key], depth + 1) unless message[key].empty?
|
91
|
+
else
|
92
|
+
print_failures_from_hash(message[key], depth + 1)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def print_key(key, depth)
|
98
|
+
ui.msg indent( color('bright yellow',"#{key} : "), depth )
|
99
|
+
end
|
100
|
+
|
101
|
+
def print_value_diff(value, depth)
|
102
|
+
print indent( color('bright fail',"server value = "), depth + 1 )
|
103
|
+
print value["server"]
|
104
|
+
print "\n"
|
105
|
+
print indent( color('bright fail',"local value = "), depth + 1 )
|
106
|
+
print value["local"]
|
107
|
+
print "\n\n"
|
108
|
+
end
|
109
|
+
|
110
|
+
def load_ruby_or_json_from_local(chef_class, folder, name)
|
111
|
+
path_template = "#{@context.repo_path}/#{folder}/#{name}.%s"
|
112
|
+
ruby_pathname = Pathname.new(path_template % "rb")
|
113
|
+
json_pathname = Pathname.new(path_template % "json")
|
114
|
+
js_pathname = Pathname.new(path_template % "js")
|
115
|
+
|
116
|
+
if ruby_pathname.exist?
|
117
|
+
instance = chef_class.new
|
118
|
+
instance.from_file(ruby_pathname.to_s)
|
119
|
+
elsif json_pathname.exist?
|
120
|
+
instance = chef_class.json_create( Yajl::Parser.parse( json_pathname.read ) )
|
121
|
+
elsif js_pathname.exist?
|
122
|
+
instance = chef_class.json_create( Yajl::Parser.parse( js_pathname.read ) )
|
123
|
+
end
|
124
|
+
|
125
|
+
instance ? instance.to_hash : nil
|
126
|
+
rescue IOError
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def indent(string, depth)
|
131
|
+
(' ' * 2 * depth) + string
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module HealthInspector
|
2
|
+
module Checklists
|
3
|
+
|
4
|
+
class Cookbook < Pairing
|
5
|
+
include ExistenceValidations
|
6
|
+
|
7
|
+
def validate_versions
|
8
|
+
if versions_exist? && !versions_match?
|
9
|
+
errors.add "chef server has #{server} but local version is #{local}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_uncommited_changes
|
14
|
+
if git_repo?
|
15
|
+
result = `cd #{cookbook_path} && git status -s`
|
16
|
+
|
17
|
+
unless result.empty?
|
18
|
+
errors.add "Uncommitted changes:\n#{result.chomp}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def validate_commits_not_pushed_to_remote
|
24
|
+
if git_repo?
|
25
|
+
result = `cd #{cookbook_path} && git status`
|
26
|
+
|
27
|
+
if result =~ /Your branch is ahead of (.+)/
|
28
|
+
errors.add "ahead of #{$1}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# TODO: Check files that exist locally but not in manifest on server
|
34
|
+
def validate_changes_on_the_server_not_in_the_repo
|
35
|
+
if versions_exist? && versions_match?
|
36
|
+
|
37
|
+
begin
|
38
|
+
cookbook = context.rest.get_rest("/cookbooks/#{name}/#{local}")
|
39
|
+
messages = []
|
40
|
+
|
41
|
+
Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
|
42
|
+
cookbook.manifest[segment].each do |manifest_record|
|
43
|
+
path = cookbook_path.join("#{manifest_record["path"]}")
|
44
|
+
|
45
|
+
if path.exist?
|
46
|
+
checksum = checksum_cookbook_file(path)
|
47
|
+
messages << "#{manifest_record['path']}" if checksum != manifest_record['checksum']
|
48
|
+
else
|
49
|
+
messages << "#{manifest_record['path']} does not exist in the repo"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
unless messages.empty?
|
55
|
+
message = "has a checksum mismatch between server and repo in\n"
|
56
|
+
message << messages.map { |f| " #{f}" }.join("\n")
|
57
|
+
errors.add message
|
58
|
+
end
|
59
|
+
|
60
|
+
rescue Net::HTTPServerException => e
|
61
|
+
errors.add "Could not find cookbook #{name} on the server"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def versions_exist?
|
68
|
+
local && server
|
69
|
+
end
|
70
|
+
|
71
|
+
def versions_match?
|
72
|
+
local == server
|
73
|
+
end
|
74
|
+
|
75
|
+
def git_repo?
|
76
|
+
cookbook_path && File.exist?("#{cookbook_path}/.git")
|
77
|
+
end
|
78
|
+
|
79
|
+
def cookbook_path
|
80
|
+
path = context.cookbook_path.find { |f| File.exist?("#{f}/#{name}") }
|
81
|
+
path ? Pathname.new(path).join(name) : nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def checksum_cookbook_file(filepath)
|
85
|
+
Chef::CookbookVersion.checksum_cookbook_file(filepath)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
class Cookbooks < Base
|
91
|
+
|
92
|
+
title "cookbooks"
|
93
|
+
|
94
|
+
def each_item
|
95
|
+
all_cookbook_names = ( server_cookbooks.keys + local_cookbooks.keys ).uniq.sort
|
96
|
+
|
97
|
+
all_cookbook_names.each do |name|
|
98
|
+
yield load_item(name)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def load_item(name)
|
103
|
+
Cookbook.new(@context,
|
104
|
+
:name => name,
|
105
|
+
:server => server_cookbooks[name],
|
106
|
+
:local => local_cookbooks[name]
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def server_cookbooks
|
111
|
+
@context.rest.get_rest("/cookbooks").inject({}) do |hsh, (name,version)|
|
112
|
+
hsh[name] = Chef::Version.new(version["versions"].first["version"])
|
113
|
+
hsh
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def local_cookbooks
|
118
|
+
@context.cookbook_path.
|
119
|
+
map { |path| Dir["#{path}/*"] }.
|
120
|
+
flatten.
|
121
|
+
select { |path| File.exists?("#{path}/metadata.rb") }.
|
122
|
+
inject({}) do |hsh, path|
|
123
|
+
|
124
|
+
name = File.basename(path)
|
125
|
+
version = (`grep '^version' #{path}/metadata.rb`).split.last[1...-1]
|
126
|
+
|
127
|
+
hsh[name] = Chef::Version.new(version)
|
128
|
+
hsh
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "chef/data_bag"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class DataBagItem < Pairing
|
6
|
+
include ExistenceValidations
|
7
|
+
include JsonValidations
|
8
|
+
end
|
9
|
+
|
10
|
+
class DataBagItems < Base
|
11
|
+
title "data bag items"
|
12
|
+
|
13
|
+
def each_item
|
14
|
+
all_item_names.each do |name|
|
15
|
+
yield load_item(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_item(name)
|
20
|
+
DataBagItem.new(@context,
|
21
|
+
:name => name,
|
22
|
+
:server => load_item_from_server(name),
|
23
|
+
:local => load_item_from_local(name)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def server_items
|
28
|
+
@server_items ||= Chef::DataBag.list.keys.map do |bag_name|
|
29
|
+
[ bag_name, Chef::DataBag.load(bag_name) ]
|
30
|
+
end.inject([]) do |arr, (bag_name, data_bag)|
|
31
|
+
arr += data_bag.keys.map { |item_name| "#{bag_name}/#{item_name}"}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def local_items
|
36
|
+
entries = nil
|
37
|
+
|
38
|
+
Dir.chdir("#{@context.repo_path}/data_bags") do
|
39
|
+
entries = Dir["**/*.json"].map { |entry| entry.gsub('.json', '') }
|
40
|
+
end
|
41
|
+
|
42
|
+
return entries
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_item_from_server(name)
|
46
|
+
bag_name, item_name = name.split("/")
|
47
|
+
Chef::DataBagItem.load(bag_name, item_name).raw_data
|
48
|
+
rescue
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_item_from_local(name)
|
53
|
+
Yajl::Parser.parse( File.read("#{@context.repo_path}/data_bags/#{name}.json") )
|
54
|
+
rescue IOError, Errno::ENOENT
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "chef/data_bag"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class DataBag < Pairing
|
6
|
+
include ExistenceValidations
|
7
|
+
end
|
8
|
+
|
9
|
+
class DataBags < Base
|
10
|
+
title "data bags"
|
11
|
+
|
12
|
+
def each_item
|
13
|
+
all_item_names.each do |name|
|
14
|
+
yield load_item(name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_item(name)
|
19
|
+
DataBag.new(@context,
|
20
|
+
:name => name,
|
21
|
+
:server => server_items.include?(name),
|
22
|
+
:local => local_items.include?(name)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def server_items
|
27
|
+
@server_items ||= Chef::DataBag.list.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def local_items
|
31
|
+
@local_items ||= Dir["#{@context.repo_path}/data_bags/*"].entries.
|
32
|
+
select { |e| File.directory?(e) }.
|
33
|
+
map { |e| File.basename(e) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "chef/environment"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
module Checklists
|
5
|
+
class Environment < Pairing
|
6
|
+
include ExistenceValidations
|
7
|
+
include JsonValidations
|
8
|
+
|
9
|
+
# Override to ignore _default environment if it is missing locally
|
10
|
+
def validate_local_copy_exists
|
11
|
+
super unless name == '_default'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Environments < Base
|
16
|
+
title "environments"
|
17
|
+
|
18
|
+
def each_item
|
19
|
+
all_item_names.each do |name|
|
20
|
+
yield load_item(name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_item(name)
|
25
|
+
Environment.new(@context,
|
26
|
+
:name => name,
|
27
|
+
:server => load_item_from_server(name),
|
28
|
+
:local => load_item_from_local(name)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def server_items
|
33
|
+
@server_items ||= Chef::Environment.list.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
def local_items
|
37
|
+
Dir.chdir("#{@context.repo_path}/environments") do
|
38
|
+
Dir["*.{rb,json,js}"].map { |e| e.gsub(/\.(rb|json|js)/,"") }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_item_from_server(name)
|
43
|
+
env = Chef::Environment.load(name)
|
44
|
+
env.to_hash
|
45
|
+
rescue
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_item_from_local(name)
|
50
|
+
load_ruby_or_json_from_local(Chef::Environment, "environments", name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "chef/role"
|
2
|
+
require 'yajl'
|
3
|
+
|
4
|
+
module HealthInspector
|
5
|
+
module Checklists
|
6
|
+
class Role < Pairing
|
7
|
+
include ExistenceValidations
|
8
|
+
include JsonValidations
|
9
|
+
end
|
10
|
+
|
11
|
+
class Roles < Base
|
12
|
+
title "roles"
|
13
|
+
|
14
|
+
def each_item
|
15
|
+
all_item_names.each do |name|
|
16
|
+
yield load_item(name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_item(name)
|
21
|
+
Role.new(@context,
|
22
|
+
:name => name,
|
23
|
+
:server => load_item_from_server(name),
|
24
|
+
:local => load_item_from_local(name)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def server_items
|
29
|
+
@server_items ||= Chef::Role.list.keys
|
30
|
+
end
|
31
|
+
|
32
|
+
def local_items
|
33
|
+
Dir.chdir("#{@context.repo_path}/roles") do
|
34
|
+
Dir["*.{rb,json,js}"].map { |e| e.gsub(/\.(rb|json|js)/, '') }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_item_from_server(name)
|
39
|
+
role = Chef::Role.load(name)
|
40
|
+
role.to_hash
|
41
|
+
rescue
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_item_from_local(name)
|
46
|
+
load_ruby_or_json_from_local(Chef::Role, "roles", name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module HealthInspector
|
2
|
+
module Color
|
3
|
+
|
4
|
+
# TODO: Use a highline color scheme here instead
|
5
|
+
def color(type, str)
|
6
|
+
colors = {
|
7
|
+
'pass' => [:green],# 90,
|
8
|
+
'fail' => [:red],# 31,
|
9
|
+
'bright pass' => [:bold, :green],# 92,
|
10
|
+
'bright fail' => [:bold, :red],# 91,
|
11
|
+
'bright yellow' => [:bold, :yellow],# 93,
|
12
|
+
'pending' => [:yellow],# 36,
|
13
|
+
'suite' => [],# 0,
|
14
|
+
'error title' => [],# 0,
|
15
|
+
'error message' => [:red],# 31,
|
16
|
+
'error stack' => [:green],# 90,
|
17
|
+
'checkmark' => [:green],# 32,
|
18
|
+
'fast' => [:green],# 90,
|
19
|
+
'medium' => [:green],# 33,
|
20
|
+
'slow' => [:red],# 31,
|
21
|
+
'green' => [:green],# 32,
|
22
|
+
'light' => [:green],# 90,
|
23
|
+
'diff gutter' => [:green],# 90,
|
24
|
+
'diff added' => [:green],# 42,
|
25
|
+
'diff removed' => [:red]# 41
|
26
|
+
}
|
27
|
+
|
28
|
+
@context.knife.ui.color( str, *colors[type] )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "chef/config"
|
2
|
+
|
3
|
+
module HealthInspector
|
4
|
+
class Context
|
5
|
+
attr_accessor :knife
|
6
|
+
|
7
|
+
def initialize(knife)
|
8
|
+
@knife = knife
|
9
|
+
end
|
10
|
+
|
11
|
+
def cookbook_path
|
12
|
+
Array( config.cookbook_path )
|
13
|
+
end
|
14
|
+
|
15
|
+
def config
|
16
|
+
Chef::Config
|
17
|
+
end
|
18
|
+
|
19
|
+
def rest
|
20
|
+
@knife.rest
|
21
|
+
end
|
22
|
+
|
23
|
+
def repo_path
|
24
|
+
ENV['PWD']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module HealthInspector
|
2
|
+
class Inspector
|
3
|
+
def self.inspect(checklists, options)
|
4
|
+
new(options).inspect( checklists )
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@context = Context.new( options[:repopath], options[:configpath] )
|
9
|
+
@context.quiet_success = options[:'quiet-success']
|
10
|
+
@context.no_color = options[:'no-color']
|
11
|
+
@context.configure
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect(checklists)
|
15
|
+
checklists.each do |checklist|
|
16
|
+
Checklists.const_get(checklist).run(@context) if Checklists.const_defined?(checklist)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module HealthInspector
|
2
|
+
class Errors
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@errors = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(message)
|
10
|
+
@errors << message
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
@errors.each { |e| yield(e) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
@errors.empty?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Pairing
|
23
|
+
attr_accessor :name, :local, :server
|
24
|
+
attr_reader :context, :errors
|
25
|
+
|
26
|
+
def initialize(context, opts={})
|
27
|
+
@context = context
|
28
|
+
@name = opts[:name]
|
29
|
+
@local = opts[:local]
|
30
|
+
@server = opts[:server]
|
31
|
+
|
32
|
+
@validations = []
|
33
|
+
@errors = Errors.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate
|
37
|
+
self.methods.grep(/^validate_/).each { |meth| send(meth) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def hash_diff(original, other)
|
41
|
+
(original.keys + other.keys).uniq.inject({}) do |memo, key|
|
42
|
+
unless original[key] == other[key]
|
43
|
+
if original[key].kind_of?(Hash) && other[key].kind_of?(Hash)
|
44
|
+
memo[key] = hash_diff(original[key], other[key])
|
45
|
+
else
|
46
|
+
memo[key] = {"server" => original[key],"local" => other[key]}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
memo
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Mixins for common validations across pairings
|
55
|
+
module ExistenceValidations
|
56
|
+
def validate_local_copy_exists
|
57
|
+
errors.add "exists on server but not locally" if local.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
def validate_server_copy_exists
|
61
|
+
errors.add "exists locally but not on server" if server.nil?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module JsonValidations
|
66
|
+
def validate_items_are_the_same
|
67
|
+
if server && local
|
68
|
+
differences = hash_diff(server, local)
|
69
|
+
errors.add differences unless differences.empty?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HealthInspector::Checklists::Cookbook do
|
4
|
+
let(:pairing) { described_class.new(health_inspector_context, :name => "dummy") }
|
5
|
+
|
6
|
+
it "should detect if an item does not exist locally" do
|
7
|
+
pairing.server = "0.0.1"
|
8
|
+
pairing.local = nil
|
9
|
+
pairing.validate
|
10
|
+
|
11
|
+
pairing.errors.should_not be_empty
|
12
|
+
pairing.errors.first.should == "exists on server but not locally"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should detect if an item does not exist on server" do
|
16
|
+
pairing.server = nil
|
17
|
+
pairing.local = "0.0.1"
|
18
|
+
pairing.validate
|
19
|
+
|
20
|
+
pairing.errors.should_not be_empty
|
21
|
+
pairing.errors.first.should == "exists locally but not on server"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should detect if an item is different" do
|
25
|
+
pairing.server = "0.0.1"
|
26
|
+
pairing.local = "0.0.2"
|
27
|
+
pairing.validate
|
28
|
+
|
29
|
+
pairing.errors.should_not be_empty
|
30
|
+
pairing.errors.first.should == "chef server has 0.0.1 but local version is 0.0.2"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should detect if an item is the same" do
|
34
|
+
pairing.should_receive(:validate_changes_on_the_server_not_in_the_repo)
|
35
|
+
pairing.server = "0.0.1"
|
36
|
+
pairing.local = "0.0.1"
|
37
|
+
pairing.validate
|
38
|
+
|
39
|
+
pairing.errors.should be_empty
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HealthInspector::Checklists::Environment do
|
4
|
+
let(:pairing) { described_class.new(health_inspector_context) }
|
5
|
+
|
6
|
+
it_behaves_like "a chef model"
|
7
|
+
it_behaves_like "a chef model that can be respresented in json"
|
8
|
+
|
9
|
+
it "should ignore _default environment if it only exists on server" do
|
10
|
+
pairing.name = "_default"
|
11
|
+
pairing.server = {}
|
12
|
+
pairing.local = nil
|
13
|
+
pairing.validate
|
14
|
+
|
15
|
+
pairing.errors.should be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/spec/role_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'health_inspector'
|
4
|
+
|
5
|
+
module HealthInspector::SpecHelpers
|
6
|
+
def health_inspector_context
|
7
|
+
@health_inspector_context ||= HealthInspector::Context.new(nil)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
RSpec.configure do |c|
|
12
|
+
c.include HealthInspector::SpecHelpers
|
13
|
+
end
|
14
|
+
|
15
|
+
shared_examples "a chef model" do
|
16
|
+
let(:pairing) { described_class.new(health_inspector_context, :name => "dummy") }
|
17
|
+
|
18
|
+
it "should detect if an item does not exist locally" do
|
19
|
+
pairing.server = {}
|
20
|
+
pairing.local = nil
|
21
|
+
pairing.validate
|
22
|
+
|
23
|
+
pairing.errors.should_not be_empty
|
24
|
+
pairing.errors.first.should == "exists on server but not locally"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should detect if an item does not exist on server" do
|
28
|
+
pairing.server = nil
|
29
|
+
pairing.local = {}
|
30
|
+
pairing.validate
|
31
|
+
|
32
|
+
pairing.errors.should_not be_empty
|
33
|
+
pairing.errors.first.should == "exists locally but not on server"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
shared_examples "a chef model that can be respresented in json" do
|
38
|
+
let(:pairing) { described_class.new(health_inspector_context, :name => "dummy") }
|
39
|
+
|
40
|
+
it "should detect if an item is different" do
|
41
|
+
pairing.server = {"foo" => "bar"}
|
42
|
+
pairing.local = {"foo" => "baz"}
|
43
|
+
pairing.validate
|
44
|
+
|
45
|
+
pairing.errors.should_not be_empty
|
46
|
+
pairing.errors.first.should == {"foo"=>{"server"=>"bar", "local"=>"baz"}}
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should detect if an item is the same" do
|
50
|
+
pairing.server = {"foo" => "bar"}
|
51
|
+
pairing.local = {"foo" => "bar"}
|
52
|
+
pairing.validate
|
53
|
+
|
54
|
+
pairing.errors.should be_empty
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-inspect
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ben Marini
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &70274490577920 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70274490577920
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70274490573900 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70274490573900
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: thor
|
38
|
+
requirement: &70274490581800 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70274490581800
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: chef
|
49
|
+
requirement: &70274490608360 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.14'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70274490608360
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: yajl-ruby
|
60
|
+
requirement: &70274490625560 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70274490625560
|
69
|
+
description: Inspect your chef repo as is compares to what is on your chef server
|
70
|
+
email:
|
71
|
+
- bmarini@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- HISTORY.md
|
79
|
+
- MIT-LICENSE
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- knife-inspect.gemspec
|
83
|
+
- lib/chef/knife/cookbook_inspect.rb
|
84
|
+
- lib/chef/knife/data_bag_inspect.rb
|
85
|
+
- lib/chef/knife/environment_inspect.rb
|
86
|
+
- lib/chef/knife/inspect.rb
|
87
|
+
- lib/chef/knife/role_inspect.rb
|
88
|
+
- lib/health_inspector.rb
|
89
|
+
- lib/health_inspector/checklists/base.rb
|
90
|
+
- lib/health_inspector/checklists/cookbooks.rb
|
91
|
+
- lib/health_inspector/checklists/data_bag_items.rb
|
92
|
+
- lib/health_inspector/checklists/data_bags.rb
|
93
|
+
- lib/health_inspector/checklists/environments.rb
|
94
|
+
- lib/health_inspector/checklists/roles.rb
|
95
|
+
- lib/health_inspector/color.rb
|
96
|
+
- lib/health_inspector/context.rb
|
97
|
+
- lib/health_inspector/inspector.rb
|
98
|
+
- lib/health_inspector/pairing.rb
|
99
|
+
- lib/health_inspector/version.rb
|
100
|
+
- spec/chef-repo/.chef/client.pem
|
101
|
+
- spec/chef-repo/.chef/knife.rb
|
102
|
+
- spec/cookbook_spec.rb
|
103
|
+
- spec/data_bag_item_spec.rb
|
104
|
+
- spec/data_bag_spec.rb
|
105
|
+
- spec/environment_spec.rb
|
106
|
+
- spec/role_spec.rb
|
107
|
+
- spec/spec_helper.rb
|
108
|
+
homepage: https://github.com/bmarini/knife-inspect
|
109
|
+
licenses: []
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project: knife-inspect
|
128
|
+
rubygems_version: 1.8.11
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: Inspect your chef repo as is compares to what is on your chef server
|
132
|
+
test_files:
|
133
|
+
- spec/chef-repo/.chef/client.pem
|
134
|
+
- spec/chef-repo/.chef/knife.rb
|
135
|
+
- spec/cookbook_spec.rb
|
136
|
+
- spec/data_bag_item_spec.rb
|
137
|
+
- spec/data_bag_spec.rb
|
138
|
+
- spec/environment_spec.rb
|
139
|
+
- spec/role_spec.rb
|
140
|
+
- spec/spec_helper.rb
|