cloud-mu 3.1.4 → 3.1.5

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/ansible/roles/mu-windows/README.md +33 -0
  3. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  4. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  5. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  6. data/ansible/roles/mu-windows/tasks/main.yml +20 -0
  7. data/ansible/roles/mu-windows/tests/inventory +2 -0
  8. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  9. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  10. data/cloud-mu.gemspec +4 -2
  11. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  12. data/cookbooks/mu-tools/recipes/windows-client.rb +140 -144
  13. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  14. data/extras/image-generators/AWS/win2k12.yaml +16 -13
  15. data/extras/image-generators/AWS/win2k16.yaml +16 -13
  16. data/extras/image-generators/AWS/win2k19.yaml +19 -0
  17. data/modules/mu.rb +72 -9
  18. data/modules/mu/adoption.rb +14 -2
  19. data/modules/mu/cloud.rb +111 -10
  20. data/modules/mu/clouds/aws.rb +23 -7
  21. data/modules/mu/clouds/aws/container_cluster.rb +640 -692
  22. data/modules/mu/clouds/aws/dnszone.rb +49 -45
  23. data/modules/mu/clouds/aws/firewall_rule.rb +177 -214
  24. data/modules/mu/clouds/aws/role.rb +17 -8
  25. data/modules/mu/clouds/aws/search_domain.rb +1 -1
  26. data/modules/mu/clouds/aws/server.rb +734 -1027
  27. data/modules/mu/clouds/aws/userdata/windows.erb +2 -1
  28. data/modules/mu/clouds/aws/vpc.rb +297 -786
  29. data/modules/mu/clouds/aws/vpc_subnet.rb +286 -0
  30. data/modules/mu/clouds/google/bucket.rb +1 -1
  31. data/modules/mu/clouds/google/container_cluster.rb +21 -17
  32. data/modules/mu/clouds/google/function.rb +8 -2
  33. data/modules/mu/clouds/google/server.rb +102 -32
  34. data/modules/mu/clouds/google/vpc.rb +1 -1
  35. data/modules/mu/config.rb +12 -1
  36. data/modules/mu/config/server.yml +1 -0
  37. data/modules/mu/defaults/AWS.yaml +51 -28
  38. data/modules/mu/groomers/ansible.rb +54 -17
  39. data/modules/mu/groomers/chef.rb +13 -7
  40. data/modules/mu/master/ssl.rb +0 -1
  41. data/modules/mu/mommacat.rb +8 -0
  42. data/modules/tests/ecs.yaml +23 -0
  43. data/modules/tests/includes-and-params.yaml +2 -1
  44. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  45. data/modules/tests/win2k12.yaml +25 -0
  46. data/modules/tests/win2k16.yaml +25 -0
  47. data/modules/tests/win2k19.yaml +25 -0
  48. data/requirements.txt +1 -0
  49. metadata +50 -4
  50. data/extras/image-generators/AWS/windows.yaml +0 -18
  51. data/modules/tests/needwork/win2k12.yaml +0 -13
@@ -195,48 +195,49 @@ action :config do
195
195
  else
196
196
  # We want to run ec2config as admin user so Windows userdata executes as admin, however the local admin account doesn't have Logon As a Service right. Domain privileges are set separately
197
197
 
