caterer 0.5.0 → 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.
@@ -5,12 +5,15 @@ module Caterer
5
5
  class Image < Base
6
6
 
7
7
  def call(env)
8
- # check to ensure the image exists
9
- image = env[:config].images[env[:image]]
10
8
 
11
- if not image
12
- env[:ui].error "image ':#{env[:image]}' is not defined"
13
- return
9
+ if env[:image]
10
+ # check to ensure the image exists
11
+ image = env[:config].images[env[:image]]
12
+
13
+ if not image
14
+ env[:ui].error "image ':#{env[:image]}' is not defined"
15
+ return
16
+ end
14
17
  end
15
18
 
16
19
  @app.call(env)
@@ -5,19 +5,22 @@ module Caterer
5
5
  class Provisioner < Base
6
6
 
7
7
  def call(env)
8
- provisioner = env[:config].images[env[:image]].provisioner
9
8
 
10
- if not provisioner
11
- env[:ui].error "provisioner for image ':#{env[:image]}' is not defined"
12
- return
13
- end
14
-
15
- if errors = provisioner.errors
16
- errors.each do |key, val|
17
- env[:ui].error "image :#{env[:image]} provisioner error -> #{key} #{val}"
9
+ if env[:image]
10
+ provisioner = env[:config].images[env[:image]].provisioner
11
+
12
+ if not provisioner
13
+ env[:ui].error "provisioner for image ':#{env[:image]}' is not defined"
14
+ return
18
15
  end
19
- return
20
- end
16
+
17
+ if errors = provisioner.errors
18
+ errors.each do |key, val|
19
+ env[:ui].error "image :#{env[:image]} provisioner error -> #{key} #{val}"
20
+ end
21
+ return
22
+ end
23
+ end
21
24
 
22
25
  @app.call(env)
23
26
  end
@@ -1,13 +1,19 @@
1
- require 'active_support/inflector'
2
-
3
1
  module Caterer
4
2
  module Action
5
3
  module Provisioner
6
4
  class Base < Action::Base
7
5
 
8
6
  def provisioner(env)
9
- config = env[:config].images[env[:image]].provisioner
10
- "Caterer::Provisioner::#{config.name.to_s.classify}".constantize.new(env[:server], config)
7
+
8
+ if image = env[:image]
9
+ env[:config].images[image].provisioner
10
+ else
11
+ Caterer.provisioners.get(env[:engine] || default_engine).new
12
+ end
13
+ end
14
+
15
+ def default_engine
16
+ Caterer.config.default_provisioner
11
17
  end
12
18
 
13
19
  end
@@ -4,7 +4,7 @@ module Caterer
4
4
  class Bootstrap < Base
5
5
 
6
6
  def call(env)
7
- provisioner(env).bootstrap
7
+ provisioner(env).bootstrap(env[:server])
8
8
  @app.call(env)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module Caterer
4
4
  class Cleanup < Base
5
5
 
6
6
  def call(env)
7
- provisioner(env).cleanup
7
+ provisioner(env).cleanup(env[:server])
8
8
  @app.call(env)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module Caterer
4
4
  class Install < Base
5
5
 
6
6
  def call(env)
7
- provisioner(env).install
7
+ provisioner(env).install(env[:server])
8
8
  @app.call(env)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module Caterer
4
4
  class Prepare < Base
5
5
 
6
6
  def call(env)
7
- provisioner(env).prepare
7
+ provisioner(env).prepare(env[:server])
8
8
  @app.call(env)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module Caterer
4
4
  class Provision < Base
5
5
 
6
6
  def call(env)
7
- provisioner(env).provision
7
+ provisioner(env).provision(env[:server])
8
8
  @app.call(env)
9
9
  end
10
10
 
@@ -6,7 +6,7 @@ module Caterer
6
6
 
7
7
  def call(env)
8
8
 
9
- if not provisioner(env).bootstrapped?
9
+ if not provisioner(env).bootstrapped?(env[:server])
10
10
  env[:ui].error "Server not bootstrapped, cannot continue"
