cloud-mu 3.1.3 → 3.1.4
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.
- 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
|