cloud-mu 3.1.2 → 3.2.0

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