11
11
  return
12
12
  end
@@ -0,0 +1,24 @@
1
+ module Caterer
2
+ module Action
3
+ module Provisioner
4
+ module Validate
5
+ class Engine < Base
6
+
7
+ def call(env)
8
+
9
+ if env[:engine]
10
+ if not Caterer.provisioners.get(env[:engine])
11
+ env[:ui].error "Unsupported provision engine #{env[:engine]}"
12
+ return
13
+ end
14
+ end
15
+
16
+ @app.call(env)
17
+
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -3,6 +3,7 @@ module Caterer
3
3
  module Provisioner
4
4
  module Validate
5
5
  autoload :Bootstrapped, 'caterer/action/provisioner/validate/bootstrapped'
6
+ autoload :Engine, 'caterer/action/provisioner/validate/engine'
6
7
  end
7
8
  end
8
9
  end
@@ -3,6 +3,7 @@ Caterer.actions.register(:validate) do
3
3
  Vli::Action::Builder.new do
4
4
  use Caterer::Action::Config::Validate::Image
5
5
  use Caterer::Action::Config::Validate::Provisioner
6
+ use Caterer::Action::Provisioner::Validate::Engine
6
7
  use Caterer::Action::Server::Validate::SSH
7
8
  use Caterer::Action::Server::Validate::Unlocked
8
9
  end
@@ -60,7 +60,7 @@ module Caterer
60
60
  argv.first.split(",").each do |host|
61
61
 
62
62
  if group = @env.config.groups[host.to_sym]
63
- group.members.each do |member|
63
+ group.members.each do |key, member|
64
64
  servers << init_server(group, member, options)
65
65
  end
66
66
  else
@@ -99,6 +99,10 @@ module Caterer
99
99
  opts[:images] = image_list(options) || member.images || group.images
100
100
  opts[:key] = options[:key] || member.key || group.key
101
101
 
102
+ if engine = options[:engine]
103
+ opts[:engine] = engine.to_sym
104
+ end
105
+
102
106
  opts[:data] = begin
103
107
  data = nil
104
108
  if json = options[:data]
@@ -3,10 +3,12 @@ module Caterer
3
3
  class Base
4
4
 
5
5
  attr_reader :images, :groups
6
+ attr_accessor :default_provisioner
6
7
 
7
8
  def initialize
8
9
  @images = {}
9
10
  @groups = {}
11
+ @default_provisioner = :chef_solo
10
12
  end
11
13
 
12
14
  def image(name)
@@ -1,5 +1,3 @@
1
- require 'active_support/inflector'
2
-
3
1
  module Caterer
4
2
  module Config
5
3
  class Image
@@ -11,7 +9,9 @@ module Caterer
11
9
  end
12
10
 
13
11
  def provision(type)
14
- @provisioner = "Caterer::Config::Provision::#{type.to_s.classify}".constantize.new(type)
12
+ provisioner_klass = Caterer.provisioners.get(type)
13
+ raise ":#{type} is not a valida provisioner" if not provisioner_klass
14
+ @provisioner = provisioner_klass.new
15
15
  yield @provisioner if block_given?
16
16
  end
17
17
 
@@ -2,19 +2,16 @@ module Caterer
2
2
  module Provisioner
3
3
  class Base
4
4
 
5
- attr_reader :server, :config
5
+ # config dsl
6
+ def errors; end
6
7
 
7
- def initialize(server, config=nil)
8
- @server = server
9
- @config = config
10
- end
11
-
12
- def bootstrap; end
13
- def bootstrapped?; true; end
14
- def cleanup; end
15
- def install; end
16
- def prepare; end
17
- def provision; end
8
+ # provision dsl
9
+ def bootstrap(server); end
10
+ def bootstrapped?(server); true; end
11
+ def cleanup(server); end
12
+ def install(server); end
13
+ def prepare(server); end
14
+ def provision(server); end
18
15
 
19
16
  end
20
17
  end
@@ -8,7 +8,76 @@ module Caterer
8
8
  module Provisioner