198
- cookbook_file "c:\\Windows\\SysWOW64\\ntrights.exe" do
199
- source "ntrights"
200
- end
201
- [new_resource.ssh_user, new_resource.ec2config_user].each { |usr|
202
- pass = if usr == new_resource.ec2config_user
203
- new_resource.ec2config_password
204
- elsif usr == new_resource.ssh_user
205
- new_resource.ssh_password
206
- end
207
-
208
- user usr do
209
- password pass
210
- end
211
-
212
- group "Administrators" do
213
- action :modify
214
- members usr
215
- append true
216
- end
217
-
218
- %w{SeDenyRemoteInteractiveLogonRight SeDenyInteractiveLogonRight SeServiceLogonRight}.each { |privilege|
219
- batch "Grant local user #{usr} logon as service right" do
220
- code "C:\\Windows\\SysWOW64\\ntrights +r #{privilege} -u #{usr}"
221
- end
222
- }
223
-
224
- # XXX user resource seems not to really be setting password, or is setting # in such a way that the user is being required to change it. Workaround.
225
- powershell_script "Adjust local account params for #{usr}" do
226
- code <<-EOH
227
- (([adsi]('WinNT://./#{usr}, user')).psbase.invoke('SetPassword', '#{pass}'))
228
- EOH
229
- end
230
-
231
- if usr == new_resource.ssh_user
232
-
233
- %w{SeCreateTokenPrivilege SeTcbPrivilege SeAssignPrimaryTokenPrivilege}.each { |privilege|
234
- batch "Grant local user #{usr} logon as service right" do
235
- code "C:\\Windows\\SysWOW64\\ntrights +r #{privilege} -u #{usr}"
236
- end
237
- }
238
-
239
- end
240
- }
198
+ # cookbook_file "c:\\Windows\\SysWOW64\\ntrights.exe" do
199
+ # source "ntrights"
200
+ # end
201
+ # [new_resource.ssh_user, new_resource.ec2config_user].each { |usr|
202
+ # pass = if usr == new_resource.ec2config_user
203
+ # new_resource.ec2config_password
204
+ # elsif usr == new_resource.ssh_user
205
+ # new_resource.ssh_password
206
+ # end
207
+ #
208
+ # user usr do
209
+ # password pass
210
+ # action :modify
211
+ # end
212
+ #
213
+ # group "Administrators" do
214
+ # action :modify
215
+ # members usr
216
+ # append true
217
+ # end
218
+ #
219
+ # %w{SeDenyRemoteInteractiveLogonRight SeDenyInteractiveLogonRight SeServiceLogonRight}.each { |privilege|
220
+ # batch "Grant local user #{usr} logon as service right" do
221
+ # code "C:\\Windows\\SysWOW64\\ntrights +r #{privilege} -u #{usr}"
222
+ # end
223
+ # }
224
+ #
225
+ # # XXX user resource seems not to really be setting password, or is setting # in such a way that the user is being required to change it. Workaround.
226
+ # powershell_script "Adjust local account params for #{usr}" do
227
+ # code <<-EOH
228
+ # (([adsi]('WinNT://./#{usr}, user')).psbase.invoke('SetPassword', '#{pass}'))
229
+ # EOH
230
+ # end
231
+ #
232
+ # if usr == new_resource.ssh_user
233
+ #
234
+ # %w{SeCreateTokenPrivilege SeTcbPrivilege SeAssignPrimaryTokenPrivilege}.each { |privilege|
235
+ # batch "Grant local user #{usr} logon as service right" do
236
+ # code "C:\\Windows\\SysWOW64\\ntrights +r #{privilege} -u #{usr}"
237
+ # end
238
+ # }
239
+ #
240
+ # end
241
+ # }
241
242
  end
242
243
  end
@@ -1,16 +1,19 @@
1
1
  ---
2
2
  appname: mu
3
+ vpcs:
4
+ - name: windowsbuild
3
5
  servers:
4
- -
5
- name: win2k12
6
- platform: windows
7
- size: m4.large
8
- scrub_groomer: true
9
- run_list:
10
- - recipe[mu-tools::updates]
11
- - recipe[mu-utility::cleanup_image_helper]
12
- create_image:
13
- image_then_destroy: true
14
- public: true
15
- copy_to_regions:
16
- - "#ALL"
6
+ - name: win2k12
7
+ platform: win2k12
8
+ vpc:
9
+ name: windowsbuild
10
+ size: m4.large
11
+ scrub_groomer: true
12
+ groomer: Ansible
13
+ run_list:
14
+ - mu-windows
15
+ create_image:
16
+ image_then_destroy: true
17
+ public: true
18
+ copy_to_regions:
19
+ - "#ALL"
@@ -1,16 +1,19 @@
1
1
  ---
