cloud-mu 3.1.3 → 3.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +10 -2
- data/bin/mu-adopt +5 -1
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-run-tests +112 -27
- data/cloud-mu.gemspec +20 -20
- data/cookbooks/mu-tools/libraries/helper.rb +2 -1
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +5 -15
- data/modules/mu.rb +10 -14
- data/modules/mu/adoption.rb +20 -14
- data/modules/mu/cleanup.rb +13 -9
- data/modules/mu/cloud.rb +26 -26
- data/modules/mu/clouds/aws.rb +100 -59
- data/modules/mu/clouds/aws/alarm.rb +4 -2
- data/modules/mu/clouds/aws/bucket.rb +25 -21
- data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
- data/modules/mu/clouds/aws/collection.rb +21 -20
- data/modules/mu/clouds/aws/container_cluster.rb +47 -26
- data/modules/mu/clouds/aws/database.rb +57 -68
- data/modules/mu/clouds/aws/dnszone.rb +14 -14
- data/modules/mu/clouds/aws/endpoint.rb +20 -16
- data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
- data/modules/mu/clouds/aws/folder.rb +7 -7
- data/modules/mu/clouds/aws/function.rb +15 -12
- data/modules/mu/clouds/aws/group.rb +14 -10
- data/modules/mu/clouds/aws/habitat.rb +16 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
- data/modules/mu/clouds/aws/log.rb +13 -10
- data/modules/mu/clouds/aws/msg_queue.rb +15 -8
- data/modules/mu/clouds/aws/nosqldb.rb +18 -11
- data/modules/mu/clouds/aws/notifier.rb +11 -6
- data/modules/mu/clouds/aws/role.rb +87 -70
- data/modules/mu/clouds/aws/search_domain.rb +30 -19
- data/modules/mu/clouds/aws/server.rb +102 -72
- data/modules/mu/clouds/aws/server_pool.rb +47 -28
- data/modules/mu/clouds/aws/storage_pool.rb +5 -6
- data/modules/mu/clouds/aws/user.rb +13 -10
- data/modules/mu/clouds/aws/vpc.rb +135 -121
- data/modules/mu/clouds/azure.rb +16 -9
- data/modules/mu/clouds/azure/container_cluster.rb +2 -3
- data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
- data/modules/mu/clouds/azure/habitat.rb +8 -6
- data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
- data/modules/mu/clouds/azure/role.rb +8 -10
- data/modules/mu/clouds/azure/server.rb +65 -25
- data/modules/mu/clouds/azure/user.rb +5 -7
- data/modules/mu/clouds/azure/vpc.rb +12 -15
- data/modules/mu/clouds/cloudformation.rb +8 -7
- data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
- data/modules/mu/clouds/google.rb +39 -24
- data/modules/mu/clouds/google/bucket.rb +9 -11
- data/modules/mu/clouds/google/container_cluster.rb +27 -42
- data/modules/mu/clouds/google/database.rb +6 -9
- data/modules/mu/clouds/google/firewall_rule.rb +11 -10
- data/modules/mu/clouds/google/folder.rb +16 -9
- data/modules/mu/clouds/google/function.rb +127 -161
- data/modules/mu/clouds/google/group.rb +21 -18
- data/modules/mu/clouds/google/habitat.rb +18 -15
- data/modules/mu/clouds/google/loadbalancer.rb +14 -16
- data/modules/mu/clouds/google/role.rb +48 -31
- data/modules/mu/clouds/google/server.rb +105 -105
- data/modules/mu/clouds/google/server_pool.rb +12 -31
- data/modules/mu/clouds/google/user.rb +67 -13
- data/modules/mu/clouds/google/vpc.rb +58 -65
- data/modules/mu/config.rb +89 -1738
- data/modules/mu/config/bucket.rb +3 -3
- data/modules/mu/config/collection.rb +3 -3
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/dnszone.rb +5 -5
- data/modules/mu/config/doc_helpers.rb +517 -0
- data/modules/mu/config/endpoint.rb +3 -3
- data/modules/mu/config/firewall_rule.rb +118 -3
- data/modules/mu/config/folder.rb +3 -3
- data/modules/mu/config/function.rb +2 -2
- data/modules/mu/config/group.rb +3 -3
- data/modules/mu/config/habitat.rb +3 -3
- data/modules/mu/config/loadbalancer.rb +3 -3
- data/modules/mu/config/log.rb +3 -3
- data/modules/mu/config/msg_queue.rb +3 -3
- data/modules/mu/config/nosqldb.rb +3 -3
- data/modules/mu/config/notifier.rb +2 -2
- data/modules/mu/config/ref.rb +333 -0
- data/modules/mu/config/role.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +508 -0
- data/modules/mu/config/search_domain.rb +3 -3
- data/modules/mu/config/server.rb +86 -58
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/tail.rb +189 -0
- data/modules/mu/config/user.rb +3 -3
- data/modules/mu/config/vpc.rb +44 -4
- data/modules/mu/defaults/Google.yaml +2 -2
- data/modules/mu/deploy.rb +13 -10
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -24
- data/modules/mu/groomers/chef.rb +52 -44
- data/modules/mu/logger.rb +17 -14
- data/modules/mu/master.rb +317 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -2
- data/modules/mu/mommacat.rb +85 -1766
- data/modules/mu/mommacat/daemon.rb +394 -0
- data/modules/mu/mommacat/naming.rb +366 -0
- data/modules/mu/mommacat/storage.rb +689 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- metadata +112 -102
@@ -1,6 +1,6 @@
|
|
1
1
|
---
|
2
|
-
centos6: ¢os6
|
3
|
-
centos7: ¢os7
|
2
|
+
centos6: ¢os6 egt-labs-admin/mu-centos-6
|
3
|
+
centos7: ¢os7 egt-labs-admin/mu-centos-7
|
4
4
|
rhel71: &rhel71 rhel-cloud/rhel-7
|
5
5
|
rhel6: &rhel6 rhel-cloud/rhel-6
|
6
6
|
debian10: &debian10 debian-cloud/debian-10
|
data/modules/mu/deploy.rb
CHANGED
@@ -126,7 +126,7 @@ module MU
|
|
126
126
|
seedsize = 1 + (retries/10).abs
|
127
127
|
seed = (0...seedsize+1).map { ('a'..'z').to_a[rand(26)] }.join
|
128
128
|
deploy_id = @appname.upcase + "-" + @environment.upcase + "-" + @timestamp + "-" + seed.upcase
|
129
|
-
end while MU::MommaCat.deploy_exists?(deploy_id) or seed == "mu"
|
129
|
+
end while MU::MommaCat.deploy_exists?(deploy_id) or seed == "mu"
|
130
130
|
MU.setVar("deploy_id", deploy_id)
|
131
131
|
MU.setVar("appname", @appname.upcase)
|
132
132
|
MU.setVar("environment", @environment.upcase)
|
@@ -140,7 +140,7 @@ module MU
|
|
140
140
|
|
141
141
|
@fromName = MU.muCfg['mu_admin_email']
|
142
142
|
|
143
|
-
MU::Cloud.resource_types.each { |
|
143
|
+
MU::Cloud.resource_types.values.each { |data|
|
144
144
|
if !@main_config[data[:cfg_plural]].nil? and @main_config[data[:cfg_plural]].size > 0
|
145
145
|
@main_config[data[:cfg_plural]].each { |resource|
|
146
146
|
if force_cloudformation
|
@@ -154,7 +154,7 @@ module MU
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
}
|
157
|
-
|
157
|
+
_shortclass, _cfg_name, _cfg_plural, classname = MU::Cloud.getResourceNames(data[:cfg_plural])
|
158
158
|
@main_config[data[:cfg_plural]].each { |resource|
|
159
159
|
resource["#MU_CLOUDCLASS"] = classname
|
160
160
|
}
|
@@ -274,7 +274,7 @@ module MU
|
|
274
274
|
MU.dupGlobals(parent_thread_id)
|
275
275
|
Thread.current.thread_variable_set("name", "mu_create_container")
|
276
276
|
# Thread.abort_on_exception = false
|
277
|
-
MU::Cloud.resource_types.each { |
|
277
|
+
MU::Cloud.resource_types.values.each { |data|
|
278
278
|
if !@main_config[data[:cfg_plural]].nil? and
|
279
279
|
@main_config[data[:cfg_plural]].size > 0 and
|
280
280
|
data[:instance].include?(:create)
|
@@ -288,7 +288,7 @@ module MU
|
|
288
288
|
MU.dupGlobals(parent_thread_id)
|
289
289
|
Thread.current.thread_variable_set("name", "mu_groom_container")
|
290
290
|
# Thread.abort_on_exception = false
|
291
|
-
MU::Cloud.resource_types.each { |
|
291
|
+
MU::Cloud.resource_types.values.each { |data|
|
292
292
|
if !@main_config[data[:cfg_plural]].nil? and
|
293
293
|
@main_config[data[:cfg_plural]].size > 0 and
|
294
294
|
data[:instance].include?(:groom)
|
@@ -311,7 +311,9 @@ module MU
|
|
311
311
|
|
312
312
|
@mommacat.save!
|
313
313
|
|
314
|
-
rescue
|
314
|
+
rescue StandardError => e
|
315
|
+
MU.log e.class.name, MU::ERR, details: caller
|
316
|
+
|
315
317
|
@my_threads.each do |t|
|
316
318
|
if t.object_id != Thread.current.object_id and
|
317
319
|
t.thread_variable_get("name") != "main_thread" and
|
@@ -338,6 +340,8 @@ module MU
|
|
338
340
|
@nocleanup = true # so we don't run this again later
|
339
341
|
end
|
340
342
|
end
|
343
|
+
|
344
|
+
|
341
345
|
@reraise_thread.raise MuError, e.inspect, e.backtrace if @reraise_thread
|
342
346
|
Thread.current.exit
|
343
347
|
ensure
|
@@ -596,7 +600,6 @@ MESSAGE_END
|
|
596
600
|
return if services.nil?
|
597
601
|
|
598
602
|
parent_thread_id = Thread.current.object_id
|
599
|
-
parent_thread = Thread.current
|
600
603
|
services.uniq!
|
601
604
|
services.each do |service|
|
602
605
|
begin
|
@@ -639,14 +642,14 @@ MESSAGE_END
|
|
639
642
|
else
|
640
643
|
raise e
|
641
644
|
end
|
642
|
-
rescue
|
645
|
+
rescue StandardError => e
|
643
646
|
MU::MommaCat.unlockAll
|
644
647
|
@main_thread.raise MuError, "Error instantiating object from #{myservice["#MU_CLOUDCLASS"]} (#{e.inspect})", e.backtrace
|
645
648
|
raise e
|
646
649
|
end
|
647
650
|
begin
|
648
651
|
run_this_method = myservice['#MUOBJECT'].method(mode)
|
649
|
-
rescue
|
652
|
+
rescue StandardError => e
|
650
653
|
MU::MommaCat.unlockAll
|
651
654
|
@main_thread.raise MuError, "Error invoking #{myservice["#MU_CLOUDCLASS"]}.#{mode} for #{myservice['name']} (#{e.inspect})", e.backtrace
|
652
655
|
raise e
|
@@ -703,7 +706,7 @@ MESSAGE_END
|
|
703
706
|
@my_threads.reject! { |thr| !thr.alive? }
|
704
707
|
sleep 10+Random.rand(20)
|
705
708
|
retry
|
706
|
-
rescue
|
709
|
+
rescue StandardError => e
|
707
710
|
MU.log e.inspect, MU::ERR, details: e.backtrace if @verbosity != MU::Logger::SILENT
|
708
711
|
MU::MommaCat.unlockAll
|
709
712
|
Thread.list.each do |t|
|
data/modules/mu/groomer.rb
CHANGED
@@ -174,7 +174,6 @@ module MU
|
|
174
174
|
raise MuNoSuchSecret, "No such vault #{vault}"
|
175
175
|
end
|
176
176
|
|
177
|
-
data = nil
|
178
177
|
if item
|
179
178
|
itempath = dir+"/"+item
|
180
179
|
if !File.exist?(itempath)
|
@@ -191,7 +190,7 @@ module MU
|
|
191
190
|
|
192
191
|
# see {MU::Groomer::Ansible.deleteSecret}
|
193
192
|
def deleteSecret(vault: nil, item: nil)
|
194
|
-
self.class.deleteSecret(vault: vault, item:
|
193
|
+
self.class.deleteSecret(vault: vault, item: item)
|
195
194
|
end
|
196
195
|
|
197
196
|
# Invoke the Ansible client on the node at the other end of a provided SSH
|
@@ -207,22 +206,60 @@ module MU
|
|
207
206
|
|
208
207
|
ssh_user = @server.config['ssh_user'] || "root"
|
209
208
|
|
210
|
-
|
209
|
+
if update_runlist
|
210
|
+
bootstrap
|
211
|
+
end
|
212
|
+
|
213
|
+
tmpfile = nil
|
214
|
+
playbook = if override_runlist and !override_runlist.empty?
|
215
|
+
play = {
|
216
|
+
"hosts" => @server.config['name']
|
217
|
+
}
|
218
|
+
play["become"] = "yes" if @server.config['ssh_user'] != "root"
|
219
|
+
play["roles"] = override_runlist if @server.config['run_list'] and !@server.config['run_list'].empty?
|
220
|
+
play["vars"] = @server.config['ansible_vars'] if @server.config['ansible_vars']
|
221
|
+
|
222
|
+
tmpfile = Tempfile.new("#{@server.config['name']}-override-runlist.yml")
|
223
|
+
tmpfile.puts [play].to_yaml
|
224
|
+
tmpfile.close
|
225
|
+
tmpfile.path
|
226
|
+
else
|
227
|
+
"#{@server.config['name']}.yml"
|
228
|
+
end
|
229
|
+
|
230
|
+
cmd = %Q{cd #{@ansible_path} && echo "#{purpose}" && #{@ansible_execs}/ansible-playbook -i hosts #{playbook} --limit=#{@server.mu_name} --vault-password-file #{pwfile} --timeout=30 --vault-password-file #{@ansible_path}/.vault_pw -u #{ssh_user}}
|
211
231
|
|
212
232
|
retries = 0
|
213
233
|
begin
|
214
234
|
MU.log cmd
|
215
|
-
|
216
|
-
|
235
|
+
Timeout::timeout(timeout) {
|
236
|
+
if output
|
237
|
+
system("#{cmd}")
|
238
|
+
else
|
239
|
+
%x{#{cmd} 2>&1}
|
240
|
+
end
|
241
|
+
|
242
|
+
if $?.exitstatus != 0
|
243
|
+
raise MU::Groomer::RunError, "Failed Ansible command: #{cmd}"
|
244
|
+
end
|
245
|
+
}
|
246
|
+
rescue Timeout::Error, MU::Groomer::RunError => e
|
217
247
|
if retries < max_retries
|
248
|
+
if reboot_first_fail and e.class.name == "MU::Groomer::RunError"
|
249
|
+
@server.reboot
|
250
|
+
reboot_first_fail = false
|
251
|
+
end
|
218
252
|
sleep 30
|
219
253
|
retries += 1
|
220
254
|
MU.log "Failed Ansible run, will retry (#{retries.to_s}/#{max_retries.to_s})", MU::NOTICE, details: cmd
|
221
255
|
retry
|
222
256
|
else
|
257
|
+
tmpfile.unlink if tmpfile
|
223
258
|
raise MuError, "Failed Ansible command: #{cmd}"
|
224
259
|
end
|
225
260
|
end
|
261
|
+
|
262
|
+
tmpfile.unlink if tmpfile
|
226
263
|
end
|
227
264
|
|
228
265
|
# This is a stub; since Ansible is effectively agentless, this operation
|
@@ -265,7 +302,7 @@ module MU
|
|
265
302
|
# Synchronize the deployment structure managed by {MU::MommaCat} into some Ansible variables, so that nodes can access this metadata.
|
266
303
|
# @return [Hash]: The data synchronized.
|
267
304
|
def saveDeployData
|
268
|
-
@server.describe
|
305
|
+
@server.describe
|
269
306
|
|
270
307
|
allvars = {
|
271
308
|
"mu_deployment" => MU::Config.stripConfig(@server.deploy.deployment),
|
@@ -316,14 +353,15 @@ module MU
|
|
316
353
|
|
317
354
|
# Expunge Ansible resources associated with a node.
|
318
355
|
# @param node [String]: The Mu name of the node in question.
|
319
|
-
# @param
|
356
|
+
# @param _vaults_to_clean [Array<Hash>]: Dummy argument, part of this method's interface but not used by the Ansible layer
|
320
357
|
# @param noop [Boolean]: Skip actual deletion, just state what we'd do
|
321
|
-
|
322
|
-
def self.cleanup(node, vaults_to_clean = [], noop = false, nodeonly: false)
|
358
|
+
def self.cleanup(node, _vaults_to_clean = [], noop = false)
|
323
359
|
deploy = MU::MommaCat.new(MU.deploy_id)
|
324
360
|
inventory = Inventory.new(deploy)
|
325
|
-
ansible_path = deploy.deploy_dir+"/ansible"
|
326
|
-
|
361
|
+
# ansible_path = deploy.deploy_dir+"/ansible"
|
362
|
+
if !noop
|
363
|
+
inventory.remove(node)
|
364
|
+
end
|
327
365
|
end
|
328
366
|
|
329
367
|
# List the Ansible vaults, if any, owned by the specified Mu user
|
@@ -344,8 +382,7 @@ module MU
|
|
344
382
|
# the results to +STDOUT+.
|
345
383
|
# @param name [String]: The variable name to use for the string's YAML key
|
346
384
|
# @param string [String]: The string to encrypt
|
347
|
-
|
348
|
-
def self.encryptString(name, string, for_user = nil)
|
385
|
+
def self.encryptString(name, string)
|
349
386
|
pwfile = vaultPasswordFile
|
350
387
|
cmd = %Q{#{ansibleExecDir}/ansible-vault}
|
351
388
|
if !system(cmd, "encrypt_string", string, "--name", name, "--vault-password-file", pwfile)
|
@@ -353,8 +390,8 @@ module MU
|
|
353
390
|
end
|
354
391
|
end
|
355
392
|
|
356
|
-
|
357
|
-
|
393
|
+
# Hunt down and return a path for Ansible executables
|
394
|
+
# @return [String]
|
358
395
|
def self.ansibleExecDir
|
359
396
|
path = nil
|
360
397
|
if File.exist?(BINDIR+"/ansible-playbook")
|
@@ -376,8 +413,12 @@ module MU
|
|
376
413
|
path
|
377
414
|
end
|
378
415
|
|
379
|
-
# Get the +.vault_pw+ file for the appropriate user. If it
|
380
|
-
# generate
|
416
|
+
# Get path to the +.vault_pw+ file for the appropriate user. If it
|
417
|
+
# doesn't exist, generate it.
|
418
|
+
#
|
419
|
+
# @param for_user [String]:
|
420
|
+
# @param pwfile [String]
|
421
|
+
# @return [String]
|
381
422
|
def self.vaultPasswordFile(for_user = nil, pwfile: nil)
|
382
423
|
pwfile ||= secret_dir(for_user)+"/.vault_pw"
|
383
424
|
@@pwfile_semaphore.synchronize {
|
@@ -392,11 +433,8 @@ module MU
|
|
392
433
|
end
|
393
434
|
|
394
435
|
# Figure out where our main stash of secrets is, and make sure it exists
|
395
|
-
|
396
|
-
|
397
|
-
end
|
398
|
-
|
399
|
-
# Figure out where our main stash of secrets is, and make sure it exists
|
436
|
+
# @param user [String]:
|
437
|
+
# @return [String]
|
400
438
|
def self.secret_dir(user = MU.mu_user)
|
401
439
|
path = MU.dataDir(user) + "/ansible-secrets"
|
402
440
|
Dir.mkdir(path, 0755) if !Dir.exist?(path)
|
@@ -404,6 +442,13 @@ module MU
|
|
404
442
|
path
|
405
443
|
end
|
406
444
|
|
445
|
+
private
|
446
|
+
|
447
|
+
# Figure out where our main stash of secrets is, and make sure it exists
|
448
|
+
def secret_dir
|
449
|
+
MU::Groomer::Ansible.secret_dir(@mu_user)
|
450
|
+
end
|
451
|
+
|
407
452
|
# Make an effort to distinguish an Ansible role from other sorts of
|
408
453
|
# artifacts, since 'roles' is an awfully generic name for a directory.
|
409
454
|
# Short of a full, slow syntax check, this is the best we're liable to do.
|
@@ -543,7 +588,7 @@ module MU
|
|
543
588
|
def haveNode?(name)
|
544
589
|
lock
|
545
590
|
read
|
546
|
-
@inv.
|
591
|
+
@inv.values.each { |nodes|
|
547
592
|
if nodes.include?(name)
|
548
593
|
unlock
|
549
594
|
return true
|
@@ -574,7 +619,7 @@ module MU
|
|
574
619
|
def remove(name)
|
575
620
|
lock
|
576
621
|
read
|
577
|
-
@inv.each_pair { |
|
622
|
+
@inv.each_pair { |_group, nodes|
|
578
623
|
nodes.delete(name)
|
579
624
|
}
|
580
625
|
save!
|
data/modules/mu/groomers/chef.rb
CHANGED
@@ -184,13 +184,13 @@ module MU
|
|
184
184
|
if !item.nil?
|
185
185
|
begin
|
186
186
|
loaded = ::ChefVault::Item.load(vault, item)
|
187
|
-
rescue ::ChefVault::Exceptions::KeysNotFound
|
187
|
+
rescue ::ChefVault::Exceptions::KeysNotFound
|
188
188
|
raise MuNoSuchSecret, "Can't load the Chef Vault #{vault}:#{item}. Does it exist? Chef user: #{MU.chef_user}"
|
189
189
|
end
|
190
190
|
else
|
191
191
|
# If we didn't ask for a particular item, list what we have.
|
192
192
|
begin
|
193
|
-
loaded = ::Chef::DataBag.load(vault).keys.select { |k
|
193
|
+
loaded = ::Chef::DataBag.load(vault).keys.select { |k| !k.match(/_keys$/) }
|
194
194
|
rescue Net::HTTPServerException
|
195
195
|
raise MuNoSuchSecret, "Failed to retrieve Vault #{vault}"
|
196
196
|
end
|
@@ -258,7 +258,6 @@ module MU
|
|
258
258
|
knifeAddToRunList(multiple: @config['run_list'])
|
259
259
|
end
|
260
260
|
|
261
|
-
pending_reboot_count = 0
|
262
261
|
chef_node = ::Chef::Node.load(@server.mu_name)
|
263
262
|
if !@config['application_attributes'].nil?
|
264
263
|
MU.log "Setting node:#{@server.mu_name} application_attributes", MU::DEBUG, details: @config['application_attributes']
|
@@ -300,7 +299,7 @@ module MU
|
|
300
299
|
cmd = "#{upgrade_cmd} chef-client --color || echo #{error_signal}"
|
301
300
|
end
|
302
301
|
Timeout::timeout(timeout) {
|
303
|
-
|
302
|
+
ssh.exec!(cmd) { |_ch, _stream, data|
|
304
303
|
extra_logfile = if Dir.exist?(@server.deploy.deploy_dir)
|
305
304
|
File.open(@server.deploy.deploy_dir+"/log", "a")
|
306
305
|
end
|
@@ -380,7 +379,7 @@ module MU
|
|
380
379
|
sleep 30
|
381
380
|
end
|
382
381
|
retry
|
383
|
-
rescue
|
382
|
+
rescue SystemExit, Timeout::Error, MU::Cloud::BootstrapTempFail, Net::HTTPServerException, HTTPClient::ConnectTimeoutError, WinRM::WinRMError, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, Net::SSH::Exception, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE, SocketError, IOError => e
|
384
383
|
begin
|
385
384
|
ssh.close if !ssh.nil?
|
386
385
|
rescue Net::SSH::Exception, IOError => e
|
@@ -390,6 +389,8 @@ module MU
|
|
390
389
|
MU.log "ssh session to #{@server.mu_name} was closed unexpectedly, waiting before trying again", MU::NOTICE
|
391
390
|
end
|
392
391
|
sleep 10
|
392
|
+
rescue StandardError => e
|
393
|
+
MU.log "Error I don't recognize closing ssh tunnel", MU::WARN, details: e.inspect
|
393
394
|
end
|
394
395
|
if e.instance_of?(MU::Groomer::RunError) and retries == 0 and max_retries > 1 and purpose != "Base Windows configuration"
|
395
396
|
MU.log "Got a run error, will attempt to install/update Chef Client on next attempt", MU::NOTICE
|
@@ -404,7 +405,7 @@ module MU
|
|
404
405
|
begin
|
405
406
|
preClean(true) # drop any Chef install that's not ours
|
406
407
|
@server.reboot # try gently rebooting the thing
|
407
|
-
rescue
|
408
|
+
rescue StandardError => e # it's ok to fail here (and to ignore failure)
|
408
409
|
MU.log "preclean err #{e.inspect}", MU::ERR
|
409
410
|
end
|
410
411
|
reboot_first_fail = false
|
@@ -429,7 +430,7 @@ module MU
|
|
429
430
|
@server.deploy.sendAdminSlack("Chef run '#{purpose}' failed on `#{@server.mu_name}` :crying_cat_face:", msg: e.message)
|
430
431
|
raise MU::Groomer::RunError, "#{@server.mu_name}: Chef run '#{purpose}' failed #{max_retries} times, last error was: #{e.message}"
|
431
432
|
end
|
432
|
-
rescue
|
433
|
+
rescue StandardError => e
|
433
434
|
@server.deploy.sendAdminSlack("Chef run '#{purpose}' failed on `#{@server.mu_name}` :crying_cat_face:", msg: e.inspect)
|
434
435
|
raise MU::Groomer::RunError, "Caught unexpected #{e.inspect} on #{@server.mu_name} in @groomer.run at #{e.backtrace[0]}"
|
435
436
|
|
@@ -443,8 +444,8 @@ module MU
|
|
443
444
|
def splunkVaultInit
|
444
445
|
self.class.loadChefLib
|
445
446
|
begin
|
446
|
-
|
447
|
-
rescue ::ChefVault::Exceptions::KeysNotFound
|
447
|
+
::ChefVault::Item.load("splunk", "admin_user")
|
448
|
+
rescue ::ChefVault::Exceptions::KeysNotFound
|
448
449
|
pw = Password.pronounceable(12..14)
|
449
450
|
creds = {
|
450
451
|
"username" => "admin",
|
@@ -550,7 +551,7 @@ module MU
|
|
550
551
|
winrm = @server.getWinRMSession(1, 30, winrm_retries: 2)
|
551
552
|
pp winrm.run(cmd)
|
552
553
|
return
|
553
|
-
rescue
|
554
|
+
rescue SystemExit, Timeout::Error, MU::Cloud::BootstrapTempFail, MU::MuError, Net::HTTPServerException, HTTPClient::ConnectTimeoutError, WinRM::WinRMError, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, Net::SSH::Exception, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE, SocketError, IOError
|
554
555
|
MU.log "WinRM failure attempting Chef upgrade on #{@server.mu_name}, will fall back to ssh", MU::WARN
|
555
556
|
cmd = %Q{powershell.exe -inputformat none -noprofile "#{cmd}"}
|
556
557
|
end
|
@@ -558,7 +559,7 @@ module MU
|
|
558
559
|
|
559
560
|
MU.log "Attempting Chef upgrade via ssh on #{@server.mu_name}", MU::NOTICE, details: cmd
|
560
561
|
ssh = @server.getSSHSession(1)
|
561
|
-
|
562
|
+
ssh.exec!(cmd) { |_ch, _stream, data|
|
562
563
|
puts data
|
563
564
|
}
|
564
565
|
end
|
@@ -580,7 +581,7 @@ module MU
|
|
580
581
|
@config['cleaned_chef'] = true
|
581
582
|
end
|
582
583
|
|
583
|
-
|
584
|
+
_nat_ssh_key, _nat_ssh_user, _nat_ssh_host, canonical_addr, ssh_user, ssh_key_name = @server.getSSHConfig
|
584
585
|
|
585
586
|
MU.log "Bootstrapping #{@server.mu_name} (#{canonical_addr}) with knife"
|
586
587
|
|
@@ -593,11 +594,12 @@ module MU
|
|
593
594
|
json_attribs['skipinitialupdates'] = @config['skipinitialupdates']
|
594
595
|
end
|
595
596
|
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
597
|
+
# XXX this seems to break Knife Bootstrap
|
598
|
+
# vault_access = if !@config['vault_access'].nil?
|
599
|
+
# @config['vault_access']
|
600
|
+
# else
|
601
|
+
# []
|
602
|
+
# end
|
601
603
|
|
602
604
|
@server.windows? ? max_retries = 25 : max_retries = 10
|
603
605
|
@server.windows? ? timeout = 1800 : timeout = 300
|
@@ -658,7 +660,7 @@ module MU
|
|
658
660
|
}
|
659
661
|
# throws Net::HTTPServerException if we haven't really bootstrapped
|
660
662
|
::Chef::Node.load(@server.mu_name)
|
661
|
-
rescue
|
663
|
+
rescue SystemExit, Timeout::Error, MU::Cloud::BootstrapTempFail, Net::HTTPServerException, HTTPClient::ConnectTimeoutError, WinRM::WinRMError, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, Net::SSH::Exception, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE, SocketError, IOError => e
|
662
664
|
if retries < max_retries
|
663
665
|
retries += 1
|
664
666
|
# Bad Chef installs are possible culprits of bootstrap failures, so
|
@@ -671,7 +673,7 @@ module MU
|
|
671
673
|
!@config['forced_preclean']
|
672
674
|
begin
|
673
675
|
preClean(false) # it's ok for this to fail
|
674
|
-
rescue
|
676
|
+
rescue StandardError => e
|
675
677
|
end
|
676
678
|
MU::Groomer::Chef.cleanup(@server.mu_name, nodeonly: true)
|
677
679
|
@config['forced_preclean'] = true
|
@@ -683,7 +685,7 @@ module MU
|
|
683
685
|
else
|
684
686
|
raise MuError, "#{@server.mu_name}: Knife Bootstrap failed too many times with #{e.inspect}"
|
685
687
|
end
|
686
|
-
rescue
|
688
|
+
rescue StandardError => e
|
687
689
|
MU.log e.inspect, MU::ERR, details: e.backtrace
|
688
690
|
sleep 10*retries
|
689
691
|
retry
|
@@ -700,7 +702,7 @@ retry
|
|
700
702
|
end
|
701
703
|
}
|
702
704
|
knifeAddToRunList("role[mu-node]")
|
703
|
-
knifeAddToRunList("mu-tools::selinux")
|
705
|
+
knifeAddToRunList("recipe[mu-tools::selinux]")
|
704
706
|
|
705
707
|
grantSecretAccess(@server.mu_name, "windows_credentials") if @server.windows?
|
706
708
|
grantSecretAccess(@server.mu_name, "ssl_cert")
|
@@ -748,7 +750,7 @@ retry
|
|
748
750
|
return
|
749
751
|
end
|
750
752
|
|
751
|
-
@server.describe
|
753
|
+
@server.describe
|
752
754
|
saveChefMetadata
|
753
755
|
begin
|
754
756
|
chef_node = ::Chef::Node.load(@server.mu_name)
|
@@ -785,7 +787,7 @@ retry
|
|
785
787
|
chef_node.save
|
786
788
|
end
|
787
789
|
return chef_node['deployment']
|
788
|
-
rescue Net::HTTPServerException
|
790
|
+
rescue Net::HTTPServerException
|
789
791
|
MU.log "Attempted to save deployment to Chef node #{@server.mu_name} before it was bootstrapped.", MU::DEBUG
|
790
792
|
end
|
791
793
|
end
|
@@ -804,7 +806,7 @@ retry
|
|
804
806
|
MU.log "knife vault remove #{vault['vault']} #{vault['item']} --search name:#{node}", MU::NOTICE
|
805
807
|
begin
|
806
808
|
::Chef::Knife.run(['vault', 'remove', vault['vault'], vault['item'], "--search", "name:#{node}"]) if !noop
|
807
|
-
rescue
|
809
|
+
rescue StandardError => e
|
808
810
|
MU.log "Error removing vault access for #{node} from #{vault['vault']} #{vault['item']}", MU::ERR, details: e.inspect
|
809
811
|
end
|
810
812
|
MU::MommaCat.unlock("vault-#{vault['vault']}")
|
@@ -858,7 +860,7 @@ retry
|
|
858
860
|
::Chef::Knife.run(['vault', 'refresh', vault['vault'], vault['item']])
|
859
861
|
end
|
860
862
|
end
|
861
|
-
rescue JSON::ParserError
|
863
|
+
rescue JSON::ParserError
|
862
864
|
MU.log "Error parsing JSON from data bag #{vault['vault']} #{vault['item']}_keys, skipping vault client cleanse", MU::WARN
|
863
865
|
end
|
864
866
|
end
|
@@ -887,18 +889,34 @@ retry
|
|
887
889
|
MU.log "Granting #{host} access to #{vault} #{item}"
|
888
890
|
begin
|
889
891
|
::Chef::Knife.run(['vault', 'update', vault, item, "--search", "name:#{host}"])
|
890
|
-
rescue
|
892
|
+
rescue StandardError => e
|
891
893
|
MU.log e.inspect, MU::ERR, details: caller
|
892
894
|
end
|
893
895
|
MU::MommaCat.unlock("vault-#{vault}", true)
|
894
896
|
end
|
895
897
|
|
898
|
+
# Execute a +knife+ command, and return its exit status and output
|
899
|
+
# @param cmd [String]: The knife subcommand to run, such as +vault list+
|
900
|
+
# @param showoutput [String]: Print the results to stdout
|
901
|
+
# @return [Array<Integer,String>]
|
902
|
+
def self.knifeCmd(cmd, showoutput = false)
|
903
|
+
MU.log "knife #{cmd}", MU::NOTICE if showoutput
|
904
|
+
output = `#{MU::Groomer::Chef.knife} #{cmd}`
|
905
|
+
exitstatus = $?.exitstatus
|
906
|
+
|
907
|
+
if showoutput
|
908
|
+
puts output
|
909
|
+
puts "Exit status: #{exitstatus}"
|
910
|
+
end
|
911
|
+
return [exitstatus, output]
|
912
|
+
end
|
913
|
+
|
896
914
|
private
|
897
915
|
|
898
916
|
# Save common Mu attributes to this node's Chef node structure.
|
899
917
|
def saveChefMetadata
|
900
918
|
self.class.loadChefLib
|
901
|
-
|
919
|
+
@server.getSSHConfig # why though
|
902
920
|
MU.log "Saving #{@server.mu_name} Chef artifacts"
|
903
921
|
|
904
922
|
begin
|
@@ -998,7 +1016,7 @@ retry
|
|
998
1016
|
deploy = MU::MommaCat.getLitter(MU.deploy_id, use_cache: false)
|
999
1017
|
@config['dependencies'].each{ |dep|
|
1000
1018
|
if dep['type'] == "database" && deploy.deployment.has_key?("databases") && deploy.deployment["databases"].has_key?(dep['name'])
|
1001
|
-
deploy.deployment["databases"][dep['name']].each { |
|
1019
|
+
deploy.deployment["databases"][dep['name']].values.each { |database|
|
1002
1020
|
grantSecretAccess(database['vault_name'], database['vault_item']) if database.has_key?("vault_name") && database.has_key?("vault_item")
|
1003
1021
|
}
|
1004
1022
|
end
|
@@ -1019,18 +1037,6 @@ retry
|
|
1019
1037
|
@secrets_granted["#{vault}:#{item}"] = item
|
1020
1038
|
end
|
1021
1039
|
|
1022
|
-
def self.knifeCmd(cmd, showoutput = false)
|
1023
|
-
MU.log "knife #{cmd}", MU::NOTICE if showoutput
|
1024
|
-
output = `#{MU::Groomer::Chef.knife} #{cmd}`
|
1025
|
-
exitstatus = $?.exitstatus
|
1026
|
-
|
1027
|
-
if showoutput
|
1028
|
-
puts output
|
1029
|
-
puts "Exit status: #{exitstatus}"
|
1030
|
-
end
|
1031
|
-
return [exitstatus, output]
|
1032
|
-
end
|
1033
|
-
|
1034
1040
|
def knifeCmd(cmd, showoutput = false)
|
1035
1041
|
self.class.knifeCmd(cmd, showoutput)
|
1036
1042
|
end
|
@@ -1063,9 +1069,11 @@ retry
|
|
1063
1069
|
if multiple.size == 0
|
1064
1070
|
multiple = [rl_entry]
|
1065
1071
|
end
|
1066
|
-
multiple.
|
1072
|
+
multiple.map! { |entry|
|
1067
1073
|
if !entry.match(/^role|recipe\[/)
|
1068
|
-
|
1074
|
+
"#{type}[#{entry}]"
|
1075
|
+
else
|
1076
|
+
entry
|
1069
1077
|
end
|
1070
1078
|
}
|
1071
1079
|
|
@@ -1110,8 +1118,8 @@ retry
|
|
1110
1118
|
MU.log("Adding #{rl_string} to Chef run_list of #{@server.mu_name}")
|
1111
1119
|
MU.log("Running #{query}", MU::DEBUG)
|
1112
1120
|
output=%x{#{query}}
|
1113
|
-
# XXX rescue
|
1114
|
-
rescue
|
1121
|
+
# XXX rescue StandardError is bad style
|
1122
|
+
rescue StandardError => e
|
1115
1123
|
raise MuError, "FAIL: #{MU::Groomer::Chef.knife} node run_list add #{@server.mu_name} \"#{rl_string}\": #{e.message} (output was #{output})"
|
1116
1124
|
end
|
1117
1125
|
end
|