9
9
  class ChefSolo < Base
10
10
 
11
- def bootstrap
11
+ attr_reader :run_list
12
+ attr_accessor :json, :cookbooks_path, :roles_path
13
+ attr_accessor :data_bags_path, :bootstrap_scripts
14
+
15
+ def initialize
16
+ @run_list = []
17
+ @json = {}
18
+ @cookbooks_path = ['cookbooks']
19
+ @roles_path = ['roles']
20
+ @data_bags_path = ['data_bags']
21
+ @bootstrap_scripts = []
22
+ end
23
+
24
+ # config DSL
25
+
26
+ def add_recipe(recipe)
27
+ @run_list << "recipe[#{recipe}]"
28
+ end
29
+
30
+ def add_role(role)
31
+ @run_list << "role[#{role}]"
32
+ end
33
+
34
+ # I don't like this at all, but it seems to make the best Caterfile workflow
35
+ def add_image(image)
36
+ image = Caterer.config.images[image]
37
+ raise "Unknown image :#{image}" if not image
38
+
39
+ provisioner = image.provisioner
40
+ raise "No provisioner for :#{image}" if not provisioner
41
+
42
+ if not provisioner.class == self.class
43
+ raise "add_image incompatibility: #{provisioner.class} != #{self.class}"
44
+ end
45
+
46
+ @run_list += provisioner.run_list
47
+ @bootstrap_scripts += provisioner.bootstrap_scripts
48
+ end
49
+
50
+ def add_bootstrap(script)
51
+ @bootstrap_scripts << script
52
+ end
53
+
54
+ def errors
55
+ errors = {}
56
+
57
+ if not @run_list.length > 0
58
+ errors[:run_list] = "is empty"
59
+ end
60
+
61
+ if not @cookbooks_path.is_a? Array
62
+ errors[:cookbooks_path] = "must be an array"
63
+ end
64
+
65
+ if not @roles_path.is_a? Array
66
+ errors[:roles_path] = "must be an array"
67
+ end
68
+
69
+ if not @data_bags_path.is_a? Array
70
+ errors[:data_bags_path] = "must be an array"
71
+ end
72
+
73
+ if errors.length > 0
74
+ errors
75
+ end
76
+ end
77
+
78
+ # provision engine
79
+
80
+ def bootstrap(server)
12
81
 
13
82
  # validate
14
83
  with_bootstrap_scripts do |script, count|
@@ -24,10 +93,10 @@ module Caterer
24
93
  with_bootstrap_scripts do |script, count|
25
94
 
26
95
  server.ui.info "Uploading #{script}..."
27
- server.ssh.upload script, "#{bootstrap_path}-#{count}"
96
+ server.ssh.upload script, "#{target_bootstrap_path}-#{count}"
28
97
 
29
- server.ssh.sudo "chown #{server.username} #{bootstrap_path}-#{count}", :stream => true
30
- server.ssh.sudo "chmod +x #{bootstrap_path}-#{count}", :stream => true
98
+ server.ssh.sudo "chown #{server.username} #{target_bootstrap_path}-#{count}", :stream => true
99
+ server.ssh.sudo "chmod +x #{target_bootstrap_path}-#{count}", :stream => true
31
100
 
32
101
  end
33
102
 
@@ -35,189 +104,162 @@ module Caterer
35
104
  with_bootstrap_scripts do |script, count|
36
105
 
37
106
  server.ui.info "Running #{script}..."
38
- server.ssh.sudo "#{bootstrap_path}-#{count}", :stream => true
107
+ server.ssh.sudo "#{target_bootstrap_path}-#{count}", :stream => true
39
108
 
40
109
  end
41
110
 
42
111
  end
43
112
 
44
- def bootstrapped?
113
+ def bootstrapped?(server)
45
114
  res = server.ssh.sudo "command -v chef-solo &>/dev/null"
46
115
  res == 0 ? true : false
47
116
  end
48
117
 
49
- def prepare
118
+ def prepare(server)
50
119
  # create base dir
