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.
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