baker 0.1.0 → 0.1.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/README.markdown +45 -4
- data/TODO +28 -0
- data/baker.log +1 -0
- data/bin/{baker → bake} +2 -2
- data/gemspec.rb +2 -2
- data/lib/baker.rb +108 -68
- data/test/baker_test.rb +25 -0
- data/test/fixtures/cookbooks-empty/baker.log +1 -0
- data/test/fixtures/cookbooks-valid/baker.log +3 -0
- data/test/fixtures/cookbooks-valid/config/baker/node.json +16 -0
- data/test/fixtures/cookbooks-valid/config/baker/solo.rb +2 -0
- data/test/fixtures/cookbooks-valid/cookbooks/example_recipe1/recipes/default.rb +1 -0
- data/test/fixtures/cookbooks-valid/cookbooks/example_recipe2/recipes/default.rb +1 -0
- metadata +20 -6
data/README.markdown
CHANGED
@@ -1,18 +1,59 @@
|
|
1
|
-
|
1
|
+
Baker
|
2
2
|
=======
|
3
3
|
|
4
|
-
A
|
4
|
+
A simple way to run chef recipes on one server.
|
5
5
|
|
6
6
|
Install
|
7
7
|
-------
|
8
8
|
|
9
9
|
<pre>
|
10
|
-
|
10
|
+
gem install baker --source http://gemcutter.org --no-ri --no-rdoc # sudo if you need to
|
11
11
|
</pre>
|
12
12
|
|
13
|
+
Prerequisite
|
14
|
+
-------
|
15
|
+
|
16
|
+
You need to set up sshkeys on the server so you can ssh into the box without passwords.
|
17
|
+
|
18
|
+
On the server:
|
19
|
+
|
20
|
+
You'll need to make sure to have chef installed.
|
21
|
+
|
22
|
+
On the client:
|
23
|
+
|
24
|
+
First you need to be in a cookbooks project. Here's an example of a mininum cookbooks project:
|
25
|
+
|
26
|
+
├── config
|
27
|
+
│ └── baker
|
28
|
+
│ ├── node.json
|
29
|
+
│ └── solo.rb
|
30
|
+
└── cookbooks
|
31
|
+
├── example_recipe1
|
32
|
+
│ └── recipes
|
33
|
+
│ └── default.rb
|
34
|
+
└── example_recipe2
|
35
|
+
└── recipes
|
36
|
+
└── default.rb
|
37
|
+
|
38
|
+
config/baker/node.json and config/baker/solo.rb are important. These are the configurations that get passed to the chef run that will tell it which recipes to run.
|
39
|
+
|
40
|
+
You need configure solo.rb to have this:
|
41
|
+
|
42
|
+
solo.rb:
|
43
|
+
file_cache_path "/tmp/baker"
|
44
|
+
cookbook_path "/tmp/baker/recipes/cookbooks"
|
45
|
+
|
46
|
+
node.json will determine what recipes you'll run:
|
47
|
+
|
48
|
+
config/baker/node.json:
|
49
|
+
|
50
|
+
|
13
51
|
Usage
|
14
52
|
-------
|
15
53
|
|
54
|
+
Once all that is set up, you can run baker and that will upload the recipes to the server and run them.
|
55
|
+
Errors are logged to /var/log/baker-chef-server.log and /var/log/baker-chef-client.log.
|
56
|
+
|
16
57
|
<pre>
|
17
|
-
|
58
|
+
bake <server>
|
18
59
|
</pre>
|
data/TODO
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
* if there is an error on the server chef-solo run, how can I notify bake command on the client.
|
2
|
+
* uploading baker-client.log to server after done or on at_exit, take logger from ey-cap
|
3
|
+
|
4
|
+
#
|
5
|
+
def execute
|
6
|
+
command = "#{@opts[:chef_bin]} -j /etc/chef/dna.json -c #{chef_config} -r \"#{@recipes_url}\" > #{@chef_log} 2>&1"
|
7
|
+
@logger.debug "Running: #{command}"
|
8
|
+
if system(command)
|
9
|
+
@logger.info "Running telinit"
|
10
|
+
system("telinit q")
|
11
|
+
@logger.info "Finished #{@name} chef run"
|
12
|
+
else
|
13
|
+
@logger.error("#{@name} chef run failed. Reporting error")
|
14
|
+
raise DeployError, "#{@name} chef run failed"
|
15
|
+
end
|
16
|
+
ensure
|
17
|
+
if File.exists?(@chef_log)
|
18
|
+
FileUtils.ln_sf(@chef_log, "/var/log/chef.#{@name}.log")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
##################################################################
|
23
|
+
|
24
|
+
@enzyme_log = Logger.new("/var/log/enzyme.log")
|
25
|
+
@stderr_log = Logger.new($stderr)
|
26
|
+
|
27
|
+
@stderr_log.send(level, message)
|
28
|
+
@enzyme_log.send(level, message)
|
data/baker.log
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Logfile created on Sun Jul 11 19:37:09 -0700 2010 by logger.rb/22283
|
data/bin/{baker → bake}
RENAMED
@@ -1,10 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require File.join(File.
|
3
|
+
require File.join(File.expand_path('../../lib/baker', __FILE__))
|
4
4
|
|
5
5
|
server = ARGV[0]
|
6
6
|
if server.nil? or server == ""
|
7
7
|
puts "Usage: baker <server-name>"
|
8
8
|
exit 1
|
9
9
|
end
|
10
|
-
Baker.run(server)
|
10
|
+
Baker.run(:host => server)
|
data/gemspec.rb
CHANGED
@@ -7,12 +7,12 @@ GEM_SPEC = Gem::Specification.new do |s|
|
|
7
7
|
s.homepage = "http://github.com/tongueroo/#{GEM_NAME}"
|
8
8
|
s.summary = "A simple way to run chef recipes"
|
9
9
|
# == CONFIGURE ==
|
10
|
-
s.executables += [
|
10
|
+
s.executables += ["bake"]
|
11
11
|
s.extra_rdoc_files = [ "README.markdown" ]
|
12
12
|
s.files = GEM_FILES.to_a
|
13
13
|
s.has_rdoc = false
|
14
14
|
s.name = GEM_NAME
|
15
15
|
s.platform = Gem::Platform::RUBY
|
16
16
|
s.require_path = "lib"
|
17
|
-
s.version = "0.1.
|
17
|
+
s.version = "0.1.1"
|
18
18
|
end
|
data/lib/baker.rb
CHANGED
@@ -1,93 +1,133 @@
|
|
1
1
|
# TODO: upload config files: dna.json and solo.rb
|
2
2
|
|
3
|
+
require 'rubygems'
|
3
4
|
require 'net/ssh'
|
4
5
|
require 'pp'
|
5
6
|
|
7
|
+
class NotCookbookProject < RuntimeError; end
|
8
|
+
|
6
9
|
class Baker
|
7
|
-
def self.run(
|
8
|
-
new(
|
10
|
+
def self.run(options)
|
11
|
+
@baker = Baker.new(options)
|
12
|
+
@baker.run
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
@host = options[:host] || raise("need to set host")
|
17
|
+
@user = options[:user]
|
18
|
+
@root = options[:root] || Dir.pwd
|
19
|
+
set_logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_logger
|
23
|
+
@logger = if File.exist?(@root+"/log")
|
24
|
+
Logger.new(@root+"/log/baker.log")
|
25
|
+
else
|
26
|
+
Logger.new(@root+"/baker.log")
|
27
|
+
end
|
9
28
|
end
|
10
|
-
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
@host = host
|
15
|
-
@user = user
|
29
|
+
|
30
|
+
def run
|
31
|
+
validate_cookbook_project
|
32
|
+
log "*** start running chef recipes on #{@host}"
|
16
33
|
Net::SSH.start(@host, @user) do |ssh|
|
17
|
-
check
|
18
|
-
upload_chef_configs(ssh)
|
19
34
|
upload_recipes(ssh)
|
20
35
|
run_chef(ssh)
|
21
36
|
end
|
22
|
-
log "done running chef recipes on #{host}"
|
37
|
+
log "*** done running chef recipes on #{@host}, check /var/log/baker-chef-server.log"
|
23
38
|
end
|
24
|
-
|
25
|
-
def
|
39
|
+
|
40
|
+
def validate_cookbook_project
|
26
41
|
if !File.exist?('cookbooks')
|
27
|
-
raise "not in chef cookbooks project
|
28
|
-
end
|
29
|
-
end
|
30
|
-
def upload_chef_configs(ssh)
|
31
|
-
log "uploading chef configs to #{@host}..."
|
32
|
-
if !File.exist?("config/baker/dna.json") or !File.exist?("config/baker/solo.rb")
|
33
|
-
raise "need to create a config/baker/dna.json and config/baker/solo.rb file, so it can be uploaded to the server that needs it"
|
42
|
+
raise NotCookbookProject.new("not in chef cookbooks project, @root is #{@root}")
|
34
43
|
end
|
35
|
-
bash_exec("tar czf chef-config.tgz config/baker")
|
36
|
-
bash_exec("scp chef-config.tgz #{@host}:")
|
37
|
-
ssh_exec(ssh, "rm -rf chef-config && tar -zxf chef-config.tgz && mv config/baker chef-config")
|
38
|
-
ssh_exec(ssh, "rm -f chef-config.tgz")
|
39
|
-
bash_exec("rm -f chef-config.tgz")
|
40
44
|
end
|
45
|
+
|
41
46
|
def upload_recipes(ssh)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
47
|
+
if !File.exist?("config/dna.json") or !File.exist?("config/solo.rb")
|
48
|
+
raise "need to create a config/dna.json and config/solo.rb file, so it can be uploaded to the server that needs it"
|
49
|
+
end
|
50
|
+
|
51
|
+
log "*** uploading chef recipes to #{@host}..."
|
52
|
+
@recipes_path = "/tmp/baker/recipes"
|
53
|
+
@tarball = "#{File.dirname(@recipes_path)}/recipes.tgz"
|
54
|
+
# create tarball
|
55
|
+
local_cmd("tar czf /tmp/recipes.tgz config cookbooks")
|
56
|
+
# upload to /tmp/baker/recipes
|
57
|
+
remote_cmd(ssh, "if [ -d '#{@recipes_path}' ] ; then rm -rf #{@recipes_path}; fi") # cleanup from before
|
58
|
+
remote_cmd(ssh, "if [ ! -d '#{@recipes_path}' ] ; then mkdir -p #{@recipes_path}; fi")
|
59
|
+
local_cmd("scp /tmp/recipes.tgz #{@host}:#{@tarball}")
|
60
|
+
# not using -C flag changes /root folder owner!!! and screws up ssh access
|
61
|
+
remote_cmd(ssh, "tar -zxf #{@tarball} -C #{@recipes_path}")
|
62
|
+
# # cleanup both remote and local
|
63
|
+
remote_cmd(ssh, "rm -f /tmp/baker/recipes.tgz")
|
64
|
+
local_cmd("rm -f /tmp/recipes.tgz")
|
54
65
|
end
|
55
|
-
|
66
|
+
|
56
67
|
def run_chef(ssh)
|
57
|
-
log "running chef recipes on #{@host}..."
|
58
|
-
chef_cmd = "chef-solo -c
|
59
|
-
log "
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
def log(msg)
|
65
|
-
puts msg
|
68
|
+
log "*** running chef recipes on #{@host}..."
|
69
|
+
chef_cmd = "chef-solo -c /tmp/baker/recipes/config/solo.rb -j /tmp/baker/recipes/config/dna.json > /var/log/baker-chef-server.log 2>&1"
|
70
|
+
log "CHEF_CMD : #{chef_cmd}"
|
71
|
+
remote_cmd(ssh, chef_cmd)
|
66
72
|
end
|
67
|
-
def debug(msg)
|
68
|
-
puts msg if @debug
|
69
|
-
end
|
70
|
-
def bash_exec(command)
|
71
|
-
`#{command}`
|
72
|
-
end
|
73
|
-
def ssh_exec(ssh, command)
|
74
73
|
|
75
|
-
|
76
|
-
|
74
|
+
private
|
75
|
+
def log(msg)
|
76
|
+
puts(msg)
|
77
|
+
@logger.info(msg)
|
77
78
|
end
|
78
79
|
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
def local_cmd(command)
|
81
|
+
puts "local cmd: #{command}"
|
82
|
+
`#{command}`
|
82
83
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
|
85
|
+
def remote_cmd(ssh, command)
|
86
|
+
puts "remote cmd: #{command}"
|
87
|
+
stdout = ""
|
88
|
+
ssh.exec!(command) do |channel, stream, data|
|
89
|
+
stdout << data if stream == :stdout
|
90
|
+
end
|
91
|
+
output = stdout
|
92
|
+
|
93
|
+
if output
|
94
|
+
output = output.split("\n").join("\n ")
|
95
|
+
puts "remote output: #{output}"
|
96
|
+
end
|
97
|
+
|
98
|
+
output
|
88
99
|
end
|
89
100
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
101
|
+
# TODO: mess with this later so try to catch the stderr when chef-solo run fails
|
102
|
+
# def remote_cmd(ssh, command)
|
103
|
+
# puts "remote cmd: #{command}"
|
104
|
+
# ssh.open_channel do |channel|
|
105
|
+
# channel.exec(command) do |ch, success|
|
106
|
+
# unless success
|
107
|
+
# abort "FAILED: couldn't execute command (ssh.channel.exec failure) #{command}"
|
108
|
+
# end
|
109
|
+
# # stdout
|
110
|
+
# channel.on_data do |ch, data| # stdout
|
111
|
+
# print data
|
112
|
+
# end
|
113
|
+
# # stderr
|
114
|
+
# channel.on_extended_data do |ch, type, data|
|
115
|
+
# next unless type == 1 # only handle stderr
|
116
|
+
# $stderr.print data
|
117
|
+
# end
|
118
|
+
# channel.on_request("exit-status") do |ch, data|
|
119
|
+
# exit_code = data.read_long
|
120
|
+
# if exit_code > 0
|
121
|
+
# puts "ERROR: exit code #{exit_code}"
|
122
|
+
# else
|
123
|
+
# puts "success"
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
# channel.on_request("exit-signal") do |ch, data|
|
127
|
+
# puts "SIGNAL: #{data.read_long}"
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
# end
|
131
|
+
# end
|
132
|
+
|
133
|
+
end
|
data/test/baker_test.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/spec'
|
3
|
+
require 'mocha'
|
4
|
+
require File.dirname(__FILE__)+"/../lib/baker"
|
5
|
+
|
6
|
+
context "Baker" do
|
7
|
+
specify "should check that its running from a cookbooks project" do
|
8
|
+
@root = File.dirname(__FILE__)+"/fixtures/cookbooks-empty"
|
9
|
+
@baker = Baker.new(:host => "test_server", :root => @root)
|
10
|
+
File.directory?(@root+"/cookbooks").should == false
|
11
|
+
should.raise(NotCookbookProject) { @baker.run }
|
12
|
+
end
|
13
|
+
|
14
|
+
# specify "should upload baker configs and recipes" do
|
15
|
+
# Net::SSH.stubs(:configuration_for).returns({})
|
16
|
+
# Net::SSH.expects(:start).with(@server.host, "default-user", @options).returns(success = Object.new)
|
17
|
+
#
|
18
|
+
# Net::SSH.start(@host, @user) do |ssh|
|
19
|
+
# upload_chef_configs(ssh)
|
20
|
+
# upload_recipes(ssh)
|
21
|
+
# run_chef(ssh)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# Logfile created on Sun Jul 11 19:38:14 -0700 2010 by logger.rb/22283
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"ec2": false,
|
3
|
+
"user":"root",
|
4
|
+
"packages":[],
|
5
|
+
"gems":[],
|
6
|
+
"users":[],
|
7
|
+
"environment": {"name":"staging"},
|
8
|
+
"packages":{},
|
9
|
+
"gems_to_install":[
|
10
|
+
{"name": "sinatra", "version": "0.9.4"}
|
11
|
+
],
|
12
|
+
"recipes":[
|
13
|
+
"example_recipe1",
|
14
|
+
"example_recipe1"
|
15
|
+
]
|
16
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
Chef::Log.info("example recipe 1 ran")
|
@@ -0,0 +1 @@
|
|
1
|
+
Chef::Log.info("example recipe 2 ran")
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: baker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Tung Nguyen
|
@@ -14,24 +15,33 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
+
date: 2011-01-12 00:00:00 -08:00
|
18
19
|
default_executable:
|
19
20
|
dependencies: []
|
20
21
|
|
21
22
|
description:
|
22
23
|
email: tongueroo@gmail.com
|
23
24
|
executables:
|
24
|
-
-
|
25
|
+
- bake
|
25
26
|
extensions: []
|
26
27
|
|
27
28
|
extra_rdoc_files:
|
28
29
|
- README.markdown
|
29
30
|
files:
|
30
|
-
-
|
31
|
+
- baker.log
|
32
|
+
- bin/bake
|
31
33
|
- gemspec.rb
|
32
34
|
- lib/baker.rb
|
33
35
|
- Rakefile
|
34
36
|
- README.markdown
|
37
|
+
- test/baker_test.rb
|
38
|
+
- test/fixtures/cookbooks-empty/baker.log
|
39
|
+
- test/fixtures/cookbooks-valid/baker.log
|
40
|
+
- test/fixtures/cookbooks-valid/config/baker/node.json
|
41
|
+
- test/fixtures/cookbooks-valid/config/baker/solo.rb
|
42
|
+
- test/fixtures/cookbooks-valid/cookbooks/example_recipe1/recipes/default.rb
|
43
|
+
- test/fixtures/cookbooks-valid/cookbooks/example_recipe2/recipes/default.rb
|
44
|
+
- TODO
|
35
45
|
has_rdoc: true
|
36
46
|
homepage: http://github.com/tongueroo/baker
|
37
47
|
licenses: []
|
@@ -42,23 +52,27 @@ rdoc_options: []
|
|
42
52
|
require_paths:
|
43
53
|
- lib
|
44
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
45
56
|
requirements:
|
46
57
|
- - ">="
|
47
58
|
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
48
60
|
segments:
|
49
61
|
- 0
|
50
62
|
version: "0"
|
51
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
52
65
|
requirements:
|
53
66
|
- - ">="
|
54
67
|
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
55
69
|
segments:
|
56
70
|
- 0
|
57
71
|
version: "0"
|
58
72
|
requirements: []
|
59
73
|
|
60
74
|
rubyforge_project:
|
61
|
-
rubygems_version: 1.3.
|
75
|
+
rubygems_version: 1.3.7
|
62
76
|
signing_key:
|
63
77
|
specification_version: 3
|
64
78
|
summary: A simple way to run chef recipes
|