51
- server.ssh.sudo "mkdir -p #{base_path}", :stream => true
52
- server.ssh.sudo "chown -R #{server.username} #{base_path}", :stream => true
120
+ server.ssh.sudo "mkdir -p #{target_base_path}", :stream => true
121
+ server.ssh.sudo "chown -R #{server.username} #{target_base_path}", :stream => true
53
122
  end
54
123
 
55
- def install
124
+ def install(server)
56
125
  server.ui.info "Preparing installation..."
57
126
 
58
127
  # upload
59
- server.ssh.upload install_script, "#{install_path}"
128
+ server.ssh.upload install_script, "#{target_install_path}"
60
129
 
61
130
  # set permissions
62
- server.ssh.sudo "chown #{server.username} #{install_path}", :stream => true
63
- server.ssh.sudo "chmod +x #{install_path}", :stream => true
131
+ server.ssh.sudo "chown #{server.username} #{target_install_path}", :stream => true
132
+ server.ssh.sudo "chmod +x #{target_install_path}", :stream => true
64
133
 
65
134
  # run
66
135
  server.ui.info "Installing chef-solo..."
67
- server.ssh.sudo "#{install_path}", :stream => true
136
+ server.ssh.sudo "#{target_install_path}", :stream => true
68
137
  end
69
138
 
70
- def provision
139
+ def provision(server)
71
140
 
72
141
  # create cookbooks directory
73
- server.ssh.sudo "mkdir -p #{cookbooks_path}", :stream => true
74
- server.ssh.sudo "chown -R #{server.username} #{cookbooks_path}", :stream => true
142
+ server.ssh.sudo "mkdir -p #{target_cookbooks_path}", :stream => true
143
+ server.ssh.sudo "chown -R #{server.username} #{target_cookbooks_path}", :stream => true
75
144
 
76
145
  # sync cookbooks
77
146
  server.ui.info "Syncing cookbooks..."
78
- config.cookbooks_path.each do |path|
79
- upload_directory path, "#{cookbooks_path}/#{Digest::MD5.hexdigest(path)}"
147
+ cookbooks_path.each do |path|
148
+ server.upload_directory path, "#{target_cookbooks_path}/#{Digest::MD5.hexdigest(path)}"
80
149
  end
81
150
 
82
151
  # create roles directory
83
- server.ssh.sudo "mkdir -p #{roles_path}", :stream => true
84
- server.ssh.sudo "chown -R #{server.username} #{roles_path}", :stream => true
152
+ server.ssh.sudo "mkdir -p #{target_roles_path}", :stream => true
153
+ server.ssh.sudo "chown -R #{server.username} #{target_roles_path}", :stream => true
85
154
 
86
155
  # sync roles
87
156
  server.ui.info "Syncing roles..."
88
- config.roles_path.each do |path|
89
- upload_directory path, roles_path
157
+ roles_path.each do |path|
158
+ server.upload_directory path, target_roles_path
90
159
  end
91
160
 
92
161
  # create data_bags directory
93
- server.ssh.sudo "mkdir -p #{data_bags_path}", :stream => true
94
- server.ssh.sudo "chown -R #{server.username} #{data_bags_path}", :stream => true
162
+ server.ssh.sudo "mkdir -p #{target_data_bags_path}", :stream => true
163
+ server.ssh.sudo "chown -R #{server.username} #{target_data_bags_path}", :stream => true
95
164
 
96
165
  # sync databags
97
166
  server.ui.info "Syncing data bags..."
98
- config.data_bags_path.each do |path|
99
- upload_directory path, data_bags_path
167
+ data_bags_path.each do |path|
168
+ server.upload_directory path, target_data_bags_path
100
169
  end
101
170
 
102
171
  # create solo.rb
103
172
  server.ui.info "Generating solo.rb..."
104
- server.ssh.upload(StringIO.new(solo_content), solo_path)
173
+ server.ssh.upload(StringIO.new(solo_content(server)), target_solo_path)
105
174
 
106
175
  # create json
107
176
  server.ui.info "Generating json config..."