2
2
  appname: mu
3
+ vpcs:
4
+ - name: windowsbuild
3
5
  servers:
4
- -
5
- name: win2k16
6
- platform: windows
7
- size: m4.large
8
- scrub_groomer: true
9
- run_list:
10
- - recipe[mu-tools::updates]
11
- - recipe[mu-utility::cleanup_image_helper]
12
- create_image:
13
- image_then_destroy: true
14
- public: true
15
- copy_to_regions:
16
- - "#ALL"
6
+ - name: win2k16
7
+ platform: win2k16
8
+ vpc:
9
+ name: windowsbuild
10
+ size: m4.large
11
+ scrub_groomer: true
12
+ groomer: Ansible
13
+ run_list:
14
+ - mu-windows
15
+ create_image:
16
+ image_then_destroy: true
17
+ public: true
18
+ copy_to_regions:
19
+ - "#ALL"
@@ -0,0 +1,19 @@
1
+ ---
2
+ appname: mu
3
+ vpcs:
4
+ - name: windowsbuild
5
+ servers:
6
+ - name: win2k19
7
+ platform: windows
8
+ vpc:
9
+ name: windowsbuild
10
+ size: m4.large
11
+ scrub_groomer: true
12
+ groomer: Ansible
13
+ run_list:
14
+ - mu-windows
15
+ create_image:
16
+ image_then_destroy: true
17
+ public: true
18
+ copy_to_regions:
19
+ - "#ALL"
@@ -263,6 +263,7 @@ module MU
263
263
  end while newguy.nil?
264
264
 
265
265
  @@mu_global_thread_semaphore.synchronize {
266
+ MU.dupGlobals(Thread.current.object_id, target_thread: newguy)
266
267
  @@mu_global_threads << newguy
267
268
  }
268
269
 
@@ -295,6 +296,68 @@ module MU
295
296
  end
296
297
  end
297
298
 
299
+ # Boilerplate retry block executor, for making cloud API calls which might
300
+ # fail transiently.
301
+ #
302
+ # @param catchme [Array<Exception>]: Exception classes which should be caught and retried
303
+ # @param wait [Integer]: Number of seconds to wait between retries
304
+ # @param max [Integer]: Maximum number of retries; if less than 1, will retry indefinitely
305
+ # @param ignoreme [Array<Exception>]: Exception classes which can be silently treated as success. This will override any +loop_if+ block and return automatically (after invoking +always+, if the latter was specified).
306
+ # @param on_retry [Proc]: Optional block of code to invoke during retries
307
+ # @param always [Proc]: Optional block of code to invoke before returning or failing, a bit like +ensure+
308
+ # @param loop_if [Proc]: Optional block of code to invoke which will cause our block to be rerun until true
309
+ # @param loop_msg [String]: Message to display every third attempt
310
+ def self.retrier(catchme = nil, wait: 30, max: 0, ignoreme: [], on_retry: nil, always: nil, loop_if: nil, loop_msg: nil)
311
+
312
+ loop_if ||= Proc.new { false }
313
+
314
+ retries = 0
315
+ begin
316
+ retries += 1
317
+ loglevel = ((retries % 3) == 0) ? MU::NOTICE : MU::DEBUG
318
+ log_attempts = retries.to_s
319
+ log_attempts += (max > 0 ? "/"+max.to_s : "")
320
+ yield(retries, wait) if block_given?
321
+ if loop_if.call
322
+ MU.log loop_msg, loglevel, details: log_attempts if loop_msg
323
+ sleep wait
324
+ end
325
+ rescue StandardError => e
326
+ if catchme and catchme.include?(e.class)
327
+ if max > 0 and retries >= max
328
+ always.call if always and always.is_a?(Proc)
329
+ if ignoreme.include?(e.class)
330
+ return
331
+ else
332
+ raise e
333
+ end
334
+ end
335
+
336
+ if on_retry and on_retry.is_a?(Proc)
337
+ on_retry.call(e)
338
+ end
339
+
340
+ if retries == max-1
341
+ MU.log e.message, MU::WARN, details: caller
342
+ sleep wait # wait extra on the final attempt
343
+ else
344
+ MU.log e.message, loglevel, details: log_attempts
345
+ end
346
+
347
+ sleep wait
348
+ retry
349
+ elsif ignoreme and ignoreme.include?(e.class)
350
+ always.call if always and always.is_a?(Proc)
351
+ return
352
+ else
353
+ always.call if always and always.is_a?(Proc)
354
+ raise e
355
+ end
356
+ end while loop_if.call and (max < 1 or retries < max)
357
+
358
+ always.call if always and always.is_a?(Proc)
359
+ end
360
+
298
361
  if !ENV.has_key?("MU_LIBDIR") and ENV.has_key?("MU_INSTALLDIR")
