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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +10 -2
  3. data/bin/mu-adopt +5 -1
  4. data/bin/mu-load-config.rb +2 -3
  5. data/bin/mu-run-tests +112 -27
  6. data/cloud-mu.gemspec +20 -20
  7. data/cookbooks/mu-tools/libraries/helper.rb +2 -1
  8. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  9. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  10. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  11. data/extras/image-generators/Google/centos6.yaml +1 -0
  12. data/extras/image-generators/Google/centos7.yaml +1 -1
  13. data/modules/mommacat.ru +5 -15
  14. data/modules/mu.rb +10 -14
  15. data/modules/mu/adoption.rb +20 -14
  16. data/modules/mu/cleanup.rb +13 -9
  17. data/modules/mu/cloud.rb +26 -26
  18. data/modules/mu/clouds/aws.rb +100 -59
  19. data/modules/mu/clouds/aws/alarm.rb +4 -2
  20. data/modules/mu/clouds/aws/bucket.rb +25 -21
  21. data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
  22. data/modules/mu/clouds/aws/collection.rb +21 -20
  23. data/modules/mu/clouds/aws/container_cluster.rb +47 -26
  24. data/modules/mu/clouds/aws/database.rb +57 -68
  25. data/modules/mu/clouds/aws/dnszone.rb +14 -14
  26. data/modules/mu/clouds/aws/endpoint.rb +20 -16
  27. data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
  28. data/modules/mu/clouds/aws/folder.rb +7 -7
  29. data/modules/mu/clouds/aws/function.rb +15 -12
  30. data/modules/mu/clouds/aws/group.rb +14 -10
  31. data/modules/mu/clouds/aws/habitat.rb +16 -13
  32. data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
  33. data/modules/mu/clouds/aws/log.rb +13 -10
  34. data/modules/mu/clouds/aws/msg_queue.rb +15 -8
  35. data/modules/mu/clouds/aws/nosqldb.rb +18 -11
  36. data/modules/mu/clouds/aws/notifier.rb +11 -6
  37. data/modules/mu/clouds/aws/role.rb +87 -70
  38. data/modules/mu/clouds/aws/search_domain.rb +30 -19
  39. data/modules/mu/clouds/aws/server.rb +102 -72
  40. data/modules/mu/clouds/aws/server_pool.rb +47 -28
  41. data/modules/mu/clouds/aws/storage_pool.rb +5 -6
  42. data/modules/mu/clouds/aws/user.rb +13 -10
  43. data/modules/mu/clouds/aws/vpc.rb +135 -121
  44. data/modules/mu/clouds/azure.rb +16 -9
  45. data/modules/mu/clouds/azure/container_cluster.rb +2 -3
  46. data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
  47. data/modules/mu/clouds/azure/habitat.rb +8 -6
  48. data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
  49. data/modules/mu/clouds/azure/role.rb +8 -10
  50. data/modules/mu/clouds/azure/server.rb +65 -25
  51. data/modules/mu/clouds/azure/user.rb +5 -7
  52. data/modules/mu/clouds/azure/vpc.rb +12 -15
  53. data/modules/mu/clouds/cloudformation.rb +8 -7
  54. data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
  55. data/modules/mu/clouds/google.rb +39 -24
  56. data/modules/mu/clouds/google/bucket.rb +9 -11
  57. data/modules/mu/clouds/google/container_cluster.rb +27 -42
  58. data/modules/mu/clouds/google/database.rb +6 -9
  59. data/modules/mu/clouds/google/firewall_rule.rb +11 -10
  60. data/modules/mu/clouds/google/folder.rb +16 -9
  61. data/modules/mu/clouds/google/function.rb +127 -161
  62. data/modules/mu/clouds/google/group.rb +21 -18
  63. data/modules/mu/clouds/google/habitat.rb +18 -15
  64. data/modules/mu/clouds/google/loadbalancer.rb +14 -16
  65. data/modules/mu/clouds/google/role.rb +48 -31
  66. data/modules/mu/clouds/google/server.rb +105 -105
  67. data/modules/mu/clouds/google/server_pool.rb +12 -31
  68. data/modules/mu/clouds/google/user.rb +67 -13
  69. data/modules/mu/clouds/google/vpc.rb +58 -65
  70. data/modules/mu/config.rb +89 -1738
  71. data/modules/mu/config/bucket.rb +3 -3
  72. data/modules/mu/config/collection.rb +3 -3
  73. data/modules/mu/config/container_cluster.rb +2 -2
  74. data/modules/mu/config/dnszone.rb +5 -5
  75. data/modules/mu/config/doc_helpers.rb +517 -0
  76. data/modules/mu/config/endpoint.rb +3 -3
  77. data/modules/mu/config/firewall_rule.rb +118 -3
  78. data/modules/mu/config/folder.rb +3 -3
  79. data/modules/mu/config/function.rb +2 -2
  80. data/modules/mu/config/group.rb +3 -3
  81. data/modules/mu/config/habitat.rb +3 -3
  82. data/modules/mu/config/loadbalancer.rb +3 -3
  83. data/modules/mu/config/log.rb +3 -3
  84. data/modules/mu/config/msg_queue.rb +3 -3
  85. data/modules/mu/config/nosqldb.rb +3 -3
  86. data/modules/mu/config/notifier.rb +2 -2
  87. data/modules/mu/config/ref.rb +333 -0
  88. data/modules/mu/config/role.rb +3 -3
  89. data/modules/mu/config/schema_helpers.rb +508 -0
  90. data/modules/mu/config/search_domain.rb +3 -3
  91. data/modules/mu/config/server.rb +86 -58
  92. data/modules/mu/config/server_pool.rb +2 -2
  93. data/modules/mu/config/tail.rb +189 -0
  94. data/modules/mu/config/user.rb +3 -3
  95. data/modules/mu/config/vpc.rb +44 -4
  96. data/modules/mu/defaults/Google.yaml +2 -2
  97. data/modules/mu/deploy.rb +13 -10
  98. data/modules/mu/groomer.rb +1 -1
  99. data/modules/mu/groomers/ansible.rb +69 -24
  100. data/modules/mu/groomers/chef.rb +52 -44
  101. data/modules/mu/logger.rb +17 -14
  102. data/modules/mu/master.rb +317 -2
  103. data/modules/mu/master/chef.rb +3 -4
  104. data/modules/mu/master/ldap.rb +3 -3
  105. data/modules/mu/master/ssl.rb +12 -2
  106. data/modules/mu/mommacat.rb +85 -1766
  107. data/modules/mu/mommacat/daemon.rb +394 -0
  108. data/modules/mu/mommacat/naming.rb +366 -0
  109. data/modules/mu/mommacat/storage.rb +689 -0
  110. data/modules/tests/bucket.yml +4 -0
  111. data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
  112. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  113. data/modules/tests/regrooms/bucket.yml +19 -0
  114. metadata +112 -102