108
- server.ssh.upload(StringIO.new(json_config), json_config_path)
177
+ server.ssh.upload(StringIO.new(json_config(config_data.merge(server.data))), target_json_config_path)
109
178
 
110
179
  # set permissions on everything
111
- server.ssh.sudo "chown -R #{server.username} #{base_path}", :stream => true
180
+ server.ssh.sudo "chown -R #{server.username} #{target_base_path}", :stream => true
112
181
 
113
182
  # run
114
183
  server.ui.info "Running chef-solo..."
115
184
  server.ssh.sudo command_string, :stream => true
116
185
  end
117
186
 
118
- def cleanup
187
+ def cleanup(server)
119
188
  server.ui.info "Cleaning up..."
120
189
 
121
190
  # installer
122
- server.ssh.sudo "rm -f #{install_path}", :stream => true
191
+ server.ssh.sudo "rm -f #{target_install_path}", :stream => true
123
192
 
124
193
  # bootstrap scripts
125
- server.ssh.sudo "rm -f #{bootstrap_path}*", :stream => true
194
+ server.ssh.sudo "rm -f #{target_bootstrap_path}*", :stream => true
126
195
 
127
196
  # solo.rb
128
- server.ssh.sudo "rm -f #{solo_path}", :stream => true
197
+ server.ssh.sudo "rm -f #{target_solo_path}", :stream => true
129
198
 
130
199
  # json
131
- server.ssh.sudo "rm -f #{json_config_path}", :stream => true
200
+ server.ssh.sudo "rm -f #{target_json_config_path}", :stream => true
132
201
 
133
202
  # for now, leave cookbooks, roles, and data bags for faster provisioning
134
203
  end
135
204
 
136
205
  protected
137
206
 
138
- def upload_directory(from, to)
139
- if File.exists? from
140
- if @server.can_rsync?
141
- from += "/" if not from.match /\/$/
142
- res = @server.rsync.sync(from, to)
143
- server.ui.error "rsync was unsuccessful" if res != 0
144
- else
145
- server.ui.warn "Rsync unavailable, falling back to scp (slower)..."
146
- unique = Digest::MD5.hexdigest(from)
147
- server.ssh.sudo "rm -rf #{to}/*", :stream => true
148
- server.ssh.sudo "mkdir -p #{to}/#{unique}", :stream => true
149
- server.ssh.sudo "chown -R #{server.username} #{to}/#{unique}", :stream => true
150
- server.ssh.upload from, "#{to}/#{unique}"
151
- server.ssh.sudo "mv #{to}/#{unique}/**/* #{to}/", :stream => true
152
- server.ssh.sudo "rm -rf #{to}/#{unique}", :stream => true
153
- end
154
- end
155
- end
156
-
157
207
  def with_bootstrap_scripts
158
- config.bootstrap_scripts.each_with_index do |script, index|
208
+ bootstrap_scripts.each_with_index do |script, index|
159
209
  yield script, index if block_given?
160
210
  end
161
211
  end
162
212
 
163
- def bootstrap_scripts
164
- config.bootstrap_scripts
165
- end
166
-
167
- def base_path
213
+ def target_base_path
168
214
  "/tmp/cater-chef-solo"
169
215
  end
170
216
 
171
- def install_path
172
- "#{base_path}/install"
173
- end
174
-
175
- def bootstrap_path
176
- "#{base_path}/bootstrap"
217
+ def target_install_path
218
+ "#{target_base_path}/install"
177
219
  end
178
220
 
179
- def cookbooks_path
180
- "#{base_path}/cookbooks"
221
+ def target_bootstrap_path
222
+ "#{target_base_path}/bootstrap"
181
223
  end
182
224
 
183
- def roles_path
184
- "#{base_path}/roles"
225
+ def target_cookbooks_path
226
+ "#{target_base_path}/cookbooks"
185
227
  end
186
228
 
187
- def data_bags_path
188
- "#{base_path}/data_bags"
229
+ def target_roles_path
230
+ "#{target_base_path}/roles"
189
231
  end
190
232
 