299
362
  ENV['MU_LIBDIR'] = ENV['MU_INSTALLDIR']+"/lib"
300
363
  else
@@ -394,20 +457,20 @@ module MU
394
457
  @@global_var_semaphore = Mutex.new
395
458
 
396
459
  # Set one of our global per-thread variables.
397
- def self.setVar(name, value)
460
+ def self.setVar(name, value, target_thread: Thread.current)
398
461
  @@global_var_semaphore.synchronize {
399
- @@globals[Thread.current.object_id] ||= Hash.new
400
- @@globals[Thread.current.object_id][name] ||= Hash.new
401
- @@globals[Thread.current.object_id][name] = value
462
+ @@globals[target_thread.object_id] ||= Hash.new
463
+ @@globals[target_thread.object_id][name] ||= Hash.new
464
+ @@globals[target_thread.object_id][name] = value
402
465
  }
403
466
  end
404
467
 
405
468
  # Copy the set of global variables in use by another thread, typically our
406
469
  # parent thread.
407
- def self.dupGlobals(parent_thread_id)
470
+ def self.dupGlobals(parent_thread_id, target_thread: Thread.current)
408
471
  @@globals[parent_thread_id] ||= {}
409
472
  @@globals[parent_thread_id].each_pair { |name, value|
410
- setVar(name, value)
473
+ setVar(name, value, target_thread: target_thread)
411
474
  }
412
475
  end
413
476
 
@@ -1015,15 +1078,15 @@ module MU
1015
1078
 
1016
1079
  # Generate a random password which will satisfy the complexity requirements of stock Amazon Windows AMIs.
1017
1080
  # return [String]: A password string.
1018
- def self.generateWindowsPassword(safe_pattern: '~!@#%^&*_-+=`|(){}[]:;<>,.?', retries: 25)
1081
+ def self.generateWindowsPassword(safe_pattern: '~!@#%^&*_-+=`|(){}[]:;<>,.?', retries: 50)
1019
1082
  # We have dopey complexity requirements, be stringent here.
1020
1083
  # I'll be nice and not condense this into one elegant-but-unreadable regular expression
1021
1084
  attempts = 0
1022
1085
  safe_metachars = Regexp.escape(safe_pattern)
1023
1086
  begin
1024
1087
  if attempts > retries
1025
- MU.log "Failed to generate an adequate Windows password after #{attempts}", MU::ERR
1026
- raise MuError, "Failed to generate an adequate Windows password after #{attempts}"
1088
+ MU.log "Failed to generate an adequate Windows password after #{attempts} attempts", MU::ERR
1089
+ raise MuError, "Failed to generate an adequate Windows password after #{attempts} attempts"
1027
1090
  end
1028
1091
  winpass = Password.random(14..16)
1029
1092
  attempts += 1
@@ -227,6 +227,16 @@ module MU
227
227
 
228
228
  Thread.abort_on_exception = true
