cloud-mu 3.1.2 → 3.2.0

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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +15 -3
  3. data/ansible/roles/mu-windows/README.md +33 -0
  4. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  5. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  6. data/ansible/roles/mu-windows/files/config.xml +76 -0
  7. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  8. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  9. data/ansible/roles/mu-windows/tasks/main.yml +36 -0
  10. data/ansible/roles/mu-windows/tests/inventory +2 -0
  11. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  12. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  13. data/bin/mu-adopt +10 -13
  14. data/bin/mu-azure-tests +57 -0
  15. data/bin/mu-cleanup +2 -4
  16. data/bin/mu-configure +52 -0
  17. data/bin/mu-deploy +3 -3
  18. data/bin/mu-findstray-tests +25 -0
  19. data/bin/mu-gen-docs +2 -4
  20. data/bin/mu-load-config.rb +2 -3
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +135 -37
  23. data/cloud-mu.gemspec +22 -20
  24. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  25. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  26. data/cookbooks/mu-tools/libraries/helper.rb +3 -2
  27. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  28. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  29. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  30. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  31. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  32. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  33. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  34. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  35. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  36. data/extras/clean-stock-amis +25 -19
  37. data/extras/generate-stock-images +1 -0
  38. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  39. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  40. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  41. data/extras/image-generators/Google/centos6.yaml +1 -0
  42. data/extras/image-generators/Google/centos7.yaml +1 -1
  43. data/modules/mommacat.ru +6 -16
  44. data/modules/mu.rb +165 -111
  45. data/modules/mu/adoption.rb +401 -68
  46. data/modules/mu/cleanup.rb +199 -306
  47. data/modules/mu/cloud.rb +100 -1632
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +46 -0
  50. data/modules/mu/cloud/machine_images.rb +212 -0
  51. data/modules/mu/cloud/providers.rb +81 -0
  52. data/modules/mu/cloud/resource_base.rb +920 -0
  53. data/modules/mu/cloud/server.rb +40 -0
  54. data/modules/mu/cloud/server_pool.rb +1 -0
  55. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  56. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  57. data/modules/mu/cloud/wrappers.rb +165 -0
  58. data/modules/mu/config.rb +171 -1767
  59. data/modules/mu/config/alarm.rb +2 -6
  60. data/modules/mu/config/bucket.rb +4 -4
  61. data/modules/mu/config/cache_cluster.rb +1 -1
  62. data/modules/mu/config/collection.rb +4 -4
  63. data/modules/mu/config/container_cluster.rb +9 -4
  64. data/modules/mu/config/database.rb +83 -104
  65. data/modules/mu/config/database.yml +1 -2
  66. data/modules/mu/config/dnszone.rb +6 -6
  67. data/modules/mu/config/doc_helpers.rb +516 -0
  68. data/modules/mu/config/endpoint.rb +4 -4
  69. data/modules/mu/config/firewall_rule.rb +103 -4
  70. data/modules/mu/config/folder.rb +4 -4
  71. data/modules/mu/config/function.rb +3 -3
  72. data/modules/mu/config/group.rb +4 -4
  73. data/modules/mu/config/habitat.rb +4 -4
  74. data/modules/mu/config/loadbalancer.rb +60 -14
  75. data/modules/mu/config/log.rb +4 -4
  76. data/modules/mu/config/msg_queue.rb +4 -4
  77. data/modules/mu/config/nosqldb.rb +4 -4
  78. data/modules/mu/config/notifier.rb +3 -3
  79. data/modules/mu/config/ref.rb +365 -0
  80. data/modules/mu/config/role.rb +4 -4
  81. data/modules/mu/config/schema_helpers.rb +509 -0
  82. data/modules/mu/config/search_domain.rb +4 -4
  83. data/modules/mu/config/server.rb +97 -70
  84. data/modules/mu/config/server.yml +1 -0
  85. data/modules/mu/config/server_pool.rb +5 -9
  86. data/modules/mu/config/storage_pool.rb +1 -1
  87. data/modules/mu/config/tail.rb +200 -0
  88. data/modules/mu/config/user.rb +4 -4
  89. data/modules/mu/config/vpc.rb +70 -27
  90. data/modules/mu/config/vpc.yml +0 -1
  91. data/modules/mu/defaults/AWS.yaml +83 -60
  92. data/modules/mu/defaults/Azure.yaml +1 -0
  93. data/modules/mu/defaults/Google.yaml +3 -2
  94. data/modules/mu/deploy.rb +30 -26
  95. data/modules/mu/groomer.rb +17 -2
  96. data/modules/mu/groomers/ansible.rb +188 -41
  97. data/modules/mu/groomers/chef.rb +116 -55
  98. data/modules/mu/logger.rb +127 -148
  99. data/modules/mu/master.rb +389 -2
  100. data/modules/mu/master/chef.rb +3 -4
  101. data/modules/mu/master/ldap.rb +3 -3
  102. data/modules/mu/master/ssl.rb +12 -3
  103. data/modules/mu/mommacat.rb +217 -2612
  104. data/modules/mu/mommacat/daemon.rb +397 -0
  105. data/modules/mu/mommacat/naming.rb +473 -0
  106. data/modules/mu/mommacat/search.rb +495 -0
  107. data/modules/mu/mommacat/storage.rb +722 -0
  108. data/modules/mu/{clouds → providers}/README.md +1 -1
  109. data/modules/mu/{clouds → providers}/aws.rb +271 -112
  110. data/modules/mu/{clouds → providers}/aws/alarm.rb +5 -3
  111. data/modules/mu/{clouds → providers}/aws/bucket.rb +26 -22
  112. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +33 -67
  113. data/modules/mu/{clouds → providers}/aws/collection.rb +24 -23
  114. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +681 -721
  115. data/modules/mu/providers/aws/database.rb +1744 -0
  116. data/modules/mu/{clouds → providers}/aws/dnszone.rb +64 -63
  117. data/modules/mu/{clouds → providers}/aws/endpoint.rb +22 -27
  118. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +214 -244
  119. data/modules/mu/{clouds → providers}/aws/folder.rb +7 -7
  120. data/modules/mu/{clouds → providers}/aws/function.rb +17 -22
  121. data/modules/mu/{clouds → providers}/aws/group.rb +23 -23
  122. data/modules/mu/{clouds → providers}/aws/habitat.rb +17 -14
  123. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +57 -48
  124. data/modules/mu/{clouds → providers}/aws/log.rb +15 -12
  125. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +17 -16
  126. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +18 -11
  127. data/modules/mu/{clouds → providers}/aws/notifier.rb +11 -6
  128. data/modules/mu/{clouds → providers}/aws/role.rb +112 -86
  129. data/modules/mu/{clouds → providers}/aws/search_domain.rb +39 -33
  130. data/modules/mu/{clouds → providers}/aws/server.rb +835 -1133
  131. data/modules/mu/{clouds → providers}/aws/server_pool.rb +56 -60
  132. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +24 -42
  133. data/modules/mu/{clouds → providers}/aws/user.rb +21 -22
  134. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  135. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
  136. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  137. data/modules/mu/{clouds → providers}/aws/vpc.rb +523 -929
  138. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  139. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  140. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  141. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  142. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  143. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  144. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  145. data/modules/mu/{clouds → providers}/azure/server.rb +95 -48
  146. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  147. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  148. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  149. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  150. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  151. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  152. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  153. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  154. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  155. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  156. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  160. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  161. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  162. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  163. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  164. data/modules/mu/{clouds → providers}/google.rb +67 -30
  165. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  166. data/modules/mu/{clouds → providers}/google/container_cluster.rb +84 -77
  167. data/modules/mu/{clouds → providers}/google/database.rb +10 -20
  168. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  169. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  170. data/modules/mu/{clouds → providers}/google/function.rb +139 -167
  171. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  172. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  173. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +18 -20
  174. data/modules/mu/{clouds → providers}/google/role.rb +92 -58
  175. data/modules/mu/{clouds → providers}/google/server.rb +242 -155
  176. data/modules/mu/{clouds → providers}/google/server_pool.rb +25 -44
  177. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  178. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  179. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  180. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  181. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  182. data/modules/tests/bucket.yml +4 -0
  183. data/modules/tests/centos6.yaml +11 -0
  184. data/modules/tests/centos7.yaml +11 -0
  185. data/modules/tests/centos8.yaml +12 -0
  186. data/modules/tests/ecs.yaml +23 -0
  187. data/modules/tests/includes-and-params.yaml +2 -1
  188. data/modules/tests/rds.yaml +108 -0
  189. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  190. data/modules/tests/regrooms/bucket.yml +19 -0
  191. data/modules/tests/regrooms/rds.yaml +123 -0
  192. data/modules/tests/server-with-scrub-muisms.yaml +1 -0
  193. data/modules/tests/super_simple_bok.yml +1 -3
  194. data/modules/tests/win2k12.yaml +17 -5
  195. data/modules/tests/win2k16.yaml +25 -0
  196. data/modules/tests/win2k19.yaml +25 -0
  197. data/requirements.txt +1 -0
  198. data/spec/mu/clouds/azure_spec.rb +2 -2
  199. metadata +232 -154
  200. data/extras/image-generators/AWS/windows.yaml +0 -18
  201. data/modules/mu/clouds/aws/database.rb +0 -1985