191
- def solo_path
192
- "#{base_path}/solo.rb"
233
+ def target_data_bags_path
234
+ "#{target_base_path}/data_bags"
193
235
  end
194
236
 
195
- def json_config_path
196
- "#{base_path}/config.json"
237
+ def target_solo_path
238
+ "#{target_base_path}/solo.rb"
197
239
  end
198
240
 
199
- def config_bootstrap
200
- config.bootstrap_script
241
+ def target_json_config_path
242
+ "#{target_base_path}/config.json"
201
243
  end
202
244
 
203
245
  def install_script
204
246
  File.expand_path("../../../templates/provisioner/chef_solo/bootstrap.sh", __FILE__)
205
247
  end
206
248
 
207
- def solo_content
208
- Tilt.new(File.expand_path('../../../templates/provisioner/chef_solo/solo.erb', __FILE__)).render(self)
249
+ def solo_content(server)
250
+ Tilt.new(File.expand_path('../../../templates/provisioner/chef_solo/solo.erb', __FILE__)).render(self, {:server => server})
209
251
  end
210
252
 
211
- def json_config
212
- MultiJson.dump(config_data)
253
+ def json_config(data)
254
+ MultiJson.dump(data)
213
255
  end
214
256
 
215
257
  def config_data
216
- {:run_list => config.run_list}.merge(config.json).merge(server.data)
258
+ {:run_list => run_list}.merge(json)
217
259
  end
218
260
 
219
261
  def command_string
220
- "chef-solo -c #{solo_path} -j #{json_config_path}"
262
+ "chef-solo -c #{target_solo_path} -j #{target_json_config_path}"
221
263
  end
222
264
 
223
265
  end
@@ -0,0 +1 @@
1
+ Caterer.provisioners.register(:chef_solo) { Caterer::Provisioner::ChefSolo }
@@ -15,6 +15,7 @@ module Caterer
15
15
  @key = opts[:key]
16
16
  @images = opts[:images] || []
17
17
  @data = opts[:data] || {}
18
+ @engine = opts[:engine]
18
19
 
19
20
  @logger = Log4r::Logger.new("caterer::server")
20
21
 
@@ -22,22 +23,38 @@ module Caterer
22
23
  end
23
24
 
24
25
  def bootstrap(opts={})
25
- if @images.length == 0
26
- ui.error "image list is empty, nothing to do"
27
- end
28
- @images.each do |i|
29
- ui.info "*** Bootstrapping image: #{i} ***"
30
- run_action(:bootstrap, opts.merge({:image => i}))
26
+ if @images.length > 0
27
+ @images.each do |i|
28
+ ui.info "*** Bootstrapping image: #{i} ***"
29
+ run_action(:bootstrap, opts.merge({:image => i}))
30
+ end
31
+ else
32
+ ui.info "*** Bootstrapping ***"
33
+ run_action(:bootstrap, opts.merge({:engine => @engine}))
31
34
  end
32
35
  end
33
36
 
34
37
  def provision(opts={})
35
- if @images.length == 0
36
- ui.error "image list is empty, nothing to do"
38
+ if @images.length > 0
39
+ @images.each do |i|
40
+ ui.info "*** Provisioning image: #{i} ***"
41
+ run_action(:provision, opts.merge({:image => i}))
42
+ end
43
+ else
44
+ ui.info "*** Provisioning ***"
45
+ run_action(:provision, opts.merge({:engine => @engine}))
37
46
  end
38
- @images.each do |i|
39
- ui.info "*** Provisioning image: #{i} ***"
40
- run_action(:provision, opts.merge({:image => i}))
47
+ end
48
+
49
+ def up(opts={})
50
+ if @images.length > 0
51
+ @images.each do |i|
52
+ ui.info "*** Up'ing image: #{i} ***"
53
+ run_action(:up, opts.merge({:image => i}))
54
+ end
55
+ else
56
+ ui.info "*** Up'ing ***"
57
+ run_action(:up, opts.merge({:engine => @engine}))
41
58
  end
42
59
  end
43
60
 
