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 CHANGED
@@ -1,18 +1,59 @@
1
- runchef
1
+ Baker
2
2
  =======
3
3
 
4
- A Simple Way to Run Chef recipes
4
+ A simple way to run chef recipes on one server.
5
5
 
6
6
  Install
7
7
  -------
8
8
 
9
9
  <pre>
10
- sudo gem install baker --source http://gemcutter.org --no-ri --no-rdoc
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
- baker <server>
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.dirname(__FILE__),'..','lib','baker')
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 += [GEM_NAME]
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.0"
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(host)
8
- new(host)
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 initialize(host, user = nil)
12
- log "start running chef recipes on #{host}"
13
- @debug = true
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 check
39
+
40
+ def validate_cookbook_project
26
41
  if !File.exist?('cookbooks')
27
- raise "not in chef cookbooks project need to be in one"
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
- log "uploading chef recipes to #{@host}..."
43
- @file_cache_path = "/tmp/chef-solo"
44
- @recipes_path = "/tmp/chef-solo/recipes"
45
- # create
46
- bash_exec("tar czf recipes.tgz .")
47
- # upload
48
- bash_exec("scp recipes.tgz #{@host}:")
49
- # move
50
- ssh_exec(ssh, "rm -rf #{@recipes_path}")
51
- ssh_exec(ssh, "mkdir -p #{@recipes_path}")
52
- ssh_exec(ssh, "tar -zxf recipes.tgz -C #{@recipes_path}")
53
- bash_exec("rm recipes.tgz")
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 ~/chef-config/solo.rb -j ~/chef-config/dna.json"
59
- log "chef_cmd : #{chef_cmd}"
60
- ssh_exec(ssh, chef_cmd)
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
- unless ARGV.empty?
76
- debug "Executing command: #{command}"
74
+ private
75
+ def log(msg)
76
+ puts(msg)
77
+ @logger.info(msg)
77
78
  end
78
79
 
79
- stdout = ""
80
- ssh.exec!(command) do |channel, stream, data|
81
- stdout << data if stream == :stdout
80
+ def local_cmd(command)
81
+ puts "local cmd: #{command}"
82
+ `#{command}`
82
83
  end
83
- output = stdout
84
-
85
- if output and @debug
86
- output = output.split("\n").join("\n ")
87
- debug " ssh output: #{output}"
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
- output
91
- end
92
- end
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
@@ -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,3 @@
1
+ # Logfile created on Tue Jan 11 22:54:01 -0800 2011 by logger.rb/22285
2
+ I, [2011-01-11T22:54:01.081234 #15321] INFO -- : start running chef recipes on usolo.loc
3
+ I, [2011-01-11T22:55:43.655179 #15337] INFO -- : start running chef recipes on usolo.loc
@@ -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,2 @@
1
+ file_cache_path "/tmp/chef-solo"
2
+ cookbook_path "/tmp/chef-solo/recipes/cookbooks"
@@ -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
- - 0
9
- version: 0.1.0
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: 2010-03-19 00:00:00 -07:00
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
- - baker
25
+ - bake
25
26
  extensions: []
26
27
 
27
28
  extra_rdoc_files:
28
29
  - README.markdown
29
30
  files:
30
- - bin/baker
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.6
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