chef-sandwich 0.2.0 → 0.3.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/NEWS +9 -0
- data/Rakefile +7 -0
- data/lib/sandwich/cli.rb +27 -12
- data/lib/sandwich/client.rb +82 -0
- data/lib/sandwich/cookbook_version.rb +27 -17
- data/lib/sandwich/runner.rb +13 -24
- data/lib/sandwich/version.rb +1 -1
- data/spec/runner_spec.rb +59 -0
- data/spec/spec_helper.rb +47 -0
- metadata +55 -23
data/NEWS
CHANGED
@@ -1,4 +1,13 @@
|
|
1
1
|
* sandwich NEWS
|
2
|
+
** 0.3.0 (2011-10-17)
|
3
|
+
|
4
|
+
- Add -e option
|
5
|
+
- Add support for cookbooks: sandwich can now load other cookbooks
|
6
|
+
- Show chef version in --version output
|
7
|
+
- Change default log level from "warn" to "error"
|
8
|
+
- Change cookbook file lookup to work relative to sandwich scripts,
|
9
|
+
fixes #6
|
10
|
+
|
2
11
|
** 0.2.0 (2011-09-07)
|
3
12
|
|
4
13
|
- Add support for cookbook_file and template resources
|
data/Rakefile
CHANGED
data/lib/sandwich/cli.rb
CHANGED
@@ -10,7 +10,9 @@ module Sandwich
|
|
10
10
|
@options = {}
|
11
11
|
|
12
12
|
# default log level
|
13
|
-
@options[:log_level] = :
|
13
|
+
@options[:log_level] = :error
|
14
|
+
|
15
|
+
@options[:command] = []
|
14
16
|
|
15
17
|
@optparse = OptionParser.new do |opts|
|
16
18
|
opts.banner = 'Usage: sandwich [options] [sandwichfile [arguments]]'
|
@@ -18,7 +20,8 @@ module Sandwich
|
|
18
20
|
opts.on_tail('-v',
|
19
21
|
'--version',
|
20
22
|
'Show sandwich version') do
|
21
|
-
puts "sandwich: #{Sandwich::
|
23
|
+
puts "sandwich: #{Sandwich::VERSION}"
|
24
|
+
puts "chef: #{Chef::VERSION}"
|
22
25
|
exit
|
23
26
|
end
|
24
27
|
|
@@ -34,6 +37,12 @@ module Sandwich
|
|
34
37
|
'Set the log level (debug, info, warn, error, fatal)') do |l|
|
35
38
|
@options[:log_level] = l.to_sym
|
36
39
|
end
|
40
|
+
|
41
|
+
opts.on('-e',
|
42
|
+
'--command COMMAND',
|
43
|
+
'Execute command as a sandwich script') do |c|
|
44
|
+
@options[:command] << c
|
45
|
+
end
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
@@ -44,21 +53,27 @@ module Sandwich
|
|
44
53
|
def run(argv)
|
45
54
|
unparsed_arguments = @optparse.order!(argv)
|
46
55
|
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
if recipe_filename.nil? || recipe_filename == '-'
|
52
|
-
recipe_filename = '<STDIN>'
|
53
|
-
recipe_file = STDIN.read
|
56
|
+
# check for -e commands
|
57
|
+
if @options[:command].any?
|
58
|
+
recipe_filename = '<COMMAND>'
|
59
|
+
recipe = @options[:command].join("\n")
|
54
60
|
else
|
55
|
-
|
61
|
+
# use first argument as sandwich script filename...
|
62
|
+
recipe_filename = unparsed_arguments.shift
|
63
|
+
|
64
|
+
# check for stdin
|
65
|
+
if recipe_filename.nil? || recipe_filename == '-'
|
66
|
+
recipe_filename = '<STDIN>'
|
67
|
+
recipe = STDIN.read
|
68
|
+
else
|
69
|
+
recipe = nil
|
70
|
+
end
|
56
71
|
end
|
57
72
|
|
58
|
-
#
|
73
|
+
# pass remaining arguments on to script
|
59
74
|
ARGV.replace(unparsed_arguments)
|
60
|
-
runner = Sandwich::Runner.new(recipe_file, recipe_filename)
|
61
75
|
|
76
|
+
runner = Sandwich::Runner.new(recipe_filename, recipe)
|
62
77
|
runner.run(@options[:log_level])
|
63
78
|
end
|
64
79
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'sandwich/cookbook_version'
|
2
|
+
require 'chef'
|
3
|
+
|
4
|
+
module Sandwich
|
5
|
+
# Chef::Client extended to inject a Sandwich cookbook into the
|
6
|
+
# client's run context
|
7
|
+
class Client < Chef::Client
|
8
|
+
# Create a new instance of Client.
|
9
|
+
#
|
10
|
+
# File specified by +recipe_filename+ is only read if no
|
11
|
+
# +recipe_string+ is supplied, otherwise +recipe_string+ is used
|
12
|
+
# as a recipe and +recipe_filename+ is only used in log messages.
|
13
|
+
#
|
14
|
+
# @param [String] recipe_filename the recipe filename
|
15
|
+
# @param [String] recipe_string the recipe definition
|
16
|
+
def initialize(recipe_filename, recipe_string = nil)
|
17
|
+
Chef::Config[:solo] = true
|
18
|
+
super()
|
19
|
+
|
20
|
+
if recipe_string
|
21
|
+
@sandwich_basedir = Dir.getwd
|
22
|
+
else
|
23
|
+
@sandwich_basedir = File.expand_path(File.dirname(recipe_filename))
|
24
|
+
recipe_string = File.read(recipe_filename)
|
25
|
+
end
|
26
|
+
|
27
|
+
add_cookbook_dir(@sandwich_basedir)
|
28
|
+
|
29
|
+
@sandwich_cookbook_name = unique_cookbook_name
|
30
|
+
@sandwich_recipe = recipe_string
|
31
|
+
@sandwich_filename = recipe_filename
|
32
|
+
end
|
33
|
+
|
34
|
+
# Silently build a new node object for this client
|
35
|
+
#
|
36
|
+
# @return [Chef::Node] the created node object
|
37
|
+
def build_node
|
38
|
+
# silence build_node from super class
|
39
|
+
silence_chef { super }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set up the client's run context, inject Sandwich cookbook into
|
43
|
+
# the created run context
|
44
|
+
#
|
45
|
+
# @return [Chef::RunContext] the created run context
|
46
|
+
def setup_run_context
|
47
|
+
run_context = super
|
48
|
+
cookbook = Sandwich::CookbookVersion.new(@sandwich_cookbook_name,
|
49
|
+
@sandwich_basedir)
|
50
|
+
run_context.cookbook_collection[@sandwich_cookbook_name] = cookbook
|
51
|
+
recipe = Chef::Recipe.new(@sandwich_cookbook_name, nil, run_context)
|
52
|
+
recipe.from_string(@sandwich_recipe, @sandwich_filename)
|
53
|
+
run_context
|
54
|
+
end
|
55
|
+
|
56
|
+
# Add a cookbook directory to the front of the client's cookbook
|
57
|
+
# search path.
|
58
|
+
#
|
59
|
+
# @param [String] cookbook_dir the cookbook directory to add
|
60
|
+
# @return [Array] the new cookbook search path
|
61
|
+
def add_cookbook_dir(cookbook_dir)
|
62
|
+
Chef::Config[:cookbook_path].unshift(cookbook_dir)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def silence_chef
|
67
|
+
log_level = Chef::Log.level
|
68
|
+
Chef::Log.level = :fatal
|
69
|
+
yield
|
70
|
+
ensure
|
71
|
+
Chef::Log.level = log_level
|
72
|
+
end
|
73
|
+
|
74
|
+
# monkey patch: don't check for empty cookbook paths
|
75
|
+
def assert_cookbook_path_not_empty(run_context); end
|
76
|
+
|
77
|
+
def unique_cookbook_name
|
78
|
+
# use uuid in sandwich cookbook name to avoid name collisions
|
79
|
+
"sandwich_#{UUIDTools::UUID.random_create}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -1,21 +1,31 @@
|
|
1
1
|
require 'chef/cookbook_version'
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
|
3
|
+
module Sandwich
|
4
|
+
# Chef::CookbookVersion, extended to use simpler file source paths
|
5
|
+
# (always uses local files relative to @basedir instead of manifest
|
6
|
+
# records)
|
7
|
+
class CookbookVersion < Chef::CookbookVersion
|
8
|
+
# @param [String] name the cookbook's name
|
9
|
+
# @param [String basedir the cookbook's basedir
|
10
|
+
def initialize(name, basedir)
|
11
|
+
super(name)
|
12
|
+
@basedir = basedir
|
13
|
+
end
|
14
|
+
|
15
|
+
# Determines the absolute source filename on disk for various file
|
16
|
+
# resources from their relative path
|
17
|
+
#
|
18
|
+
# @param [Chef::Node] node the node object, ignored
|
19
|
+
# @param [Symbol] segment the segment of the current resource, ignored
|
20
|
+
# @param [String] filename the source file path
|
21
|
+
# @param [String] current_filepath the target file path, ignored
|
22
|
+
# @return [String] the preferred source filename
|
23
|
+
def preferred_filename_on_disk_location(node,
|
24
|
+
segment,
|
25
|
+
filename,
|
26
|
+
current_filepath=nil)
|
27
|
+
# keep absolute paths, convert relative paths into absolute paths
|
28
|
+
filename.start_with?('/') ? filename : File.join(@basedir, filename)
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
data/lib/sandwich/runner.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
require 'chef'
|
1
|
+
require 'chef/config'
|
2
2
|
require 'sandwich/recipe'
|
3
|
-
require 'sandwich/
|
3
|
+
require 'sandwich/client'
|
4
4
|
|
5
5
|
module Sandwich
|
6
6
|
# This class constructs a {Chef::Recipe} from a recipe string and
|
7
|
-
# applies it with Chef standalone mode
|
7
|
+
# applies it with Chef standalone mode.
|
8
8
|
class Runner
|
9
|
+
# Create a new instance of Runner.
|
10
|
+
#
|
11
|
+
# File specified by +recipe_filename+ is only read if no
|
12
|
+
# +recipe_string+ is supplied, otherwise +recipe_string+ is used
|
13
|
+
# as a recipe and +recipe_filename+ is only used in log messages.
|
14
|
+
#
|
15
|
+
# @param [String] recipe_filename the recipe filename
|
9
16
|
# @param [String] recipe_string the recipe definition
|
10
|
-
def initialize(
|
11
|
-
@client =
|
12
|
-
cookbook_name = 'sandwich'
|
13
|
-
cookbook_collection = single_cookbook_collection(cookbook_name)
|
14
|
-
@run_context = Chef::RunContext.new(@client.node, cookbook_collection)
|
15
|
-
@recipe = Chef::Recipe.new(cookbook_name, nil, @run_context)
|
16
|
-
@recipe.from_string(recipe_string, filename)
|
17
|
+
def initialize(recipe_filename, recipe_string = nil)
|
18
|
+
@client = Sandwich::Client.new(recipe_filename, recipe_string)
|
17
19
|
end
|
18
20
|
|
19
21
|
# Run Chef in standalone mode, apply recipe
|
@@ -25,17 +27,10 @@ module Sandwich
|
|
25
27
|
# @return [void]
|
26
28
|
def run(log_level = :warn)
|
27
29
|
configure_chef(log_level)
|
28
|
-
|
30
|
+
@client.run
|
29
31
|
end
|
30
32
|
|
31
33
|
private
|
32
|
-
def solo_client
|
33
|
-
Chef::Config[:solo] = true
|
34
|
-
client = Chef::Client.new
|
35
|
-
client.run_ohai
|
36
|
-
client.build_node
|
37
|
-
end
|
38
|
-
|
39
34
|
def configure_chef(log_level)
|
40
35
|
Chef::Log.level = log_level
|
41
36
|
|
@@ -46,11 +41,5 @@ module Sandwich
|
|
46
41
|
Chef::Config[:file_backup_path] = File.join(local_cache, 'backup')
|
47
42
|
end
|
48
43
|
end
|
49
|
-
|
50
|
-
# create a cookbook collection containing a single empty cookbook
|
51
|
-
def single_cookbook_collection(cookbook_name)
|
52
|
-
cookbook = Chef::CookbookVersion.new(cookbook_name)
|
53
|
-
Chef::CookbookCollection.new({ cookbook_name => cookbook })
|
54
|
-
end
|
55
44
|
end
|
56
45
|
end
|
data/lib/sandwich/version.rb
CHANGED
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Sandwich::Runner do
|
5
|
+
after(:each) do
|
6
|
+
FakeFS::FileSystem.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Chef::Resource::File do
|
10
|
+
it 'should create files' do
|
11
|
+
with_fakefs do
|
12
|
+
filename = '/foo'
|
13
|
+
content = 'hello world'
|
14
|
+
recipe = %Q(file '#{filename}' do content '#{content}';end)
|
15
|
+
run_recipe(recipe)
|
16
|
+
file = File.read(filename)
|
17
|
+
file.must_equal content
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should throw exceptions for files in missing directories' do
|
22
|
+
with_fakefs do
|
23
|
+
filename = '/i/am/not/here'
|
24
|
+
content = 'hello world'
|
25
|
+
recipe = %Q(file '#{filename}' do content '#{content}';end)
|
26
|
+
run = Proc.new { run_recipe recipe }
|
27
|
+
run.must_raise(Errno::ENOENT,
|
28
|
+
Chef::Exceptions::EnclosingDirectoryDoesNotExist)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Chef::Resource::CookbookFile do
|
34
|
+
it 'should create cookbook files' do
|
35
|
+
with_fakefs do
|
36
|
+
source = '/source'
|
37
|
+
target = '/target'
|
38
|
+
content = 'hello world'
|
39
|
+
recipe = %Q(cookbook_file '#{target}' do source '#{source}';end)
|
40
|
+
# create source for cookbook file
|
41
|
+
File.open(source, 'w') { |f| f.write(content) }
|
42
|
+
run_recipe(recipe)
|
43
|
+
File.read(source).must_equal File.read(target)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe Chef::Resource::Directory do
|
49
|
+
it 'should create directories' do
|
50
|
+
with_fakefs do
|
51
|
+
dir = '/foo'
|
52
|
+
recipe = %Q(directory '#{dir}')
|
53
|
+
assert !Dir.exists?(dir)
|
54
|
+
run_recipe(recipe)
|
55
|
+
assert Dir.exists?(dir)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'fakefs/safe'
|
5
|
+
require 'sandwich/runner'
|
6
|
+
require 'chef'
|
7
|
+
|
8
|
+
# Ohai::System, monkey patched to return static values
|
9
|
+
class Ohai::System
|
10
|
+
def all_plugins
|
11
|
+
@data = Mash.new({ :hostname => 'archie',
|
12
|
+
:platform => 'ubuntu',
|
13
|
+
:fqdn => 'archie.example.com',
|
14
|
+
:platform_version => '11.04',
|
15
|
+
:os_version => '2.6.38-10-generic' })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# monkey patch for https://github.com/defunkt/fakefs/issues/96
|
20
|
+
class FakeFS::Dir
|
21
|
+
def self.mkdir(path, integer = 0)
|
22
|
+
FileUtils.mkdir(path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def runner_from_recipe(recipe)
|
27
|
+
Sandwich::Runner.new('<SPEC_HELPER>', recipe)
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_recipe(recipe)
|
31
|
+
runner_from_recipe(recipe).run(:fatal)
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_fakefs
|
35
|
+
FakeFS.activate!
|
36
|
+
setup_standard_dirs
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
FakeFS.deactivate!
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_standard_dirs
|
43
|
+
FileUtils.mkdir_p '/tmp'
|
44
|
+
end
|
45
|
+
|
46
|
+
# make sure Chef 0.10 exceptions are available when using older Chef versions
|
47
|
+
class Chef::Exceptions::EnclosingDirectoryDoesNotExist; end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-sandwich
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 0.2.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Sebastian Boehm
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-10-17 00:00:00 +02:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
@@ -26,13 +21,53 @@ dependencies:
|
|
26
21
|
requirements:
|
27
22
|
- - ">="
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 25
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
- 9
|
33
24
|
version: "0.9"
|
34
25
|
type: :runtime
|
35
26
|
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: uuidtools
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: minitest
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: fakefs
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rake
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.8.7
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
36
71
|
description: |
|
37
72
|
Sandwich lets you apply Chef recipes to your system without having to
|
38
73
|
worry about cookbooks or configuration.
|
@@ -50,13 +85,16 @@ files:
|
|
50
85
|
- LICENSE
|
51
86
|
- NEWS
|
52
87
|
- bin/sandwich
|
53
|
-
- lib/sandwich.rb
|
54
|
-
- lib/sandwich/version.rb
|
55
88
|
- lib/sandwich/cli.rb
|
56
|
-
- lib/sandwich/
|
89
|
+
- lib/sandwich/client.rb
|
57
90
|
- lib/sandwich/cookbook_version.rb
|
91
|
+
- lib/sandwich/recipe.rb
|
58
92
|
- lib/sandwich/runner.rb
|
59
|
-
|
93
|
+
- lib/sandwich/version.rb
|
94
|
+
- lib/sandwich.rb
|
95
|
+
- spec/runner_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
has_rdoc: true
|
60
98
|
homepage: https://github.com/sometimesfood/sandwich
|
61
99
|
licenses: []
|
62
100
|
|
@@ -70,23 +108,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
108
|
requirements:
|
71
109
|
- - ">="
|
72
110
|
- !ruby/object:Gem::Version
|
73
|
-
hash: 3
|
74
|
-
segments:
|
75
|
-
- 0
|
76
111
|
version: "0"
|
77
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
113
|
none: false
|
79
114
|
requirements:
|
80
115
|
- - ">="
|
81
116
|
- !ruby/object:Gem::Version
|
82
|
-
hash: 3
|
83
|
-
segments:
|
84
|
-
- 0
|
85
117
|
version: "0"
|
86
118
|
requirements: []
|
87
119
|
|
88
120
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
121
|
+
rubygems_version: 1.6.2
|
90
122
|
signing_key:
|
91
123
|
specification_version: 3
|
92
124
|
summary: The easiest way to get started as a chef
|