229
229
  resources.values.each { |obj_thr|
230
+ obj_desc = nil
231
+ begin
232
+ obj_desc = obj_thr.cloud_desc
233
+ rescue StandardError
234
+ ensure
235
+ if !obj_desc
236
+ MU.log cloud+" "+type.to_s+" "+obj_thr.cloud_id+" did not return a cloud descriptor, skipping", MU::WARN
237
+ next
238
+ end
239
+ end
230
240
  threads << Thread.new(obj_thr) { |obj|
231
241
 
232
242
  kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats)
@@ -463,7 +473,9 @@ module MU
463
473
 
464
474
  def resolveReferences(cfg, deploy, parent)
465
475
  if cfg.is_a?(MU::Config::Ref)
476
+ cfg.kitten(deploy) || cfg.kitten
466
477
  hashcfg = cfg.to_h
478
+
467
479
  if cfg.kitten(deploy)
468
480
  littermate = deploy.findLitterMate(type: cfg.type, name: cfg.name, cloud_id: cfg.id, habitat: cfg.habitat)
469
481
 
@@ -486,14 +498,14 @@ module MU
486
498
  hashcfg.delete("name") if cfg.id and !cfg.deploy_id
487
499
  end
488
500
  end
489
- elsif hashcfg["id"] # reference to raw cloud ids is reasonable
501
+ elsif hashcfg["id"] and !hashcfg["name"]
490
502
  hashcfg.delete("deploy_id")
491
- hashcfg.delete("name")
492
503
  else
493
504
  pp parent.cloud_desc
494
505
  raise Incomplete, "Failed to resolve reference on behalf of #{parent}"
495
506
  end
496
507
  hashcfg.delete("deploy_id") if hashcfg['deploy_id'] == deploy.deploy_id
508
+
497
509
  if parent and parent.config
498
510
  cred_cfg = MU::Cloud.const_get(parent.cloud).credConfig(parent.credentials)
499
511
 
@@ -1344,8 +1344,10 @@ module MU
1344
1344
  # which can refer to external resources (@vpc, @loadbalancers,
1345
1345
  # @add_firewall_rules)
1346
1346
  def dependencies(use_cache: false, debug: false)
1347
- @dependencies = {} if @dependencies.nil?
1348
- @loadbalancers = [] if @loadbalancers.nil?
1347
+ @dependencies ||= {}
1348
+ @loadbalancers ||= []
1349
+ @firewall_rules ||= []
1350
+
1349
1351
  if @config.nil?
1350
1352
  return [@dependencies, @vpc, @loadbalancers]
1351
1353
  end
@@ -1560,9 +1562,101 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1560
1562
  }
1561
1563
  end
1562
1564
 
1565
+ # Munge in external resources referenced by the existing_deploys
1566
+ # keyword
1567
+ if @config["existing_deploys"] && !@config["existing_deploys"].empty?
1568
+ @config["existing_deploys"].each { |ext_deploy|
1569
+ if ext_deploy["cloud_id"]
1570
+ found = MU::MommaCat.findStray(
1571
+ @config['cloud'],
1572
+ ext_deploy["cloud_type"],
1573
+ cloud_id: ext_deploy["cloud_id"],
1574
+ region: @config['region'],
1575
+ dummy_ok: false
1576
+ ).first
1577
+
1578
+ MU.log "Couldn't find existing resource #{ext_deploy["cloud_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
1579
+ @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: found.mu_name, triggering_node: @mu_name)
1580
+ elsif ext_deploy["mu_name"] && ext_deploy["deploy_id"]
1581
+ MU.log "#{ext_deploy["mu_name"]} / #{ext_deploy["deploy_id"]}"
1582
+ found = MU::MommaCat.findStray(
1583
+ @config['cloud'],
1584
+ ext_deploy["cloud_type"],
1585
+ deploy_id: ext_deploy["deploy_id"],
1586
+ mu_name: ext_deploy["mu_name"],
1587
+ region: @config['region'],
1588
+ dummy_ok: false
1589
+ ).first
1590
+
1591
+ MU.log "Couldn't find existing resource #{ext_deploy["mu_name"]}/#{ext_deploy["deploy_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
1592
+ @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: ext_deploy["mu_name"], triggering_node: @mu_name)
1593
+ else
1594
+ MU.log "Trying to find existing deploy, but either the cloud_id is not valid or no mu_name and deploy_id where provided", MU::ERR
1595
+ end
1596
+ }
1597
+ end
1598
+
1599
+ if @config['dns_records'] && !@config['dns_records'].empty?
1600
+ @config['dns_records'].each { |dnsrec|
1601
+ if dnsrec.has_key?("name")
1602
+ if dnsrec['name'].start_with?(@deploy.deploy_id.downcase) && !dnsrec['name'].start_with?(@mu_name.downcase)
1603
+ MU.log "DNS records for #{@mu_name} seem to be wrong, deleting from current config", MU::WARN, details: dnsrec
1604
+ dnsrec.delete('name')
1605
+ dnsrec.delete('target')
1606
+ end
1607
+ end
1608
+ }
1609
+ end
1610
+
1563
1611
  return [@dependencies, @vpc, @loadbalancers]
