knife-essentials 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/LICENSE +201 -0
- data/README.rdoc +114 -0
- data/Rakefile +24 -0
- data/lib/chef/knife/diff.rb +28 -0
- data/lib/chef/knife/list.rb +107 -0
- data/lib/chef/knife/show.rb +30 -0
- data/lib/chef_fs.rb +9 -0
- data/lib/chef_fs/command_line.rb +91 -0
- data/lib/chef_fs/diff.rb +158 -0
- data/lib/chef_fs/file_pattern.rb +292 -0
- data/lib/chef_fs/file_system.rb +69 -0
- data/lib/chef_fs/file_system/base_fs_dir.rb +23 -0
- data/lib/chef_fs/file_system/base_fs_object.rb +52 -0
- data/lib/chef_fs/file_system/chef_server_root_dir.rb +48 -0
- data/lib/chef_fs/file_system/cookbook_dir.rb +80 -0
- data/lib/chef_fs/file_system/cookbook_file.rb +32 -0
- data/lib/chef_fs/file_system/cookbook_subdir.rb +25 -0
- data/lib/chef_fs/file_system/cookbooks_dir.rb +21 -0
- data/lib/chef_fs/file_system/data_bag_dir.rb +22 -0
- data/lib/chef_fs/file_system/data_bags_dir.rb +23 -0
- data/lib/chef_fs/file_system/file_system_entry.rb +36 -0
- data/lib/chef_fs/file_system/file_system_root_dir.rb +11 -0
- data/lib/chef_fs/file_system/nonexistent_fs_object.rb +23 -0
- data/lib/chef_fs/file_system/not_found_exception.rb +12 -0
- data/lib/chef_fs/file_system/rest_list_dir.rb +42 -0
- data/lib/chef_fs/file_system/rest_list_entry.rb +72 -0
- data/lib/chef_fs/knife.rb +47 -0
- data/lib/chef_fs/path_utils.rb +43 -0
- data/lib/chef_fs/version.rb +4 -0
- data/spec/chef_fs/diff_spec.rb +263 -0
- data/spec/chef_fs/file_pattern_spec.rb +507 -0
- data/spec/chef_fs/file_system_spec.rb +117 -0
- data/spec/support/file_system_support.rb +108 -0
- metadata +79 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'chef_fs/path_utils'
|
2
|
+
|
3
|
+
module ChefFS
|
4
|
+
module FileSystem
|
5
|
+
# Yields a list of all things under (and including) this entry that match the
|
6
|
+
# given pattern.
|
7
|
+
#
|
8
|
+
# ==== Attributes
|
9
|
+
#
|
10
|
+
# * +entry+ - Entry to start listing under
|
11
|
+
# * +pattern+ - ChefFS::FilePattern to match children under
|
12
|
+
#
|
13
|
+
def self.list(entry, pattern, &block)
|
14
|
+
# Include self in results if it matches
|
15
|
+
if pattern.match?(entry.path)
|
16
|
+
block.call(entry)
|
17
|
+
end
|
18
|
+
|
19
|
+
if entry.dir? && pattern.could_match_children?(entry.path)
|
20
|
+
# If it's possible that our children could match, descend in and add matches.
|
21
|
+
exact_child_name = pattern.exact_child_name_under(entry.path)
|
22
|
+
|
23
|
+
# If we've got an exact name, don't bother listing children; just grab the
|
24
|
+
# child with the given name.
|
25
|
+
if exact_child_name
|
26
|
+
exact_child = entry.child(exact_child_name)
|
27
|
+
if exact_child
|
28
|
+
list(exact_child, pattern, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Otherwise, go through all children and find any matches
|
32
|
+
else
|
33
|
+
entry.children.each do |child|
|
34
|
+
list(child, pattern, &block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Resolve the given path against the entry, returning
|
41
|
+
# the entry at the end of the path.
|
42
|
+
#
|
43
|
+
# ==== Attributes
|
44
|
+
#
|
45
|
+
# * +entry+ - the entry to start looking under. Relative
|
46
|
+
# paths will be resolved from here.
|
47
|
+
# * +path+ - the path to resolve. If it starts with +/+,
|
48
|
+
# the path will be resolved starting from +entry.root+.
|
49
|
+
#
|
50
|
+
# ==== Examples
|
51
|
+
#
|
52
|
+
# ChefFS::FileSystem.resolve_path(root_path, 'cookbooks/java/recipes/default.rb')
|
53
|
+
#
|
54
|
+
def self.resolve_path(entry, path)
|
55
|
+
return entry if path.length == 0
|
56
|
+
return resolve_path(entry.root, path) if path[0] == "/" && entry.root != entry
|
57
|
+
if path[0] == "/"
|
58
|
+
path = path[1,path.length-1]
|
59
|
+
end
|
60
|
+
|
61
|
+
result = entry
|
62
|
+
ChefFS::PathUtils::split(path).each do |part|
|
63
|
+
result = result.child(part)
|
64
|
+
end
|
65
|
+
result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'chef_fs/file_system/base_fs_object'
|
2
|
+
require 'chef_fs/file_system/nonexistent_fs_object'
|
3
|
+
|
4
|
+
module ChefFS
|
5
|
+
module FileSystem
|
6
|
+
class BaseFSDir < BaseFSObject
|
7
|
+
def initialize(name, parent)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def dir?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
# Override child(name) to provide a child object by name without the network read
|
16
|
+
def child(name)
|
17
|
+
children.select { |child| child.name == name }.first || NonexistentFSObject.new(name, self)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Abstract: children
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'chef_fs/path_utils'
|
2
|
+
|
3
|
+
module ChefFS
|
4
|
+
module FileSystem
|
5
|
+
class BaseFSObject
|
6
|
+
def initialize(name, parent)
|
7
|
+
@parent = parent
|
8
|
+
@name = name
|
9
|
+
if parent
|
10
|
+
@path = ChefFS::PathUtils::join(parent.path, name)
|
11
|
+
else
|
12
|
+
if name != ''
|
13
|
+
raise ArgumentError, "Name of root object must be empty string: was '#{name}' instead"
|
14
|
+
end
|
15
|
+
@path = '/'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :name
|
20
|
+
attr_reader :parent
|
21
|
+
attr_reader :path
|
22
|
+
|
23
|
+
def root
|
24
|
+
parent ? parent.root : self
|
25
|
+
end
|
26
|
+
|
27
|
+
def path_for_printing
|
28
|
+
if parent
|
29
|
+
ChefFS::PathUtils::join(parent.path_for_printing, name)
|
30
|
+
else
|
31
|
+
name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def dir?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def exists?
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def content_type
|
44
|
+
:text
|
45
|
+
end
|
46
|
+
|
47
|
+
# Important directory attributes: name, parent, path, root
|
48
|
+
# Overridable attributes: dir?, child(name), path_for_printing
|
49
|
+
# Abstract: read, write, delete, children
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'chef_fs/file_system/base_fs_dir'
|
2
|
+
require 'chef_fs/file_system/rest_list_dir'
|
3
|
+
require 'chef_fs/file_system/data_bags_dir'
|
4
|
+
require 'chef_fs/file_system/cookbooks_dir'
|
5
|
+
|
6
|
+
module ChefFS
|
7
|
+
module FileSystem
|
8
|
+
class ChefServerRootDir < BaseFSDir
|
9
|
+
def initialize(root_name, config)
|
10
|
+
super("", nil)
|
11
|
+
@chef_server_url = config[:chef_server_url]
|
12
|
+
@chef_username = config[:node_name]
|
13
|
+
@chef_private_key = config[:client_key]
|
14
|
+
@environment = config[:environment]
|
15
|
+
@root_name = root_name
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :chef_server_url
|
19
|
+
attr_reader :chef_username
|
20
|
+
attr_reader :chef_private_key
|
21
|
+
attr_reader :environment
|
22
|
+
|
23
|
+
def rest
|
24
|
+
Chef::REST.new(chef_server_url, chef_username, chef_private_key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def api_path
|
28
|
+
""
|
29
|
+
end
|
30
|
+
|
31
|
+
def path_for_printing
|
32
|
+
@root_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def children
|
36
|
+
@children ||= [
|
37
|
+
RestListDir.new("clients", self),
|
38
|
+
CookbooksDir.new(self),
|
39
|
+
DataBagsDir.new(self),
|
40
|
+
RestListDir.new("environments", self),
|
41
|
+
RestListDir.new("nodes", self),
|
42
|
+
RestListDir.new("roles", self),
|
43
|
+
# RestListDir.new("sandboxes", self)
|
44
|
+
]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'chef_fs/file_system/rest_list_dir'
|
2
|
+
require 'chef_fs/file_system/cookbook_subdir'
|
3
|
+
require 'chef_fs/file_system/cookbook_file'
|
4
|
+
require 'chef/cookbook_version'
|
5
|
+
|
6
|
+
module ChefFS
|
7
|
+
module FileSystem
|
8
|
+
class CookbookDir < BaseFSDir
|
9
|
+
def initialize(name, parent, versions = nil)
|
10
|
+
super(name, parent)
|
11
|
+
@versions = versions
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :versions
|
15
|
+
|
16
|
+
def add_child(child)
|
17
|
+
@children << child
|
18
|
+
end
|
19
|
+
|
20
|
+
def api_path
|
21
|
+
"#{parent.api_path}/#{name}/_latest"
|
22
|
+
end
|
23
|
+
|
24
|
+
def child(name)
|
25
|
+
children.select { |child| child.name == name }.first || NonexistentFSObject.new(name, self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def children
|
29
|
+
if @children.nil?
|
30
|
+
@children = []
|
31
|
+
Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
|
32
|
+
next unless manifest.has_key?(segment)
|
33
|
+
manifest[segment].each do |segment_file|
|
34
|
+
parts = segment_file['path'].split('/')
|
35
|
+
# Get or create the path to the file
|
36
|
+
container = self
|
37
|
+
parts[0,parts.length-1].each do |part|
|
38
|
+
old_container = container
|
39
|
+
container = old_container.children.select { |child| part == child.name }.first
|
40
|
+
if !container
|
41
|
+
container = CookbookSubdir.new(part, old_container)
|
42
|
+
old_container.add_child(container)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# Create the file itself
|
46
|
+
container.add_child(CookbookFile.new(parts[parts.length-1], container, segment_file))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
@children
|
51
|
+
end
|
52
|
+
|
53
|
+
def exists?
|
54
|
+
if !@versions
|
55
|
+
child = parent.children.select { |child| child.name == name }.first
|
56
|
+
@versions = child.versions if child
|
57
|
+
end
|
58
|
+
!!@versions
|
59
|
+
end
|
60
|
+
|
61
|
+
def rest
|
62
|
+
parent.rest
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def manifest
|
68
|
+
begin
|
69
|
+
@manifest ||= rest.get_rest(api_path).manifest
|
70
|
+
rescue Net::HTTPServerException
|
71
|
+
if $!.response.code == "404"
|
72
|
+
raise ChefFS::FileSystem::NotFoundException, $!
|
73
|
+
else
|
74
|
+
raise
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'chef_fs/file_system/base_fs_object'
|
2
|
+
|
3
|
+
module ChefFS
|
4
|
+
module FileSystem
|
5
|
+
class CookbookFile < BaseFSObject
|
6
|
+
def initialize(name, parent, file)
|
7
|
+
super(name, parent)
|
8
|
+
@file = file
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :file
|
12
|
+
|
13
|
+
def checksum
|
14
|
+
file[:checksum]
|
15
|
+
end
|
16
|
+
|
17
|
+
def read
|
18
|
+
old_sign_on_redirect = rest.sign_on_redirect
|
19
|
+
rest.sign_on_redirect = false
|
20
|
+
begin
|
21
|
+
rest.get_rest(file['url'])
|
22
|
+
ensure
|
23
|
+
rest.sign_on_redirect = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def rest
|
28
|
+
parent.rest
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'chef_fs/file_system/base_fs_dir'
|
2
|
+
|
3
|
+
# TODO: take environment into account
|
4
|
+
|
5
|
+
module ChefFS
|
6
|
+
module FileSystem
|
7
|
+
class CookbookSubdir < BaseFSDir
|
8
|
+
def initialize(name, parent)
|
9
|
+
super(name, parent)
|
10
|
+
@children = []
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :versions
|
14
|
+
attr_reader :children
|
15
|
+
|
16
|
+
def add_child(child)
|
17
|
+
@children << child
|
18
|
+
end
|
19
|
+
|
20
|
+
def rest
|
21
|
+
parent.rest
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'chef_fs/file_system/rest_list_dir'
|
2
|
+
require 'chef_fs/file_system/cookbook_dir'
|
3
|
+
|
4
|
+
module ChefFS
|
5
|
+
module FileSystem
|
6
|
+
class CookbooksDir < RestListDir
|
7
|
+
def initialize(parent)
|
8
|
+
super("cookbooks", parent)
|
9
|
+
end
|
10
|
+
|
11
|
+
def child(name)
|
12
|
+
result = @children.select { |child| child.name == name }.first if @children
|
13
|
+
result || CookbookDir.new(name, self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def children
|
17
|
+
@children ||= rest.get_rest(api_path).map { |key, value| CookbookDir.new(key, self, value) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'chef_fs/file_system/base_fs_dir'
|
2
|
+
require 'chef_fs/file_system/rest_list_entry'
|
3
|
+
|
4
|
+
# TODO: take environment into account
|
5
|
+
|
6
|
+
module ChefFS
|
7
|
+
module FileSystem
|
8
|
+
class DataBagDir < RestListDir
|
9
|
+
def initialize(name, parent, exists = nil)
|
10
|
+
super(name, parent)
|
11
|
+
@exists = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists?
|
15
|
+
if @exists.nil?
|
16
|
+
@exists = parent.children.any? { |child| child.name == name }
|
17
|
+
end
|
18
|
+
@exists
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'chef_fs/file_system/rest_list_dir'
|
2
|
+
require 'chef_fs/file_system/data_bag_dir'
|
3
|
+
|
4
|
+
# TODO: take environment into account
|
5
|
+
|
6
|
+
module ChefFS
|
7
|
+
module FileSystem
|
8
|
+
class DataBagsDir < RestListDir
|
9
|
+
def initialize(parent)
|
10
|
+
super("data_bags", parent, "data")
|
11
|
+
end
|
12
|
+
|
13
|
+
def child(name)
|
14
|
+
result = @children.select { |child| child.name == name }.first if @children
|
15
|
+
result || DataBagDir.new(name, self)
|
16
|
+
end
|
17
|
+
|
18
|
+
def children
|
19
|
+
@children ||= rest.get_rest(api_path).keys.map { |entry| DataBagDir.new(entry, self, true) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'chef_fs/file_system/base_fs_dir'
|
2
|
+
require 'chef_fs/file_system/rest_list_dir'
|
3
|
+
require 'chef_fs/path_utils'
|
4
|
+
|
5
|
+
module ChefFS
|
6
|
+
module FileSystem
|
7
|
+
class FileSystemEntry < BaseFSDir
|
8
|
+
def initialize(name, parent, file_path = nil)
|
9
|
+
super(name, parent)
|
10
|
+
@file_path = file_path || "#{parent.file_path}/#{name}"
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :file_path
|
14
|
+
|
15
|
+
def path_for_printing
|
16
|
+
ChefFS::PathUtils::relative_to(file_path, File.absolute_path(Dir.pwd))
|
17
|
+
end
|
18
|
+
|
19
|
+
def children
|
20
|
+
@children ||= Dir.entries(file_path).select { |entry| entry[0] != "." }.map { |entry| FileSystemEntry.new(entry, self) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def dir?
|
24
|
+
File.directory?(file_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def read
|
28
|
+
begin
|
29
|
+
IO.read(file_path)
|
30
|
+
rescue IONotFoundException # TODO real exception
|
31
|
+
raise NotFoundException, $!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|