@@ -45,34 +62,14 @@ module Caterer
45
62
  run_action(:reboot, opts)
46
63
  end
47
64
 
48
- def up(opts={})
49
- if @images.length == 0
50
- ui.error "image list is empty, nothing to do"
51
- end
52
- @images.each do |i|
53
- ui.info "*** Up'ing image: #{i} ***"
54
- run_action(:up, opts.merge({:image => i}))
55
- end
56
- end
57
-
58
65
  def lock(opts={})
59
- if @images.length == 0
60
- ui.error "image list is empty, nothing to do"
61
- end
62
- @images.each do |i|
63
- ui.info "*** Locking image: #{i} ***"
64
- run_action(:lock, opts.merge({:image => i}))
65
- end
66
+ ui.info "*** Locking ***"
67
+ run_action(:lock, opts)
66
68
  end
67
69
 
68
70
  def unlock(opts={})
69
- if @images.length == 0
70
- ui.error "image list is empty, nothing to do"
71
- end
72
- @images.each do |i|
73
- ui.info "*** Unlocking image: #{i} ***"
74
- run_action(:unlock, opts.merge({:image => i}))
75
- end
71
+ ui.info "*** Unlocking ***"
72
+ run_action(:unlock, opts)
76
73
  end
77
74
 
78
75
  def reboot!
@@ -112,7 +109,7 @@ module Caterer
112
109
  opts[:paranoid] = false
113
110
  opts[:port] = port
114
111
  opts[:password] = password if password
115
- opts[:keys] = ["#{@key}"] if @key
112
+ opts[:keys] = [].tap {|keys| keys << @key if @key }
116
113
  end
117
114
  end
118
115
 
@@ -160,6 +157,26 @@ module Caterer
160
157
  env.action_runner.run(name, options)
161
158
  end
162
159
 
160
+ def upload_directory(from, to)
161
+ if File.exists? from
162
+ if can_rsync?
163
+ from += "/" if not from.match /\/$/
164
+ res = rsync.sync(from, to)
165
+ ui.error "rsync was unsuccessful" if res != 0
166
+ else
167
+ # yuck. Heaven help the poor soul who hath not rsync...
168
+ ui.warn "Rsync unavailable, falling back to scp (slower)..."
169
+ unique = Digest::MD5.hexdigest(from)
170
+ ssh.sudo "rm -rf #{to}/*", :stream => true
171
+ ssh.sudo "mkdir -p #{to}/#{unique}", :stream => true
172
+ ssh.sudo "chown -R #{username} #{to}/#{unique}", :stream => true
173
+ ssh.upload from, "#{to}/#{unique}"
174
+ ssh.sudo "mv #{to}/#{unique}/**/* #{to}/", :stream => true
175
+ ssh.sudo "rm -rf #{to}/#{unique}", :stream => true
176
+ end
177
+ end
178
+ end
179
+
163
180
  protected
164
181
 
165
182
  def lock_path
@@ -1,3 +1,3 @@
1
1
  module Caterer
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
data/lib/caterer.rb CHANGED
@@ -23,6 +23,10 @@ module Caterer
23
23
  @commands ||= Vli::Registry.new
24
24
  end
25
25
 
26
+ def provisioners
27
+ @provisioners ||= Vli::Registry.new
28
+ end
29
+
26
30
  def config
27
31
  @config ||= Config::Base.new
28
32
  end
@@ -34,4 +38,5 @@ module Caterer
34
38
  end
35
39
 
36
40
  require 'caterer/commands'
37
- require 'caterer/actions'
41
+ require 'caterer/actions'
42
+ require 'caterer/provisioners'
@@ -1,5 +1,5 @@
1
- file_cache_path "<%= base_path %>"
1
+ file_cache_path "<%= target_base_path %>"
2
2
  node_name "<%= server.host %>"