1564
1612
  end
1565
1613
 
1614
+ # Using the automatically-defined +@vpc+ from {dependencies} in
1615
+ # conjunction with our config, return our configured subnets.
1616
+ # @return [Array<MU::Cloud::VPC::Subnet>]
1617
+ def mySubnets
1618
+ dependencies
1619
+ if !@vpc or !@config["vpc"]
1620
+ return nil
1621
+ end
1622
+
1623
+ if @config["vpc"]["subnet_id"] or @config["vpc"]["subnet_name"]
1624
+ @config["vpc"]["subnets"] ||= []
1625
+ subnet_block = {}
1626
+ subnet_block["subnet_id"] = @config["vpc"]["subnet_id"] if @config["vpc"]["subnet_id"]
1627
+ subnet_block["subnet_name"] = @config["vpc"]["subnet_name"] if @config["vpc"]["subnet_name"]
1628
+ @config["vpc"]["subnets"] << subnet_block
1629
+ @config["vpc"]["subnets"].uniq!
1630
+ end
1631
+
1632
+ if (!@config["vpc"]["subnets"] or @config["vpc"]["subnets"].empty?) and
1633
+ !@config["vpc"]["subnet_id"]
1634
+ return @vpc.subnets
1635
+ end
1636
+
1637
+ subnets = []
1638
+ @config["vpc"]["subnets"].each { |subnet|
1639
+ subnet_obj = @vpc.getSubnet(cloud_id: subnet["subnet_id"].to_s, name: subnet["subnet_name"].to_s)
1640
+ raise MuError, "Couldn't find a live subnet for #{self.to_s} matching #{subnet} in #{@vpc.to_s} (#{@vpc.subnets.map { |s| s.name }.join(",")})" if subnet_obj.nil?
1641
+ subnets << subnet_obj
1642
+ }
1643
+
1644
+ subnets
1645
+ end
1646
+
1647
+ # @return [Array<MU::Cloud::FirewallRule>]
1648
+ def myFirewallRules
1649
+ dependencies
1650
+
1651
+ rules = []
1652
+ if @dependencies.has_key?("firewall_rule")
1653
+ rules = @dependencies['firewall_rule'].values
1654
+ end
1655
+ # XXX what other ways are these specified?
1656
+
1657
+ rules
1658
+ end
1659
+
1566
1660
  # Defaults any resources that don't declare their release-readiness to
1567
1661
  # ALPHA. That'll learn 'em.
1568
1662
  def self.quality
@@ -1668,13 +1762,13 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1668
1762
  def handleWindowsFail(e, retries, rebootable_fails, max_retries: 30, reboot_on_problems: false, retry_interval: 45)
1669
1763
  msg = "WinRM connection to https://"+@mu_name+":5986/wsman: #{e.message}, waiting #{retry_interval}s (attempt #{retries}/#{max_retries})"
1670
1764
  if e.class.name == "WinRM::WinRMAuthorizationError" or e.message.match(/execution expired/) and reboot_on_problems