@@ -1,6 +1,6 @@
1
1
  ---
2
- centos6: &centos6 centos-cloud/centos-6
3
- centos7: &centos7 centos-cloud/centos-7
2
+ centos6: &centos6 egt-labs-admin/mu-centos-6
3
+ centos7: &centos7 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
@@ -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" or seed[0] == seed[1]
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 { |cloudclass, data|
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
- shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(data[:cfg_plural])
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 { |cloudclass, data|
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 { |cloudclass, data|
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 Exception => e
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 Exception => e
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 Exception => e
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 Exception => e
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|
@@ -121,7 +121,7 @@ module MU
121
121
  else
122
122
  retval = @groomer_obj.method(method).call
123
123
  end
124
- rescue Exception => e
124
+ rescue StandardError => e
125
125
  pp e.backtrace
126
126
  raise MU::Groomer::RunError, e.message, e.backtrace
127
127
  end
@@ -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: nil)
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
- cmd = %Q{cd #{@ansible_path} && #{@ansible_execs}/ansible-playbook -i hosts #{@server.config['name']}.yml --limit=#{@server.mu_name} --vault-password-file #{pwfile} --timeout=30 --vault-password-file #{@ansible_path}/.vault_pw -u #{ssh_user}}
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
- raise MU::Groomer::RunError, "Failed Ansible command: #{cmd}" if !system(cmd)
216
- rescue MU::Groomer::RunError => e
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(update_cache: true) # Make sure we're fresh
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 vaults_to_clean [Array<Hash>]: Some vaults to expunge
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
- # @param nodeonly [Boolean]: Just delete the node and its keys, but leave other artifacts
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
- inventory.remove(node)
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
- # @param for_user [String]: Encrypt using the Vault password of the specified Mu user
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
- private
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 doesn't exist,
380
- # generate one.
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
- def secret_dir
396
- MU::Groomer::Ansible.secret_dir(@mu_user)
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.each_pair { |group, nodes|
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 { |group, nodes|
622
+ @inv.each_pair { |_group, nodes|
578
623
  nodes.delete(name)
579
624
  }
580
625
  save!
@@ -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 => e
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, v| !k.match(/_keys$/) }
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
- retval = ssh.exec!(cmd) { |ch, stream, data|
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 RuntimeError, SystemCallError, Timeout::Error, SocketError, Errno::ECONNRESET, IOError, Net::SSH::Exception, MU::Groomer::RunError, WinRM::WinRMError, MU::MuError => e
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 Exception => e # it's ok to fail here (and to ignore failure)
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 Exception => e
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
- loaded = ::ChefVault::Item.load("splunk", "admin_user")
447
- rescue ::ChefVault::Exceptions::KeysNotFound => e
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 Net::SSH::Disconnect, SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::HTTPServerException, SystemExit, Errno::ECONNREFUSED, Errno::EPIPE, WinRM::WinRMError, HTTPClient::ConnectTimeoutError, RuntimeError, MU::Cloud::BootstrapTempFail, MU::MuError => e
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
- retval = ssh.exec!(cmd) { |ch, stream, data|
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
- nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_addr, ssh_user, ssh_key_name = @server.getSSHConfig
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
- if !@config['vault_access'].nil?
597
- vault_access = @config['vault_access']
598
- else
599
- vault_access = []
600
- end
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 Net::SSH::Disconnect, SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::HTTPServerException, SystemExit, Errno::ECONNREFUSED, Errno::EPIPE, WinRM::WinRMError, HTTPClient::ConnectTimeoutError, RuntimeError, MU::Cloud::BootstrapTempFail, Net::SSH::Exception, Net::SSH::ConnectionTimeout => e
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 Exception => e
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 Exception => e
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(update_cache: true) # Make sure we're fresh
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 => e
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 Exception => e
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 => e
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 Exception => e
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
- nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_addr, ssh_user, ssh_key_name = @server.getSSHConfig
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 { |name, database|
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.each { |entry|
1072
+ multiple.map! { |entry|
1067
1073
  if !entry.match(/^role|recipe\[/)
1068
- entry = "#{type}[#{entry}]"
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 Exception is bad style
1114
- rescue Exception => e
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