@@ -15,7 +15,7 @@ action :create do
15
15
  devicename = device
16
16
 
17
17
  if set_gcp_cfg_params
18
- devicename.gsub!(/.*?\//, "")
18
+ devicename= devicename.gsub(/.*?\//, "")
19
19
  device = "/dev/disk/by-id/google-"+devicename
20
20
  end
21
21
 
@@ -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
@@ -18,37 +18,43 @@ require 'json'
18
18
  require File.realpath(File.expand_path(File.dirname(__FILE__)+"/../bin/mu-load-config.rb"))
19
19
  require 'mu'
20
20
 
21
- credentials = if ARGV[0] and !ARGV[0].empty?
22
- ARGV[0]
23
- else
24
- nil
21
+ $opts = Optimist::options do
22
+ banner <<-EOS
23
+ #{$0} [-c credentials] [-i imagename]
24
+ EOS
25
+ opt :credentials, "Use these AWS credentials from mu.yaml instead of the default set", :required => false, :type => :string
26
+ opt :image, "Purge a specific image, instead of just scrubing old ones", :required => false, :type => :string
25
27
  end
26
28
 
27
29
  filters = [
28
30
  {
29
31
  name: "owner-id",
30
- values: [MU::Cloud::AWS.credToAcct(credentials)]
32
+ values: [MU::Cloud::AWS.credToAcct($opts[:credentials])]
31
33
  }
32
34
  ]
33
35
 
34
36
 
35
37
  MU::Cloud::AWS.listRegions.each { | r|
36
- images = MU::Cloud::AWS.ec2(region: r, credentials: credentials).describe_images(
38
+ images = MU::Cloud::AWS.ec2(region: r, credentials: $opts[:credentials]).describe_images(
37
39
  filters: filters + [{ "name" => "state", "values" => ["available"]}]
38
40
  ).images
39
41
  images.each { |ami|
40
- if (DateTime.now.to_time - DateTime.parse(ami.creation_date).to_time) > 15552000 and ami.name.match(/^MU-(PROD|DEV)/)
41
- snaps = []
42
- ami.block_device_mappings.each { |dev|
43
- if !dev.ebs.nil?
44
- snaps << dev.ebs.snapshot_id
45
- end
46
- }
47
- MU.log "Deregistering #{ami.name} (#{ami.creation_date})", MU::WARN, details: snaps
48
- MU::Cloud::AWS.ec2(region: r, credentials: credentials).deregister_image(image_id: ami.image_id)
49
- snaps.each { |snap_id|
50
- MU::Cloud::AWS.ec2(region: r, credentials: credentials).delete_snapshot(snapshot_id: snap_id)
51
- }
52
- end
42
+ if ($opts[:image] and ami.name == $opts[:image]) or
43
+ ((DateTime.now.to_time - DateTime.parse(ami.creation_date).to_time) > 15552000 and ami.name.match(/^MU-(PROD|DEV)/))
44
+ snaps = []
45
+ ami.block_device_mappings.each { |dev|
46
+ if !dev.ebs.nil?
47
+ snaps << dev.ebs.snapshot_id
48
+ end
49
+ }
50
+ MU.log "Deregistering #{ami.name}, #{r} (#{ami.creation_date})", MU::WARN, details: snaps
51
+ begin
52
+ MU::Cloud::AWS.ec2(region: r, credentials: $opts[:credentials]).deregister_image(image_id: ami.image_id)
53
+ rescue Aws::EC2::Errors::InvalidAMIIDUnavailable
54
+ end
55
+ snaps.each { |snap_id|
56
+ MU::Cloud::AWS.ec2(region: r, credentials: $opts[:credentials]).delete_snapshot(snapshot_id: snap_id)
57
+ }
58
+ end
53
59
  }
54
60
  }
@@ -91,6 +91,7 @@ $opts[:clouds].each { |cloud|
91
91
  end
92
92
  next if !needed
93
93
  end
94
+ MU.log "Loading "+bok_dir+"/"+cloud+"/"+platform+".yaml"
94
95
  conf_engine = MU::Config.new(
95
96
  bok_dir+"/"+cloud+"/"+platform+".yaml",
96
97
  default_credentials: $opts[(cloud.downcase+"_creds").to_sym]
@@ -1,16 +1,21 @@
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
+ ansible_vars:
16
+ mu_build_image: true
17
+ create_image:
18
+ image_then_destroy: true
19
+ public: true
20
+ copy_to_regions:
21
+ - "#ALL"
@@ -1,16 +1,21 @@
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
+ ansible_vars:
16
+ mu_build_image: true
17
+ create_image:
18
+ image_then_destroy: true
19
+ public: true
20
+ copy_to_regions:
21
+ - "#ALL"
@@ -0,0 +1,21 @@
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
+ ansible_vars:
16
+ mu_build_image: true
17
+ create_image:
18
+ image_then_destroy: true
19
+ public: true
20
+ copy_to_regions:
21
+ - "#ALL"
@@ -16,3 +16,4 @@
16
16
  create_image:
17
17
  image_then_destroy: true
18
18
  public: true
19
+ family: mu-centos-6
@@ -4,7 +4,6 @@
4
4
  - name: centos7
5
5
  cloud: Google
6
6
  image_id: "centos-cloud/centos-7"
7
- platform: centos6
8
7
  ssh_user: centos
9
8
  size: g1-small
10
9
  associate_public_ip: true
@@ -16,3 +15,4 @@
16
15
  create_image:
17
16
  image_then_destroy: true
18
17
  public: true
18
+ family: mu-centos-7
@@ -16,7 +16,7 @@ require 'pp'
16
16
  require 'base64'
17
17
  require 'etc'
18
18
 
19
- home = Etc.getpwuid(Process.uid).dir
19
+ Etc.getpwuid(Process.uid).dir
20
20
 
21
21
  if !ENV.include?('MU_INSTALLDIR')
22
22
  ENV['MU_INSTALLDIR'] = "/opt/mu"
@@ -51,8 +51,8 @@ Signal.trap("URG") do
51
51
  end
52
52
 
53
53
  begin
54
- MU::MommaCat.syncMonitoringConfig(false)
55
- rescue Exception => e
54
+ MU::Master.syncMonitoringConfig(false)
55
+ rescue StandardError => e
56
56
  MU.log e.inspect, MU::ERR, details: e.backtrace
57
57
  # ...but don't die!
58
58
  end
@@ -64,14 +64,12 @@ Thread.new {
64
64
  MU::MommaCat.cleanTerminatedInstances
65
65
  MU::Master.cleanExpiredScratchpads if $ENABLE_SCRATCHPAD
66
66
  sleep 60
67
- rescue Exception => e
67
+ rescue StandardError => e
68
68
  MU.log "Error in cleanTerminatedInstances thread: #{e.inspect}", MU::ERR, details: e.backtrace
69
69
  retry
70
70
  end while true
71
71
  }
72
72
 
73
- required_vars = ["mu_id", "mu_deploy_secret", "mu_resource_name", "mu_resource_type", "mu_instance_id"]
74
-
75
73
  # Use a template to generate a pleasant-looking HTML page for simple messages
76
74
  # and errors.
77
75
  def genHTMLMessage(title: "", headline: "", msg: "", template: $MU_CFG['html_template'], extra_vars: {})
@@ -193,7 +191,6 @@ def releaseKitten(mu_id)
193
191
  end
194
192
 
195
193
  app = proc do |env|
196
- ok = false
197
194
  returnval = [
198
195
  200,
199
196
  {
@@ -318,7 +315,7 @@ app = proc do |env|
318
315
  elsif !filter or !path
319
316
  returnval = throw404 env['REQUEST_PATH']
320
317
  else
321
- MU::MommaCat.addInstanceToEtcHosts(path, filter)
318
+ MU::Master.addInstanceToEtcHosts(path, filter)
322
319
  returnval = [
323
320
  200,
324
321
  {
@@ -356,7 +353,6 @@ app = proc do |env|
356
353
 
357
354
  elsif !env["rack.input"].nil?
358
355
  req = Rack::Utils.parse_nested_query(env["rack.input"].read)
359
- ok = true
360
356
 
361
357
  if req["mu_user"].nil?
362
358
  req["mu_user"] = "mu"
@@ -373,7 +369,6 @@ app = proc do |env|
373
369
  kittenpile = getKittenPile(req)
374
370
  if kittenpile.nil? or kittenpile.original_config.nil? or kittenpile.original_config[req["mu_resource_type"]+"s"].nil?
375
371
  returnval = throw500 "Couldn't find config data for #{req["mu_resource_type"]} in deploy_id #{req["mu_id"]}"
376
- ok = false
377
372
  next
378
373
  end
379
374
  server_cfg = nil
@@ -385,7 +380,6 @@ app = proc do |env|
385
380
  }
386
381
  if server_cfg.nil?
387
382
  returnval = throw500 "Couldn't find config data for #{req["mu_resource_type"]} name: #{req["mu_resource_name"]} deploy_id: #{req["mu_id"]}"
388
- ok = false
389
383
  next
390
384
  end
391
385
 
@@ -426,7 +420,6 @@ MU.log "ADDVOLUME REQUEST", MU::WARN, details: params
426
420
  instance.addVolume(params["dev"], params["size"], delete_on_termination: params["delete_on_termination"])
427
421
  else
428
422
  returnval = throw500 "I don't know how to add a volume for #{instance}"
429
- ok = false
430
423
  end
431
424
  elsif !instance.nil?
432
425
  if !req["mu_bootstrap"].nil?
@@ -434,16 +427,13 @@ MU.log "ADDVOLUME REQUEST", MU::WARN, details: params
434
427
  returnval[2] = ["Grooming asynchronously, check Momma Cat logs on the master for details."]
435
428
  else
436
429
  returnval = throw500 "Didn't get 'mu_bootstrap' parameter from instance id '#{req["mu_instance_id"]}'"
437
- ok = false
438
430
  end
439
431
  else
440
432
  returnval = throw500 "No such instance id '#{req["mu_instance_id"]}' nor was this an SSL signing request"
441
- ok = false
442
433
  end
443
434
  end
444
- rescue Exception => e
435
+ rescue StandardError => e
445
436
  returnval = throw500 "Invalid request: #{e.inspect} (#{req})", e.backtrace
446
- ok = false
447
437
  ensure
448
438
  if !req.nil?
449
439
  releaseKitten(req['mu_id'])
@@ -79,38 +79,40 @@ class Hash
79
79
  }
80
80
  return 0 if self == other # that was easy!
81
81
  # compare elements and decide who's "bigger" based on their totals?
82
- 0
82
+
83
+ # fine, try some brute force and just hope everything implements to_s
84
+ self.flatten.map { |e| e.to_s }.join() <=> other.flatten.map { |e| e.to_s }.join()
83
85
  end
84
86
 
85
- # Recursively compare two hashes
86
- def diff(with, on = self, level: 0, parents: [])
87
+ # Recursively compare two Mu Basket of Kittens hashes and report the differences
88
+ def diff(with, on = self, level: 0, parents: [], report: {}, habitat: nil)
87
89
  return if with.nil? and on.nil?
88
90
  if with.nil? or on.nil? or with.class != on.class
89
91
  return # XXX ...however we're flagging differences
90
92
  end
91
93
  return if on == with
92
94
 
93
- tree = ""
94
- indentsize = 0
95
- parents.each { |p|
96
- tree += (" " * indentsize) + p + " => \n"
97
- indentsize += 2
98
- }
99
- indent = (" " * indentsize)
100
-
101
95
  changes = []
96
+ report ||= {}
102
97
  if on.is_a?(Hash)
103
98
  on_unique = (on.keys - with.keys)
104
99
  with_unique = (with.keys - on.keys)
105
100
  shared = (with.keys & on.keys)
106
101
  shared.each { |k|
107
- diff(with[k], on[k], level: level+1, parents: parents + [k])
102
+
103
+ report_data = diff(with[k], on[k], level: level+1, parents: parents + [k], report: report[k], habitat: habitat)
104
+ if report_data and !report_data.empty?
105
+ report ||= {}
106
+ report[k] = report_data
107
+ end
108
108
  }
109
109
  on_unique.each { |k|
110
- changes << "- ".red+PP.pp({k => on[k] }, '')
110
+ report[k] = { :action => :removed, :parents => parents, :value => on[k].clone }
111
+ report[k][:habitat] = habitat if habitat
111
112
  }
112
113
  with_unique.each { |k|
113
- changes << "+ ".green+PP.pp({k => with[k]}, '')
114
+ report[k] = { :action => :added, :parents => parents, :value => with[k].clone }
115
+ report[k][:habitat] = habitat if habitat
114
116
  }
115
117
  elsif on.is_a?(Array)
116
118
  return if with == on
@@ -121,34 +123,28 @@ class Hash
121
123
  # custom objects which we might find in here so that we can get away with
122
124
  # sorting arrays full of weird, non-primitive types.
123
125
  done = []
124
- # before_a = on.dup
125
- # after_a = on.dup.sort
126
- # before_b = with.dup
127
- # after_b = with.dup.sort
128
126
  on.sort.each { |elt|
129
- if elt.is_a?(Hash) and elt['name'] or elt['entity']# or elt['cloud_id']
127
+ if elt.is_a?(Hash) and !MU::MommaCat.getChunkName(elt).first.nil?
128
+ elt_namestr, elt_location, elt_location_list = MU::MommaCat.getChunkName(elt)
129
+
130
130
  with.sort.each { |other_elt|
131
- if (elt['name'] and other_elt['name'] == elt['name']) or
132
- (elt['name'].nil? and !elt["id"].nil? and elt["id"] == other_elt["id"]) or
133
- (elt['name'].nil? and elt["id"].nil? and
134
- !elt["entity"].nil? and !other_elt["entity"].nil? and
135
- (
136
- (elt["entity"]["id"] and elt["entity"]["id"] == other_elt["entity"]["id"]) or
137
- (elt["entity"]["name"] and elt["entity"]["name"] == other_elt["entity"]["name"])
138
- )
131
+ other_elt_namestr, other_elt_location, other_elt_location_list = MU::MommaCat.getChunkName(other_elt)
132
+
133
+ # Case 1: The array element exists in both version of this array
134
+ if elt_namestr and other_elt_namestr and
135
+ elt_namestr == other_elt_namestr and
136
+ (elt_location.nil? or other_elt_location.nil? or
137
+ elt_location == other_elt_location or
138
+ !(elt_location_list & other_elt_location_list).empty?
139
139
  )
140
- break if elt == other_elt
141
140
  done << elt
142
141
  done << other_elt
143
- namestr = if elt['type']
144
- "#{elt['type']}[#{elt['name']}]"
145
- elsif elt['name']
146
- elt['name']
147
- elsif elt['entity'] and elt["entity"]["id"]
148
- elt['entity']['id']
142
+ break if elt == other_elt # if they're identical, we're done
143
+ report_data = diff(other_elt, elt, level: level+1, parents: parents + [elt_namestr], habitat: (elt_location || habitat))
144
+ if report_data and !report_data.empty?
145
+ report ||= {}
146
+ report[elt_namestr] = report_data
149
147
  end
150
-
151
- diff(other_elt, elt, level: level+1, parents: parents + [namestr])
152
148
  break
153
149
  end
154
150
  }
@@ -156,43 +152,34 @@ class Hash
156
152
  }
157
153
  on_unique = (on - with) - done
158
154
  with_unique = (with - on) - done
159
- # if on_unique.size > 0 or with_unique.size > 0
160
- # if before_a != after_a
161
- # MU.log "A BEFORE", MU::NOTICE, details: before_a
162
- # MU.log "A AFTER", MU::NOTICE, details: after_a
163
- # end
164
- # if before_b != after_b
165
- # MU.log "B BEFORE", MU::NOTICE, details: before_b
166
- # MU.log "B AFTER", MU::NOTICE, details: after_b
167
- # end
168
- # end
155
+
156
+ # Case 2: This array entry exists in the old version, but not the new one
169
157
  on_unique.each { |e|
170
- changes << if e.is_a?(Hash)
171
- "- ".red+PP.pp(Hash.bok_minimize(e), '').gsub(/\n/, "\n "+(indent))
172
- else
173
- "- ".red+e.to_s
174
- end
158
+ namestr, loc = MU::MommaCat.getChunkName(e)
159
+
160
+ report ||= {}
161
+ report[namestr] = { :action => :removed, :parents => parents, :value => e.clone }
162
+ report[namestr][:habitat] = loc if loc
175
163
  }
164
+
165
+ # Case 3: This array entry exists in the new version, but not the old one
176
166
  with_unique.each { |e|
177
- changes << if e.is_a?(Hash)
178
- "+ ".green+PP.pp(Hash.bok_minimize(e), '').gsub(/\n/, "\n "+(indent))
179
- else
180
- "+ ".green+e.to_s
181
- end
167
+ namestr, loc = MU::MommaCat.getChunkName(e)
168
+
169
+ report ||= {}
170
+ report[namestr] = { :action => :added, :parents => parents, :value => e.clone }
171
+ report[namestr][:habitat] = loc if loc
182
172
  }
173
+
174
+ # A plain old leaf node of data
183
175
  else
184
176
  if on != with
185
- changes << "-".red+" #{on.to_s}"
186
- changes << "+".green+" #{with.to_s}"
177
+ report = { :action => :changed, :parents => parents, :oldvalue => on, :value => with.clone }
178
+ report[:habitat] = habitat if habitat
187
179
  end
188
180
  end
189
181
 
190
- if changes.size > 0
191
- puts tree
192
- changes.each { |c|
193
- puts indent+c
194
- }
195
- end
182
+ report.freeze
196
183
  end
197
184
 
198
185
  # Implement a merge! that just updates each hash leaf as needed, not
@@ -216,8 +203,29 @@ class Hash
216
203
  end
217
204
 
218
205
  ENV['HOME'] = Etc.getpwuid(Process.uid).dir
206
+ module MU
207
+
208
+ # For log entries that should only be logged when we're in verbose mode
209
+ DEBUG = 0.freeze
210
+ # For ordinary log entries
211
+ INFO = 1.freeze
212
+ # For more interesting log entries which are not errors
213
+ NOTICE = 2.freeze
214
+ # Log entries for non-fatal errors
215
+ WARN = 3.freeze
216
+ # Log entries for non-fatal errors
217
+ WARNING = 3.freeze
218
+ # Log entries for fatal errors
219
+ ERR = 4.freeze
220
+ # Log entries for fatal errors
221
+ ERROR = 4.freeze
222
+ # Log entries that will be held and displayed/emailed at the end of deploy,
223
+ # cleanup, etc.
224
+ SUMMARY = 5.freeze
225
+ end
219
226
 
220
227
  require 'mu/logger'
228
+
221
229
  module MU
222
230
 
223
231
  # Subclass core thread so we can gracefully handle it when we hit system
@@ -267,6 +275,7 @@ module MU
267
275
  end while newguy.nil?
268
276
 
269
277
  @@mu_global_thread_semaphore.synchronize {
278
+ MU.dupGlobals(Thread.current.object_id, target_thread: newguy)
270
279
  @@mu_global_threads << newguy
271
280
  }
272
281
 
@@ -276,8 +285,9 @@ module MU
276
285
  # Wrapper class for fatal Exceptions. Gives our internals something to
277
286
  # inherit that will log an error message appropriately before bubbling up.
278
287
  class MuError < StandardError
279
- def initialize(message = nil)
280
- MU.log message, MU::ERR, details: caller[2] if !message.nil?
288
+ def initialize(message = nil, silent: false, details: nil)
289
+ details ||= caller[2]
290
+ MU.log message, MU::ERR, details: details if !message.nil? and !silent
281
291
  if MU.verbosity == MU::Logger::SILENT
282
292
  super ""
283
293
  else
@@ -289,8 +299,8 @@ module MU
289
299
  # Wrapper class for temporary Exceptions. Gives our internals something to
290
300
  # inherit that will log a notice message appropriately before bubbling up.
291
301
  class MuNonFatal < StandardError
292
- def initialize(message = nil)
293
- MU.log message, MU::NOTICE if !message.nil?
302
+ def initialize(message = nil, silent: false)
303
+ MU.log message, MU::NOTICE if !message.nil? and !silent
294
304
  if MU.verbosity == MU::Logger::SILENT
295
305
  super ""
296
306
  else
@@ -299,6 +309,68 @@ module MU
299
309
  end
300
310
  end
301
311
 
312
+ # Boilerplate retry block executor, for making cloud API calls which might
313
+ # fail transiently.
314
+ #
315
+ # @param catchme [Array<Exception>]: Exception classes which should be caught and retried
316
+ # @param wait [Integer]: Number of seconds to wait between retries
317
+ # @param max [Integer]: Maximum number of retries; if less than 1, will retry indefinitely
318
+ # @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).
319
+ # @param on_retry [Proc]: Optional block of code to invoke during retries
320
+ # @param always [Proc]: Optional block of code to invoke before returning or failing, a bit like +ensure+
321
+ # @param loop_if [Proc]: Optional block of code to invoke which will cause our block to be rerun until true
322
+ # @param loop_msg [String]: Message to display every third attempt
323
+ def self.retrier(catchme = nil, wait: 30, max: 0, ignoreme: [], on_retry: nil, always: nil, loop_if: nil, loop_msg: nil)
324
+
325
+ loop_if ||= Proc.new { false }
326
+
327
+ retries = 0
328
+ begin
329
+ retries += 1
330
+ loglevel = ((retries % 3) == 0) ? MU::NOTICE : MU::DEBUG
331
+ log_attempts = retries.to_s
332
+ log_attempts += (max > 0 ? "/"+max.to_s : "")
333
+ yield(retries, wait) if block_given?
334
+ if loop_if.call
335
+ MU.log loop_msg, loglevel, details: log_attempts if loop_msg
336
+ sleep wait
337
+ end
338
+ rescue StandardError => e
339
+ if catchme and catchme.include?(e.class)
340
+ if max > 0 and retries >= max
341
+ always.call if always and always.is_a?(Proc)
342
+ if ignoreme.include?(e.class)
343
+ return
344
+ else
345
+ raise e
346
+ end
347
+ end
348
+
349
+ if on_retry and on_retry.is_a?(Proc)
350
+ on_retry.call(e)
351
+ end
352
+
353
+ if retries == max-1
354
+ MU.log e.message, MU::WARN, details: caller
355
+ sleep wait # wait extra on the final attempt
356
+ else
357
+ MU.log e.message, loglevel, details: log_attempts
358
+ end
359
+
360
+ sleep wait
361
+ retry
362
+ elsif ignoreme and ignoreme.include?(e.class)
363
+ always.call if always and always.is_a?(Proc)
364
+ return
365
+ else
366
+ always.call if always and always.is_a?(Proc)
367
+ raise e
368
+ end
369
+ end while loop_if.call and (max < 1 or retries < max)
370
+
371
+ always.call if always and always.is_a?(Proc)
372
+ end
373
+
302
374
  if !ENV.has_key?("MU_LIBDIR") and ENV.has_key?("MU_INSTALLDIR")
303
375
  ENV['MU_LIBDIR'] = ENV['MU_INSTALLDIR']+"/lib"
304
376
  else
@@ -349,6 +421,13 @@ module MU
349
421
 
350
422
  if Gem.paths and Gem.paths.home and File.dirname(__FILE__).match(/^#{Gem.paths.home}/)
351
423
  @in_gem = true
424
+ elsif Gem.paths and Gem.paths.path and !Gem.paths.path.empty?
425
+ Gem.paths.path.each { |p|
426
+ if File.dirname(__FILE__).match(/^#{Regexp.quote(p)}/)
427
+ @in_gem = true
428
+ end
429
+ }
430
+ @in_gem = false if !defined? @in_gem
352
431
  else
353
432
  @in_gem = false
354
433
  end
@@ -391,20 +470,20 @@ module MU
391
470
  @@global_var_semaphore = Mutex.new
392
471
 
393
472
  # Set one of our global per-thread variables.
394
- def self.setVar(name, value)
473
+ def self.setVar(name, value, target_thread: Thread.current)
395
474
  @@global_var_semaphore.synchronize {
396
- @@globals[Thread.current.object_id] ||= Hash.new
397
- @@globals[Thread.current.object_id][name] ||= Hash.new
398
- @@globals[Thread.current.object_id][name] = value
475
+ @@globals[target_thread.object_id] ||= Hash.new
476
+ @@globals[target_thread.object_id][name] ||= Hash.new
477
+ @@globals[target_thread.object_id][name] = value
399
478
  }
400
479
  end
401
480
 
402
481
  # Copy the set of global variables in use by another thread, typically our
403
482
  # parent thread.
404
- def self.dupGlobals(parent_thread_id)
483
+ def self.dupGlobals(parent_thread_id, target_thread: Thread.current)
405
484
  @@globals[parent_thread_id] ||= {}
406
485
  @@globals[parent_thread_id].each_pair { |name, value|
407
- setVar(name, value)
486
+ setVar(name, value, target_thread: target_thread)
408
487
  }
409
488
  end
410
489
 
@@ -532,9 +611,10 @@ module MU
532
611
  end
533
612
 
534
613
  # Shortcut to invoke {MU::Logger#log}
535
- def self.log(msg, level = MU::INFO, details: nil, html: false, verbosity: nil, color: true)
614
+ def self.log(msg, level = MU::INFO, shorthand_details = nil, details: nil, html: false, verbosity: nil, color: true)
536
615
  return if (level == MU::DEBUG and verbosity and verbosity <= MU::Logger::LOUD)
537
616
  return if verbosity and verbosity == MU::Logger::SILENT
617
+ details ||= shorthand_details
538
618
 
539
619
  if (level == MU::ERR or
540
620
  level == MU::WARN or
@@ -553,25 +633,6 @@ module MU
553
633
  @@logger.log(msg, level, details: details, html: html, verbosity: verbosity, color: color)
554
634
  end
555
635
 
556
- # For log entries that should only be logged when we're in verbose mode
557
- DEBUG = 0.freeze
558
- # For ordinary log entries
559
- INFO = 1.freeze
560
- # For more interesting log entries which are not errors
561
- NOTICE = 2.freeze
562
- # Log entries for non-fatal errors
563
- WARN = 3.freeze
564
- # Log entries for non-fatal errors
565
- WARNING = 3.freeze
566
- # Log entries for fatal errors
567
- ERR = 4.freeze
568
- # Log entries for fatal errors
569
- ERROR = 4.freeze
570
- # Log entries that will be held and displayed/emailed at the end of deploy,
571
- # cleanup, etc.
572
- SUMMARY = 5.freeze
573
-
574
-
575
636
  autoload :Cleanup, 'mu/cleanup'
576
637
  autoload :Deploy, 'mu/deploy'
577
638
  autoload :MommaCat, 'mu/mommacat'
@@ -585,7 +646,7 @@ module MU
585
646
  new_cfg = $MU_CFG.dup
586
647
  examples = {}
587
648
  MU::Cloud.supportedClouds.each { |cloud|
588
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
649
+ cloudclass = MU::Cloud.cloudClass(cloud)
589
650
  begin
590
651
  if cloudclass.hosted? and !$MU_CFG[cloud.downcase]
591
652
  cfg_blob = cloudclass.hosted_config
@@ -642,7 +703,7 @@ module MU
642
703
  !$MU_CFG['public_address'].empty? and @@my_public_ip != $MU_CFG['public_address']
643
704
  @@mu_public_addr = $MU_CFG['public_address']
644
705
  if !@@mu_public_addr.match(/^\d+\.\d+\.\d+\.\d+$/)
645
- hostname = IO.readlines("/etc/hostname")[0].gsub /\n/, ''
706
+ hostname = IO.readlines("/etc/hostname")[0].gsub(/\n/, '')
646
707
 
647
708
  hostlines = File.open('/etc/hosts').grep(/.*#{hostname}.*/)
648
709
  if hostlines and !hostlines.empty?
@@ -741,11 +802,7 @@ module MU
741
802
  # @param groomer [String]: The grooming agent to load.
742
803
  # @return [Class]: The class object implementing this groomer agent
743
804
  def self.loadGroomer(groomer)
744
- if !File.size?(MU.myRoot+"/modules/mu/groomers/#{groomer.downcase}.rb")
745
- raise MuError, "Requested to use unsupported grooming agent #{groomer}"
746
- end
747
- require "mu/groomers/#{groomer.downcase}"
748
- return Object.const_get("MU").const_get("Groomer").const_get(groomer)
805
+ MU::Groomer.loadGroomer(groomer)
749
806
  end
750
807
 
751
808
  @@myRegion_var = nil
@@ -899,8 +956,7 @@ module MU
899
956
 
900
957
  @@myCloudDescriptor = nil
901
958
  if MU.myCloud
902
- svrclass = const_get("MU").const_get("Cloud").const_get(MU.myCloud).const_get("Server")
903
- found = svrclass.find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
959
+ found = MU::Cloud.resourceClass(MU.myCloud, "Server").find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
904
960
  # found = MU::MommaCat.findStray(MU.myCloud, "server", cloud_id: @@myInstanceId, dummy_ok: true, region: MU.myRegion)
905
961
  if !found.nil? and found.size == 1
906
962
  @@myCloudDescriptor = found.values.first
@@ -913,8 +969,7 @@ module MU
913
969
  def self.myVPCObj
914
970
  return nil if MU.myCloud.nil?
915
971
  return @@myVPCObj_var if @@myVPCObj_var
916
- cloudclass = const_get("MU").const_get("Cloud").const_get(MU.myCloud)
917
- @@myVPCObj_var ||= cloudclass.myVPCObj
972
+ @@myVPCObj_var ||= MU::Cloud.cloudClass(MU.myCloud).myVPCObj
918
973
  @@myVPCObj_var
919
974
  end
920
975
 
@@ -1012,15 +1067,15 @@ module MU
1012
1067
 
1013
1068
  # Generate a random password which will satisfy the complexity requirements of stock Amazon Windows AMIs.
1014
1069
  # return [String]: A password string.
1015
- def self.generateWindowsPassword(safe_pattern: '~!@#%^&*_-+=`|(){}[]:;<>,.?', retries: 25)
1070
+ def self.generateWindowsPassword(safe_pattern: '~!@#%^&*_-+=`|(){}[]:;<>,.?', retries: 50)
1016
1071
  # We have dopey complexity requirements, be stringent here.
1017
1072
  # I'll be nice and not condense this into one elegant-but-unreadable regular expression
1018
1073
  attempts = 0
1019
1074
  safe_metachars = Regexp.escape(safe_pattern)
1020
1075
  begin
1021
1076
  if attempts > retries
1022
- MU.log "Failed to generate an adequate Windows password after #{attempts}", MU::ERR
1023
- raise MuError, "Failed to generate an adequate Windows password after #{attempts}"
1077
+ MU.log "Failed to generate an adequate Windows password after #{attempts} attempts", MU::ERR
1078
+ raise MuError, "Failed to generate an adequate Windows password after #{attempts} attempts"
1024
1079
  end
1025
1080
  winpass = Password.random(14..16)
1026
1081
  attempts += 1
@@ -1039,10 +1094,9 @@ module MU
1039
1094
 
1040
1095
  clouds = platform.nil? ? MU::Cloud.supportedClouds : [platform]
1041
1096
  clouds.each { |cloud|
1042
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
1043
- bucketname = cloudclass.adminBucketName(credentials)
1097
+ bucketname = MU::Cloud.cloudClass(cloud).adminBucketName(credentials)
1044
1098
  begin
1045
- if platform or (cloudclass.hosted? and platform.nil?) or cloud == MU::Config.defaultCloud
1099
+ if platform or (MU::Cloud.cloudClass(cloud).hosted? and platform.nil?) or cloud == MU::Config.defaultCloud
1046
1100
  return bucketname
1047
1101
  end
1048
1102
  end