3
- cookbook_path <%= config.cookbooks_path.map { |path| "#{cookbooks_path}/#{Digest::MD5.hexdigest(path)}" }.inspect %>
4
- data_bag_path "<%= data_bags_path %>"
5
- role_path "<%= roles_path %>"
3
+ cookbook_path <%= cookbooks_path.map { |path| "#{target_cookbooks_path}/#{Digest::MD5.hexdigest(path)}" }.inspect %>
4
+ data_bag_path "<%= target_data_bags_path %>"
5
+ role_path "<%= target_roles_path %>"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caterer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-23 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: log4r
@@ -195,6 +195,7 @@ files:
195
195
  - lib/caterer/action/provisioner/provision.rb
196
196
  - lib/caterer/action/provisioner/validate.rb
197
197
  - lib/caterer/action/provisioner/validate/bootstrapped.rb
198
+ - lib/caterer/action/provisioner/validate/engine.rb
198
199
  - lib/caterer/action/server.rb
199
200
  - lib/caterer/action/server/lock.rb
200
201
  - lib/caterer/action/server/reboot.rb
@@ -222,13 +223,12 @@ files:
222
223
  - lib/caterer/config/group.rb
223
224
  - lib/caterer/config/image.rb
224
225
  - lib/caterer/config/member.rb
225
- - lib/caterer/config/provision.rb
226
- - lib/caterer/config/provision/chef_solo.rb
227
226
  - lib/caterer/environment.rb
228
227
  - lib/caterer/logger.rb
229
228
  - lib/caterer/provisioner.rb
230
229
  - lib/caterer/provisioner/base.rb
231
230
  - lib/caterer/provisioner/chef_solo.rb
231
+ - lib/caterer/provisioners.rb
232
232
  - lib/caterer/server.rb
233
233
  - lib/caterer/util.rb
234
234
  - lib/caterer/util/ansi_escape_code_remover.rb
@@ -1,74 +0,0 @@
1
- module Caterer
2
- module Config
3
- module Provision
4
-
5
- class ChefSolo
6
-
7
- attr_reader :name, :run_list
8
- attr_accessor :json, :cookbooks_path, :roles_path, :data_bags_path, :bootstrap_scripts
9
-
10
- def initialize(name)
11
- @name = name
12
- @run_list = []
13
- @json = {}
14
- @cookbooks_path = ['cookbooks']
15
- @roles_path = ['roles']
16
- @data_bags_path = ['data_bags']
17
- @bootstrap_scripts = []
18
- end
19
-
20
- def add_recipe(recipe)
21
- @run_list << "recipe[#{recipe}]"
22
- end
23
-
24
- def add_role(role)
25
- @run_list << "role[#{role}]"
26
- end
27
-
28
- def add_image(image)
29
- image = Caterer.config.images[image]
30
- raise "Unknown image :#{image}" if not image
31
-
32
- provisioner = image.provisioner
33
- raise "No provisioner for :#{image}" if not provisioner
34
-
35
- if not provisioner.name == :chef_solo
36
- raise "Incompatible provisioner. Must be :#{provisioner.name}"
37
- end
38
-
39
- @run_list += provisioner.run_list
40
- @bootstrap_scripts += provisioner.bootstrap_scripts
41
- end
42
-
43
- def add_bootstrap(script)
44
- @bootstrap_scripts << script
45
- end
46
-
47
- def errors
48
- errors = {}
49
-
50
- if not @run_list.length > 0
51
- errors[:run_list] = "is empty"
52
- end
53
-
54
- if not @cookbooks_path.is_a? Array
55
- errors[:cookbooks_path] = "must be an array"
56
- end
57
-
58
- if not @roles_path.is_a? Array
59
- errors[:roles_path] = "must be an array"
60
- end
61
-
62
- if not @data_bags_path.is_a? Array
63
- errors[:data_bags_path] = "must be an array"
64
- end
65
-
66
- if errors.length > 0
67
- errors
68
- end
69
- end
70
-
71
- end
72
- end
73
- end
74
- end
@@ -1,7 +0,0 @@
1
- module Caterer
2
- module Config
3
- module Provision
4
- autoload :ChefSolo, 'caterer/config/provision/chef_solo'
5
- end
6
- end
7
- end