cloud-mu 3.1.4 → 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
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
  }