1671
- if rebootable_fails > 0 and (rebootable_fails % 5) == 0
1765
+ if rebootable_fails > 0 and (rebootable_fails % 7) == 0
1672
1766
  MU.log "#{@mu_name} still misbehaving, forcing Stop and Start from API", MU::WARN
1673
1767
  reboot(true) # vicious API stop/start
1674
1768
  sleep retry_interval*3
1675
1769
  rebootable_fails = 0
1676
1770
  else
1677
- if rebootable_fails == 3
1771
+ if rebootable_fails == 5
1678
1772
  MU.log "#{@mu_name} misbehaving, attempting to reboot from API", MU::WARN
1679
1773
  reboot # graceful API restart
1680
1774
  sleep retry_interval*2
@@ -1900,7 +1994,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1900
1994
  # @param timeout [Integer]:
1901
1995
  # @param winrm_retries [Integer]:
1902
1996
  # @param reboot_on_problems [Boolean]:
1903
- def getWinRMSession(max_retries = 40, retry_interval = 60, timeout: 30, winrm_retries: 5, reboot_on_problems: false)
1997
+ def getWinRMSession(max_retries = 40, retry_interval = 60, timeout: 30, winrm_retries: 2, reboot_on_problems: false)
1904
1998
  _nat_ssh_key, _nat_ssh_user, _nat_ssh_host, canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
1905
1999
  @mu_name ||= @config['mu_name']
1906
2000
 
@@ -1924,7 +2018,8 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1924
2018
  retries = 0
1925
2019
  rebootable_fails = 0
1926
2020
  begin
1927
- MU.log "Calling WinRM on #{@mu_name}", MU::DEBUG, details: opts
2021
+ loglevel = retries > 4 ? MU::NOTICE : MU::DEBUG
2022
+ MU.log "Calling WinRM on #{@mu_name}", loglevel, details: opts
1928
2023
  opts = {
1929
2024
  endpoint: 'https://'+@mu_name+':5986/wsman',
1930
2025
  retry_limit: winrm_retries,
@@ -1932,10 +2027,16 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1932
2027
  ca_trust_path: "#{MU.mySSLDir}/Mu_CA.pem",
1933
2028
  transport: :ssl,
1934
2029
  operation_timeout: timeout,
1935
- client_cert: "#{MU.mySSLDir}/#{@mu_name}-winrm.crt",
1936
- client_key: "#{MU.mySSLDir}/#{@mu_name}-winrm.key"
1937
2030
  }
2031
+ if retries % 2 == 0
2032
+ opts[:user] = @config['windows_admin_username']
2033
+ opts[:password] = getWindowsAdminPassword
2034
+ else
2035
+ opts[:client_cert] = "#{MU.mySSLDir}/#{@mu_name}-winrm.crt"
2036
+ opts[:client_key] = "#{MU.mySSLDir}/#{@mu_name}-winrm.key"
2037
+ end
1938
2038
  conn = WinRM::Connection.new(opts)
2039
+ conn.logger.level = :debug if retries > 2
1939
2040
  MU.log "WinRM connection to #{@mu_name} created", MU::DEBUG, details: conn
1940
2041
  shell = conn.shell(:powershell)
1941
2042
  shell.run('ipconfig') # verify that we can do something
@@ -2069,10 +2170,10 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
2069
2170
  if params and params[:region]
2070
2171
  in_msg += " "+params[:region]
2071
2172
  end
2072
- if params and params[:flags] and params[:flags]["project"]
2173
+ if params and params[:flags] and params[:flags]["project"] and !params[:flags]["project"].empty?
2073
2174
  in_msg += " project "+params[:flags]["project"]
2074
2175
  end
2075
- MU.log "Skipping #{shortname} cleanup method in #{in_msg} due to exception: #{e.message}", MU::WARN, details: e.backtrace
2176
+ MU.log "Skipping #{shortname} cleanup method in #{in_msg} due to #{e.class.name}: #{e.message}", MU::WARN, details: e.backtrace
2076
2177
  ok = false
2077
2178
  end
2078
2179
  }