knife-stackbuilder 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +115 -0
- data/Rakefile +42 -0
- data/bin/stackbuilder_debug +0 -0
- data/lib/chef/knife/stack_build.rb +114 -0
- data/lib/chef/knife/stack_delete.rb +50 -0
- data/lib/chef/knife/stack_initialize_repo.rb +62 -0
- data/lib/chef/knife/stack_upload_certificates.rb +38 -0
- data/lib/chef/knife/stack_upload_cookbooks.rb +49 -0
- data/lib/chef/knife/stack_upload_data_bags.rb +36 -0
- data/lib/chef/knife/stack_upload_environments.rb +31 -0
- data/lib/chef/knife/stack_upload_repo.rb +39 -0
- data/lib/chef/knife/stack_upload_roles.rb +33 -0
- data/lib/chef/knife/stackbuilder_base.rb +32 -0
- data/lib/stackbuilder/chef/repo.rb +442 -0
- data/lib/stackbuilder/chef/stack_generic_node.rb +67 -0
- data/lib/stackbuilder/chef/stack_node_manager.rb +251 -0
- data/lib/stackbuilder/chef/stack_provider.rb +77 -0
- data/lib/stackbuilder/chef/stack_vagrant_node.rb +72 -0
- data/lib/stackbuilder/common/config.rb +44 -0
- data/lib/stackbuilder/common/errors.rb +18 -0
- data/lib/stackbuilder/common/helpers.rb +379 -0
- data/lib/stackbuilder/common/semaphore.rb +54 -0
- data/lib/stackbuilder/common/teeio.rb +29 -0
- data/lib/stackbuilder/stack/node_manager.rb +38 -0
- data/lib/stackbuilder/stack/node_provider.rb +21 -0
- data/lib/stackbuilder/stack/node_task.rb +424 -0
- data/lib/stackbuilder/stack/stack.rb +224 -0
- data/lib/stackbuilder/version.rb +8 -0
- data/lib/stackbuilder.rb +53 -0
- metadata +100 -0
@@ -0,0 +1,442 @@
|
|
1
|
+
# Copyright (c) 2014 Mevan Samaratunga
|
2
|
+
|
3
|
+
include StackBuilder::Common::Helpers
|
4
|
+
|
5
|
+
module StackBuilder::Chef
|
6
|
+
|
7
|
+
class RepoNotFoundError < StackBuilder::Common::StackBuilderError; end
|
8
|
+
class InvalidRepoError < StackBuilder::Common::StackBuilderError; end
|
9
|
+
|
10
|
+
class Repo
|
11
|
+
|
12
|
+
include ERB::Util
|
13
|
+
|
14
|
+
attr_reader :environments
|
15
|
+
|
16
|
+
REPO_DIRS = [
|
17
|
+
'etc',
|
18
|
+
'cookbooks',
|
19
|
+
'environments',
|
20
|
+
'secrets',
|
21
|
+
'data_bags',
|
22
|
+
'roles'
|
23
|
+
]
|
24
|
+
|
25
|
+
def initialize(path, certificates = nil, environments = nil, cookbooks = nil)
|
26
|
+
|
27
|
+
raise StackBuilder::Common::StackBuilderError, "Repo path cannot be nil." if path.nil?
|
28
|
+
|
29
|
+
@logger = StackBuilder::Common::Config.logger
|
30
|
+
@repo_path = File.expand_path(path)
|
31
|
+
|
32
|
+
if Dir.exist?(@repo_path)
|
33
|
+
|
34
|
+
REPO_DIRS.each do |folder|
|
35
|
+
|
36
|
+
next if [ 'cookbooks' ].include?(folder)
|
37
|
+
|
38
|
+
repo_folder = "#{@repo_path}/#{folder}"
|
39
|
+
raise InvalidRepoError,
|
40
|
+
"Repo folder #{repo_folder} is missing" unless Dir.exist?(repo_folder)
|
41
|
+
end
|
42
|
+
|
43
|
+
@environments = [ ]
|
44
|
+
Dir["#{@repo_path}/environments/**/*.rb"].each do |envfile|
|
45
|
+
@environments << envfile[/\/(\w+).rb$/, 1]
|
46
|
+
end
|
47
|
+
|
48
|
+
@logger.debug("Found stack environments #{@environments}")
|
49
|
+
else
|
50
|
+
raise RepoNotFoundError,
|
51
|
+
"Unable to load repo @ #{@repo_path}. If you need to create a repo please " +
|
52
|
+
"provide the list of environments at a minimum" if environments.nil?
|
53
|
+
|
54
|
+
REPO_DIRS.each do |folder|
|
55
|
+
system("mkdir -p #{@repo_path}/#{folder}")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Create Berksfile
|
59
|
+
@berks_cookbooks = cookbooks.nil? ? [] : cookbooks.split(',').map { |s| s.strip.split(':') }
|
60
|
+
berksfile_template = IO.read(File.expand_path('../../resources/Berksfile.erb', __FILE__))
|
61
|
+
|
62
|
+
berksfile = ERB.new(berksfile_template, nil, '-<>').result(binding)
|
63
|
+
File.open("#{@repo_path}/Berksfile", 'w+') { |f| f.write(berksfile) }
|
64
|
+
|
65
|
+
# Create Environments and Stacks
|
66
|
+
@environments = environments.split(',').map { |s| s.strip }
|
67
|
+
configfile_template = IO.read(File.expand_path('../../resources/Config.yml.erb', __FILE__))
|
68
|
+
envfile_template = IO.read(File.expand_path('../../resources/Environment.rb.erb', __FILE__))
|
69
|
+
stackfile_template = IO.read(File.expand_path('../../resources/Stack.yml.erb', __FILE__))
|
70
|
+
|
71
|
+
i = 1
|
72
|
+
@environments.each do |env_name|
|
73
|
+
|
74
|
+
@environment = env_name
|
75
|
+
|
76
|
+
configfile = ERB.new(configfile_template, nil, '-<>').result(binding)
|
77
|
+
File.open("#{@repo_path}/etc/#{env_name}.yml", 'w+') { |f| f.write(configfile) }
|
78
|
+
|
79
|
+
envfile = ERB.new(envfile_template, nil, '-<>').result(binding)
|
80
|
+
File.open("#{@repo_path}/environments/#{env_name}.rb", 'w+') { |f| f.write(envfile) }
|
81
|
+
|
82
|
+
stackfile = ERB.new(stackfile_template, nil, '-<>').result(binding)
|
83
|
+
File.open("#{@repo_path}/stack#{i}.yml", 'w+') { |f| f.write(stackfile) }
|
84
|
+
i += 1
|
85
|
+
end
|
86
|
+
@environment = nil
|
87
|
+
|
88
|
+
# Create or copy certs
|
89
|
+
create_certs(certificates) unless certificates.nil?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def upload_environments(environment = nil)
|
94
|
+
|
95
|
+
environments = (environment.nil? ? @environments : [ environment ])
|
96
|
+
knife_cmd = Chef::Knife::EnvironmentFromFile.new
|
97
|
+
|
98
|
+
environments.each do |env_name|
|
99
|
+
|
100
|
+
# TODO: Handle JSON environment files. JSON files should be processed similar to roles.
|
101
|
+
|
102
|
+
knife_cmd.name_args = [ "#{@repo_path}/environments/#{env_name}.rb" ]
|
103
|
+
run_knife(knife_cmd)
|
104
|
+
puts "Uploaded environment '#{env_name}' to '#{Chef::Config.chef_server_url}'."
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def upload_certificates(environment = nil, server = nil)
|
109
|
+
|
110
|
+
create_certs(server) unless server.nil?
|
111
|
+
|
112
|
+
knife_cmd = Chef::Knife::DataBagList.new
|
113
|
+
data_bag_list = run_knife(knife_cmd).split
|
114
|
+
|
115
|
+
# Create environment specific data bags to hold certificates
|
116
|
+
@environments.each do |env_name|
|
117
|
+
|
118
|
+
data_bag_env = 'certificates-' + env_name
|
119
|
+
unless data_bag_list.include?(data_bag_env)
|
120
|
+
knife_cmd = Chef::Knife::DataBagCreate.new
|
121
|
+
knife_cmd.name_args = data_bag_env
|
122
|
+
run_knife(knife_cmd)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
Dir["#{@repo_path}/.certs/*"].each do |server_cert_dir|
|
127
|
+
|
128
|
+
if File.directory?(server_cert_dir)
|
129
|
+
|
130
|
+
s = server_cert_dir.split('/').last
|
131
|
+
|
132
|
+
server_env_name = s[/.*_(\w+)$/, 1]
|
133
|
+
server_name = server_env_name.nil? ? s : s[/(.*)_\w+$/, 1]
|
134
|
+
|
135
|
+
if server.nil? || server==server_name
|
136
|
+
|
137
|
+
if server_env_name.nil?
|
138
|
+
|
139
|
+
environments = (environment.nil? ? @environments : [ environment ])
|
140
|
+
environments.each do |env_name|
|
141
|
+
upload_certificate(server_cert_dir, server_name, env_name)
|
142
|
+
end
|
143
|
+
|
144
|
+
elsif environment.nil? || environment==server_env_name
|
145
|
+
upload_certificate(server_cert_dir, server_name, server_env_name)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def upload_data_bags(environment = nil, data_bag = nil)
|
153
|
+
|
154
|
+
environments = (environment.nil? ? @environments : [ environment ])
|
155
|
+
|
156
|
+
knife_cmd = Chef::Knife::DataBagList.new
|
157
|
+
data_bag_list = run_knife(knife_cmd).split
|
158
|
+
|
159
|
+
Dir["#{@repo_path}/data_bags/*"].each do |data_bag_dir|
|
160
|
+
|
161
|
+
data_bag_name = data_bag_dir[/\/(\w+)$/, 1]
|
162
|
+
if data_bag.nil? || data_bag==data_bag_name
|
163
|
+
|
164
|
+
environments.each do |env_name|
|
165
|
+
|
166
|
+
data_bag_env = data_bag_name + '-' + env_name
|
167
|
+
unless data_bag_list.include?(data_bag_env)
|
168
|
+
knife_cmd = Chef::Knife::DataBagCreate.new
|
169
|
+
knife_cmd.name_args = data_bag_env
|
170
|
+
run_knife(knife_cmd)
|
171
|
+
end
|
172
|
+
|
173
|
+
env_file = "#{@repo_path}/etc/#{env_name}.yml"
|
174
|
+
env_vars = File.exist?(env_file) ?
|
175
|
+
StackBuilder::Common.load_yaml("#{@repo_path}/etc/#{env_name}.yml", ENV) : { }
|
176
|
+
|
177
|
+
secret = get_secret(env_name)
|
178
|
+
|
179
|
+
upload_data_bag_items(secret, data_bag_dir, data_bag_env, env_vars)
|
180
|
+
|
181
|
+
env_item_dir = data_bag_dir + '/' + env_name
|
182
|
+
upload_data_bag_items(secret, env_item_dir, data_bag_env, env_vars) if Dir.exist?(env_item_dir)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def upload_cookbooks(cookbook = nil, upload_options = '--no-freeze')
|
189
|
+
|
190
|
+
berksfile_path = "#{@repo_path}/Berksfile"
|
191
|
+
debug_flag = (@logger.debug? ? ' --debug' : '')
|
192
|
+
|
193
|
+
# Need to invoke Berkshelf from the shell as directly invoking it causes
|
194
|
+
# cookbook validation to throw an exception when 'Berksfile.upload' is
|
195
|
+
# called.
|
196
|
+
#
|
197
|
+
# TBD: More research needs to be done as direct invocation is preferable
|
198
|
+
|
199
|
+
cmd = ""
|
200
|
+
|
201
|
+
cmd += "export BERKSHELF_CHEF_CONFIG=#{ENV['BERKSHELF_CHEF_CONFIG']}; " \
|
202
|
+
if ENV.has_key?('BERKSHELF_CHEF_CONFIG')
|
203
|
+
|
204
|
+
if cookbook.nil?
|
205
|
+
cmd += "berks install#{debug_flag} --berksfile=#{berksfile_path}; "
|
206
|
+
cmd += "berks upload#{debug_flag} --berksfile=#{berksfile_path} #{upload_options}; "
|
207
|
+
else
|
208
|
+
cmd += "berks upload#{debug_flag} --berksfile=#{berksfile_path} #{upload_options} #{cookbook}; "
|
209
|
+
end
|
210
|
+
|
211
|
+
system(cmd)
|
212
|
+
end
|
213
|
+
|
214
|
+
def upload_roles(role = nil)
|
215
|
+
|
216
|
+
if role.nil?
|
217
|
+
Dir["#{@repo_path}/roles/*.json"].each do |role_file|
|
218
|
+
upload_role(role_file)
|
219
|
+
end
|
220
|
+
else
|
221
|
+
role_file = "#{@repo_path}/roles/#{role}.json"
|
222
|
+
upload_role(role_file) if File.exist?(role_file)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def get_secret(env_name)
|
227
|
+
|
228
|
+
secretfile = "#{@repo_path}/secrets/#{env_name}"
|
229
|
+
if File.exists?(secretfile)
|
230
|
+
key = IO.read(secretfile)
|
231
|
+
else
|
232
|
+
key = SecureRandom.uuid()
|
233
|
+
File.open("#{@repo_path}/secrets/#{env_name}", 'w+') { |f| f.write(key) }
|
234
|
+
end
|
235
|
+
|
236
|
+
key
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
def create_certs(certificates)
|
242
|
+
|
243
|
+
repo_cert_dir = @repo_path + '/.certs'
|
244
|
+
FileUtils.mkdir_p(repo_cert_dir)
|
245
|
+
|
246
|
+
if Dir.exist?(certificates)
|
247
|
+
|
248
|
+
raise CertificateError, "Unable to locate public CA certificate for server " +
|
249
|
+
"@#{certificates}/cacert.pem" unless File.exist?("#{certificates}/cacert.pem")
|
250
|
+
|
251
|
+
system("rsync -ru #{certificates}/* #{repo_cert_dir}")
|
252
|
+
else
|
253
|
+
|
254
|
+
cacert_file = "#{repo_cert_dir}/cacert.pem"
|
255
|
+
cakey_file = "#{repo_cert_dir}/cakey.pem"
|
256
|
+
|
257
|
+
if File.exist?(cacert_file) && File.exist?(cakey_file)
|
258
|
+
|
259
|
+
ca_cert = OpenSSL::X509::Certificate.new(IO.read(cacert_file))
|
260
|
+
ca_key = OpenSSL::PKey::RSA.new(IO.read(cakey_file))
|
261
|
+
else
|
262
|
+
ca_key = OpenSSL::PKey::RSA.new(2048)
|
263
|
+
File.open(cakey_file, 'w+') { |f| f.write(ca_key.to_pem) }
|
264
|
+
|
265
|
+
ca_subject = "/CN=ca/DC=stackbuilder.org"
|
266
|
+
ca_cert = create_ca_cert(ca_key, ca_subject)
|
267
|
+
File.open(cacert_file, 'w+') { |f| f.write(ca_cert.to_pem) }
|
268
|
+
end
|
269
|
+
|
270
|
+
servers = certificates.split(',')
|
271
|
+
servers.each do |server|
|
272
|
+
|
273
|
+
server_dir = "#{repo_cert_dir}/#{server}"
|
274
|
+
server_cert_file = "#{server_dir}/cert.pem"
|
275
|
+
server_key_file = "#{server_dir}/key.pem"
|
276
|
+
|
277
|
+
unless File.exist?(server_cert_file) && File.exist?(server_key_file)
|
278
|
+
|
279
|
+
server_key = OpenSSL::PKey::RSA.new(2048)
|
280
|
+
server_subject = "/C=US/O=#{server}/OU=Chef Community/CN=#{server}"
|
281
|
+
server_cert = create_server_cert(create_csr(server_key, server_subject), ca_key, ca_cert)
|
282
|
+
|
283
|
+
FileUtils.mkdir_p(server_dir)
|
284
|
+
|
285
|
+
File.open(server_cert_file, 'w+') { |f| f.write(server_cert.to_pem) }
|
286
|
+
File.open(server_key_file, 'w+') { |f| f.write(server_key.to_pem) }
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def create_ca_cert(ca_key, ca_subject)
|
293
|
+
|
294
|
+
ca_cert = create_cert(ca_key, ca_subject)
|
295
|
+
|
296
|
+
extension_factory = OpenSSL::X509::ExtensionFactory.new
|
297
|
+
extension_factory.subject_certificate = ca_cert
|
298
|
+
extension_factory.issuer_certificate = ca_cert
|
299
|
+
|
300
|
+
ca_cert.add_extension extension_factory
|
301
|
+
.create_extension('subjectKeyIdentifier', 'hash')
|
302
|
+
ca_cert.add_extension extension_factory
|
303
|
+
.create_extension('basicConstraints', 'CA:TRUE', true)
|
304
|
+
ca_cert.add_extension extension_factory
|
305
|
+
.create_extension('keyUsage', 'cRLSign,keyCertSign', true)
|
306
|
+
|
307
|
+
ca_cert.sign ca_key, OpenSSL::Digest::SHA256.new
|
308
|
+
|
309
|
+
ca_cert
|
310
|
+
end
|
311
|
+
|
312
|
+
def create_csr(key, subject)
|
313
|
+
|
314
|
+
csr = OpenSSL::X509::Request.new
|
315
|
+
csr.version = 0
|
316
|
+
csr.subject = OpenSSL::X509::Name.parse(subject)
|
317
|
+
csr.public_key = key.public_key
|
318
|
+
csr.sign key, OpenSSL::Digest::SHA256.new
|
319
|
+
|
320
|
+
csr
|
321
|
+
end
|
322
|
+
|
323
|
+
def create_server_cert(csr, ca_key, ca_cert)
|
324
|
+
|
325
|
+
csr_cert = create_cert(csr.public_key, csr.subject, ca_cert.subject)
|
326
|
+
|
327
|
+
extension_factory = OpenSSL::X509::ExtensionFactory.new
|
328
|
+
extension_factory.subject_certificate = csr_cert
|
329
|
+
extension_factory.issuer_certificate = ca_cert
|
330
|
+
|
331
|
+
csr_cert.add_extension extension_factory
|
332
|
+
.create_extension('basicConstraints', 'CA:FALSE')
|
333
|
+
csr_cert.add_extension extension_factory
|
334
|
+
.create_extension('keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
|
335
|
+
csr_cert.add_extension extension_factory
|
336
|
+
.create_extension('subjectKeyIdentifier', 'hash')
|
337
|
+
|
338
|
+
csr_cert.sign ca_key, OpenSSL::Digest::SHA256.new
|
339
|
+
|
340
|
+
csr_cert
|
341
|
+
end
|
342
|
+
|
343
|
+
def create_cert(key, subject, issuer = nil)
|
344
|
+
|
345
|
+
cert = OpenSSL::X509::Certificate.new
|
346
|
+
cert.serial = 0x0
|
347
|
+
cert.version = 2
|
348
|
+
cert.not_before = Time.now
|
349
|
+
cert.not_after = Time.now + (10 * 365 * 24 * 60 * 60) # 10 years
|
350
|
+
|
351
|
+
cert.public_key = key.public_key
|
352
|
+
|
353
|
+
cert.subject = subject.is_a?(OpenSSL::X509::Name) ?
|
354
|
+
subject : OpenSSL::X509::Name.parse(subject)
|
355
|
+
|
356
|
+
cert.issuer = issuer.is_a?(OpenSSL::X509::Name) ?
|
357
|
+
issuer : OpenSSL::X509::Name.parse(issuer.nil? ? subject : issuer)
|
358
|
+
|
359
|
+
cert
|
360
|
+
end
|
361
|
+
|
362
|
+
def upload_certificate(server_cert_dir, server_name, server_env_name)
|
363
|
+
|
364
|
+
data_bag_name = 'certificates-' + server_env_name
|
365
|
+
|
366
|
+
data_bag_item = {
|
367
|
+
'id' => server_name,
|
368
|
+
'cacert' => IO.read(server_cert_dir + "/../cacert.pem"),
|
369
|
+
'cert' => IO.read(server_cert_dir + "/cert.pem"),
|
370
|
+
'key' => IO.read(server_cert_dir + "/key.pem") }
|
371
|
+
|
372
|
+
tmpfile = "#{Dir.tmpdir}/#{server_name}.json"
|
373
|
+
File.open("#{tmpfile}", 'w+') { |f| f.write(data_bag_item.to_json) }
|
374
|
+
|
375
|
+
knife_cmd = Chef::Knife::DataBagFromFile.new
|
376
|
+
knife_cmd.name_args = [ data_bag_name, tmpfile ]
|
377
|
+
knife_cmd.config[:secret] = get_secret(server_env_name)
|
378
|
+
run_knife(knife_cmd)
|
379
|
+
|
380
|
+
puts "Uploaded '#{server_env_name}' certificate for server '#{server_name}' " +
|
381
|
+
"to data bag '#{data_bag_name}' at '#{Chef::Config.chef_server_url}'."
|
382
|
+
|
383
|
+
rescue Exception => msg
|
384
|
+
@logger.error(msg)
|
385
|
+
ensure
|
386
|
+
File.delete(tmpfile) unless tmpfile.nil? || !File.exist?(tmpfile)
|
387
|
+
end
|
388
|
+
|
389
|
+
def upload_data_bag_items(secret, path, data_bag_name, env_vars)
|
390
|
+
|
391
|
+
tmpfile = nil
|
392
|
+
|
393
|
+
Dir["#{path}/*.json"].each do |data_bag_file|
|
394
|
+
|
395
|
+
data_bag_item = eval_map_values(JSON.load(File.new(data_bag_file, 'r')), env_vars, data_bag_file)
|
396
|
+
|
397
|
+
data_bag_item_name = data_bag_item['id']
|
398
|
+
@logger.debug("Uploading data bag '#{data_bag_item_name}' with contents:\n#{data_bag_item.to_yaml}")
|
399
|
+
|
400
|
+
tmpfile = "#{Dir.tmpdir}/#{data_bag_item_name}.json"
|
401
|
+
File.open("#{tmpfile}", 'w+') { |f| f.write(data_bag_item.to_json) }
|
402
|
+
|
403
|
+
knife_cmd = Chef::Knife::DataBagFromFile.new
|
404
|
+
knife_cmd.name_args = [ data_bag_name, tmpfile ]
|
405
|
+
knife_cmd.config[:secret] = secret
|
406
|
+
run_knife(knife_cmd)
|
407
|
+
|
408
|
+
File.delete(tmpfile)
|
409
|
+
|
410
|
+
puts "Uploaded item '#{data_bag_item_name}' of data bag " +
|
411
|
+
"'#{data_bag_name}' to '#{Chef::Config.chef_server_url}'."
|
412
|
+
end
|
413
|
+
|
414
|
+
rescue Exception => msg
|
415
|
+
@logger.error(msg)
|
416
|
+
ensure
|
417
|
+
File.delete(tmpfile) unless tmpfile.nil? || !File.exist?(tmpfile)
|
418
|
+
end
|
419
|
+
|
420
|
+
def upload_role(role_file)
|
421
|
+
|
422
|
+
role_content = eval_map_values(JSON.load(File.new(role_file, 'r')), ENV)
|
423
|
+
|
424
|
+
role_name = role_content.is_a?(Chef::Role) ? role_content.name : role_content['name']
|
425
|
+
@logger.debug("Uploading role '#{role_name}' with contents:\n#{role_content.to_yaml}")
|
426
|
+
|
427
|
+
tmpfile = "#{Dir.tmpdir}/#{role_name}.json"
|
428
|
+
File.open("#{tmpfile}", 'w+') { |f| f.write(role_content.to_json) }
|
429
|
+
|
430
|
+
knife_cmd = Chef::Knife::RoleFromFile.new
|
431
|
+
knife_cmd.name_args = [ tmpfile ]
|
432
|
+
run_knife(knife_cmd)
|
433
|
+
|
434
|
+
puts "Uploaded role '#{role_name}' to '#{Chef::Config.chef_server_url}'."
|
435
|
+
|
436
|
+
rescue Exception => msg
|
437
|
+
@logger.error(msg)
|
438
|
+
ensure
|
439
|
+
File.delete(tmpfile) unless tmpfile.nil? || !File.exist?(tmpfile)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright (c) 2014 Mevan Samaratunga
|
2
|
+
|
3
|
+
include StackBuilder::Common::Helpers
|
4
|
+
|
5
|
+
module StackBuilder::Chef
|
6
|
+
|
7
|
+
class GenericNodeManager < StackBuilder::Chef::NodeManager
|
8
|
+
|
9
|
+
def create_vm(name, knife_config)
|
10
|
+
|
11
|
+
create_class_name = knife_config['create']['class']
|
12
|
+
raise ArgumentError, "Knife plugin's server 'create' class name not provided." \
|
13
|
+
if create_class_name.nil?
|
14
|
+
|
15
|
+
knife_cmd = eval(create_class_name + '.new')
|
16
|
+
|
17
|
+
if knife_config['create'].has_key?('name_key')
|
18
|
+
name_key = knife_config['create']['name_key']
|
19
|
+
knife_cmd.config[name_key.to_sym] = name
|
20
|
+
else
|
21
|
+
knife_cmd.name_args = [ name ]
|
22
|
+
end
|
23
|
+
|
24
|
+
config_knife(knife_cmd, knife_config['create']['options'] || { })
|
25
|
+
config_knife(knife_cmd, knife_config['options'] || { })
|
26
|
+
|
27
|
+
if knife_config['create']['synchronized']
|
28
|
+
@@sync ||= Mutex.new
|
29
|
+
@@sync.synchronize {
|
30
|
+
run_knife(knife_cmd, knife_config['create']['retries'] || 0)
|
31
|
+
}
|
32
|
+
else
|
33
|
+
run_knife(knife_cmd, knife_config['create']['retries'] || 0)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete_vm(name, knife_config)
|
38
|
+
|
39
|
+
return unless knife_config.has_key?('delete')
|
40
|
+
|
41
|
+
delete_class_name = knife_config['delete']['class']
|
42
|
+
raise ArgumentError, "Knife plugin's server 'delete' class name not provided." \
|
43
|
+
if delete_class_name.nil?
|
44
|
+
|
45
|
+
knife_cmd = eval(delete_class_name + '.new')
|
46
|
+
|
47
|
+
if knife_config['delete'].has_key?('name_key')
|
48
|
+
name_key = knife_config['create']['name_key']
|
49
|
+
knife_cmd.config[name_key.to_sym] = name
|
50
|
+
else
|
51
|
+
knife_cmd.name_args = [ name ]
|
52
|
+
end
|
53
|
+
|
54
|
+
config_knife(knife_cmd, knife_config['delete']['options'] || { })
|
55
|
+
config_knife(knife_cmd, knife_config['options'] || { })
|
56
|
+
|
57
|
+
if knife_config['delete']['synchronized']
|
58
|
+
@@sync ||= Mutex.new
|
59
|
+
@@sync.synchronize {
|
60
|
+
run_knife(knife_cmd, knife_config['delete']['retries'] || 0)
|
61
|
+
}
|
62
|
+
else
|
63
|
+
run_knife(knife_cmd, knife_config['delete']['retries'] || 0)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|