cloud-mu 3.1.3 → 3.3.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 (212) 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 +21 -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 +4 -4
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +147 -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 +158 -111
  45. data/modules/mu/adoption.rb +404 -71
  46. data/modules/mu/cleanup.rb +221 -306
  47. data/modules/mu/cloud.rb +129 -1633
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +44 -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 +926 -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 +169 -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 +32 -3
  61. data/modules/mu/config/cache_cluster.rb +2 -2
  62. data/modules/mu/config/cdn.rb +100 -0
  63. data/modules/mu/config/collection.rb +4 -4
  64. data/modules/mu/config/container_cluster.rb +9 -4
  65. data/modules/mu/config/database.rb +84 -105
  66. data/modules/mu/config/database.yml +1 -2
  67. data/modules/mu/config/dnszone.rb +10 -9
  68. data/modules/mu/config/doc_helpers.rb +516 -0
  69. data/modules/mu/config/endpoint.rb +5 -4
  70. data/modules/mu/config/firewall_rule.rb +103 -4
  71. data/modules/mu/config/folder.rb +4 -4
  72. data/modules/mu/config/function.rb +19 -10
  73. data/modules/mu/config/group.rb +4 -4
  74. data/modules/mu/config/habitat.rb +4 -4
  75. data/modules/mu/config/job.rb +89 -0
  76. data/modules/mu/config/loadbalancer.rb +60 -14
  77. data/modules/mu/config/log.rb +4 -4
  78. data/modules/mu/config/msg_queue.rb +4 -4
  79. data/modules/mu/config/nosqldb.rb +4 -4
  80. data/modules/mu/config/notifier.rb +10 -21
  81. data/modules/mu/config/ref.rb +411 -0
  82. data/modules/mu/config/role.rb +4 -4
  83. data/modules/mu/config/schema_helpers.rb +509 -0
  84. data/modules/mu/config/search_domain.rb +4 -4
  85. data/modules/mu/config/server.rb +98 -71
  86. data/modules/mu/config/server.yml +1 -0
  87. data/modules/mu/config/server_pool.rb +5 -9
  88. data/modules/mu/config/storage_pool.rb +1 -1
  89. data/modules/mu/config/tail.rb +200 -0
  90. data/modules/mu/config/user.rb +4 -4
  91. data/modules/mu/config/vpc.rb +71 -27
  92. data/modules/mu/config/vpc.yml +0 -1
  93. data/modules/mu/defaults/AWS.yaml +91 -68
  94. data/modules/mu/defaults/Azure.yaml +1 -0
  95. data/modules/mu/defaults/Google.yaml +3 -2
  96. data/modules/mu/deploy.rb +43 -26
  97. data/modules/mu/groomer.rb +17 -2
  98. data/modules/mu/groomers/ansible.rb +188 -41
  99. data/modules/mu/groomers/chef.rb +116 -55
  100. data/modules/mu/logger.rb +127 -148
  101. data/modules/mu/master.rb +410 -2
  102. data/modules/mu/master/chef.rb +3 -4
  103. data/modules/mu/master/ldap.rb +3 -3
  104. data/modules/mu/master/ssl.rb +12 -3
  105. data/modules/mu/mommacat.rb +218 -2612
  106. data/modules/mu/mommacat/daemon.rb +403 -0
  107. data/modules/mu/mommacat/naming.rb +473 -0
  108. data/modules/mu/mommacat/search.rb +495 -0
  109. data/modules/mu/mommacat/storage.rb +722 -0
  110. data/modules/mu/{clouds → providers}/README.md +1 -1
  111. data/modules/mu/{clouds → providers}/aws.rb +380 -122
  112. data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
  113. data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
  114. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
  115. data/modules/mu/providers/aws/cdn.rb +782 -0
  116. data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
  117. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
  118. data/modules/mu/providers/aws/database.rb +1744 -0
  119. data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
  120. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  121. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
  122. data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
  123. data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
  124. data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
  125. data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
  126. data/modules/mu/providers/aws/job.rb +466 -0
  127. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
  128. data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
  129. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
  130. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
  131. data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
  132. data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
  133. data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
  134. data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
  135. data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
  136. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
  137. data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
  138. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  139. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  140. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  141. data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
  142. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  143. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  144. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  145. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  146. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  147. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  148. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  149. data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
  150. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  151. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  152. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  153. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  154. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  155. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  156. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  160. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  161. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  162. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  163. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  164. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  165. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  166. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  167. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  168. data/modules/mu/{clouds → providers}/google.rb +68 -30
  169. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  170. data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
  171. data/modules/mu/{clouds → providers}/google/database.rb +11 -21
  172. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  173. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  174. data/modules/mu/{clouds → providers}/google/function.rb +140 -168
  175. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  176. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  177. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
  178. data/modules/mu/{clouds → providers}/google/role.rb +94 -58
  179. data/modules/mu/{clouds → providers}/google/server.rb +243 -156
  180. data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
  181. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  182. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  183. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  184. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  185. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  186. data/modules/tests/aws-jobs-functions.yaml +46 -0
  187. data/modules/tests/bucket.yml +4 -0
  188. data/modules/tests/centos6.yaml +15 -0
  189. data/modules/tests/centos7.yaml +15 -0
  190. data/modules/tests/centos8.yaml +12 -0
  191. data/modules/tests/ecs.yaml +23 -0
  192. data/modules/tests/eks.yaml +1 -1
  193. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  194. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  195. data/modules/tests/includes-and-params.yaml +2 -1
  196. data/modules/tests/microservice_app.yaml +288 -0
  197. data/modules/tests/rds.yaml +108 -0
  198. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  199. data/modules/tests/regrooms/bucket.yml +19 -0
  200. data/modules/tests/regrooms/rds.yaml +123 -0
  201. data/modules/tests/server-with-scrub-muisms.yaml +2 -1
  202. data/modules/tests/super_complex_bok.yml +2 -2
  203. data/modules/tests/super_simple_bok.yml +3 -5
  204. data/modules/tests/win2k12.yaml +17 -5
  205. data/modules/tests/win2k16.yaml +25 -0
  206. data/modules/tests/win2k19.yaml +25 -0
  207. data/requirements.txt +1 -0
  208. data/spec/mu/clouds/azure_spec.rb +2 -2
  209. metadata +240 -154
  210. data/extras/image-generators/AWS/windows.yaml +0 -18
  211. data/modules/mu/clouds/aws/database.rb +0 -1985
  212. data/modules/mu/clouds/aws/endpoint.rb +0 -592
@@ -25,13 +25,15 @@ module MU
25
25
  # Routines for removing cloud resources.
26
26
  class Cleanup
27
27
 
28
- home = Etc.getpwuid(Process.uid).dir
29
-
30
28
  @deploy_id = nil
31
29
  @noop = false
32
30
  @onlycloud = false
33
31
  @skipcloud = false
34
32
 
33
+ # Resource types, in the order in which we generally have to clean them up
34
+ # to disentangle them from one another.
35
+ TYPES_IN_ORDER = ["Collection", "CDN", "Endpoint", "Function", "ServerPool", "ContainerCluster", "SearchDomain", "Server", "MsgQueue", "Database", "CacheCluster", "StoragePool", "LoadBalancer", "NoSQLDB", "FirewallRule", "Alarm", "Notifier", "Log", "Job", "VPC", "Role", "Group", "User", "Bucket", "DNSZone", "Collection"]
36
+
35
37
  # Purge all resources associated with a deployment.
36
38
  # @param deploy_id [String]: The identifier of the deployment to remove (typically seen in the MU-ID tag on a resource).
37
39
  # @param noop [Boolean]: Do not delete resources, merely list what would be deleted.
@@ -50,20 +52,14 @@ module MU
50
52
  @onlycloud = onlycloud
51
53
  @skipcloud = skipcloud
52
54
  @ignoremaster = ignoremaster
55
+ @deploy_id = deploy_id
53
56
 
54
57
  if @skipcloud and @onlycloud # you actually mean noop
55
58
  @onlycloud = @skipcloud = false
56
59
  @noop = true
57
60
  end
58
61
 
59
- if MU.mu_user != "mu"
60
- MU.setVar("dataDir", Etc.getpwnam(MU.mu_user).dir+"/.mu/var")
61
- else
62
- MU.setVar("dataDir", MU.mainDataDir)
63
- end
64
-
65
-
66
- types_in_order = ["Collection", "Endpoint", "Function", "ServerPool", "ContainerCluster", "SearchDomain", "Server", "MsgQueue", "Database", "CacheCluster", "StoragePool", "LoadBalancer", "NoSQLDB", "FirewallRule", "Alarm", "Notifier", "Log", "VPC", "Role", "Group", "User", "Bucket", "DNSZone", "Collection"]
62
+ MU.setVar("dataDir", (MU.mu_user == "mu" ? MU.mainDataDir : Etc.getpwnam(MU.mu_user).dir+"/.mu/var"))
67
63
 
68
64
  # Load up our deployment metadata
69
65
  if !mommacat.nil?
@@ -81,174 +77,27 @@ module MU
81
77
  MU.log "Searching for remnants of #{deploy_id}, though this may be an invalid MU-ID.", MU::WARN
82
78
  end
83
79
  @mommacat = MU::MommaCat.new(deploy_id, mu_user: MU.mu_user, delay_descriptor_load: true)
84
- rescue Exception => e
80
+ rescue StandardError => e
85
81
  MU.log "Can't load a deploy record for #{deploy_id} (#{e.inspect}), cleaning up resources by guesswork", MU::WARN, details: e.backtrace
86
82
  MU.setVar("deploy_id", deploy_id)
87
-
88
83
  end
89
84
  end
90
85
 
91
- regionsused = @mommacat.regionsUsed if @mommacat
92
- credsused = @mommacat.credsUsed if @mommacat
86
+ @regionsused = @mommacat.regionsUsed if @mommacat
87
+ @credsused = @mommacat.credsUsed if @mommacat
88
+ @habitatsused = @mommacat.habitatsUsed if @mommacat
93
89
 
94
90
  if !@skipcloud
95
- creds = {}
96
- MU::Cloud.availableClouds.each { |cloud|
97
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
98
- if $MU_CFG[cloud.downcase] and $MU_CFG[cloud.downcase].size > 0
99
- creds[cloud] ||= {}
100
- cloudclass.listCredentials.each { |credset|
101
- next if credsets and credsets.size > 0 and !credsets.include?(credset)
102
- next if credsused and credsused.size > 0 and !credsused.include?(credset)
103
- MU.log "Will scan #{cloud} with credentials #{credset}"
104
- creds[cloud][credset] = cloudclass.listRegions(credentials: credset)
105
- }
106
- else
107
- if cloudclass.hosted?
108
- creds[cloud] ||= {}
109
- creds[cloud]["#default"] = cloudclass.listRegions
110
- end
111
- end
112
- }
91
+ creds = listUsedCredentials(credsets)
113
92
 
114
- parent_thread_id = Thread.current.object_id
115
- deleted_nodes = 0
116
93
  cloudthreads = []
117
- keyname = "deploy-#{MU.deploy_id}"
94
+
118
95
  had_failures = false
119
96
 
120
97
  creds.each_pair { |provider, credsets_outer|
121
98
  cloudthreads << Thread.new(provider, credsets_outer) { |cloud, credsets_inner|
122
- MU.dupGlobals(parent_thread_id)
123
99
  Thread.abort_on_exception = false
124
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
125
- habitatclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get("Habitat")
126
- credsets_inner.each_pair { |credset, acct_regions|
127
- next if credsused and !credsused.include?(credset)
128
- global_vs_region_semaphore = Mutex.new
129
- global_done = {}
130
- habitats_done = {}
131
- regionthreads = []
132
- acct_regions.each { |r|
133
- if regionsused
134
- if regionsused.size > 0
135
- next if !regionsused.include?(r)
136
- else
137
- next if r != cloudclass.myRegion(credset)
138
- end
139
- end
140
- if regions and !regions.empty?
141
- next if !regions.include?(r)
142
- MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}...", MU::NOTICE
143
- end
144
- regionthreads << Thread.new {
145
- MU.dupGlobals(parent_thread_id)
146
- Thread.abort_on_exception = false
147
- MU.setVar("curRegion", r)
148
- projects = []
149
- if habitats
150
- projects = habitats
151
- else
152
- if $MU_CFG and $MU_CFG[cloud.downcase] and
153
- $MU_CFG[cloud.downcase][credset] and
154
- $MU_CFG[cloud.downcase][credset]["project"]
155
- # XXX GCP credential schema needs an array for projects
156
- projects << $MU_CFG[cloud.downcase][credset]["project"]
157
- end
158
- begin
159
- projects.concat(cloudclass.listProjects(credset))
160
- rescue NoMethodError
161
- end
162
- end
163
-
164
- if projects == []
165
- projects << "" # dummy
166
- MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}", MU::NOTICE
167
- end
168
- projects.uniq!
169
-
170
- # We do these in an order that unrolls dependent resources
171
- # sensibly, and we hit :Collection twice because AWS
172
- # CloudFormation sometimes fails internally.
173
- projectthreads = []
174
- projects.each { |project|
175
- next if !habitatclass.isLive?(project, credset)
176
- if habitats and !habitats.empty? and project != ""
177
- next if !habitats.include?(project)
178
- end
179
-
180
- projectthreads << Thread.new {
181
- MU.dupGlobals(parent_thread_id)
182
- MU.setVar("curRegion", r)
183
- Thread.abort_on_exception = false
184
- if project != ""
185
- MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}, project #{project}", MU::NOTICE
186
- end
187
-
188
- MU.dupGlobals(parent_thread_id)
189
- flags = {
190
- "project" => project,
191
- "onlycloud" => @onlycloud,
192
- "skipsnapshots" => @skipsnapshots,
193
- }
194
- types_in_order.each { |t|
195
- shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(t)
196
- begin
197
- skipme = false
198
- global_vs_region_semaphore.synchronize {
199
- MU::Cloud.loadCloudType(cloud, t)
200
- if Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(t).isGlobal?
201
- global_done[project] ||= []
202
- if !global_done[project].include?(t)
203
- global_done[project] << t
204
- flags['global'] = true
205
- else
206
- skipme = true
207
- end
208
- end
209
- }
210
- next if skipme
211
- rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented => e
212
- next
213
- rescue MU::MuError, NoMethodError => e
214
- MU.log "While checking mu/clouds/#{cloud.downcase}/#{cloudclass.cfg_name} for global-ness in cleanup: "+e.message, MU::WARN
215
- next
216
- rescue ::Aws::EC2::Errors::AuthFailure, ::Google::Apis::ClientError => e
217
- MU.log e.message+" in "+r, MU::ERR
218
- next
219
- end
220
-
221
- begin
222
- if !self.call_cleanup(t, credset, cloud, flags, r)
223
- had_failures = true
224
- end
225
- rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented => e
226
- next
227
- end
228
- }
229
- } # types_in_order.each { |t|
230
- } # projects.each { |project|
231
- projectthreads.each do |t|
232
- t.join
233
- end
234
-
235
- # XXX move to MU::AWS
236
- if cloud == "AWS"
237
- resp = MU::Cloud::AWS.ec2(region: r, credentials: credset).describe_key_pairs(
238
- filters: [{name: "key-name", values: [keyname]}]
239
- )
240
- resp.data.key_pairs.each { |keypair|
241
- MU.log "Deleting key pair #{keypair.key_name} from #{r}"
242
- MU::Cloud::AWS.ec2(region: r, credentials: credset).delete_key_pair(key_name: keypair.key_name) if !@noop
243
- }
244
- end
245
- } # regionthreads << Thread.new {
246
- } # acct_regions.each { |r|
247
- regionthreads.each do |t|
248
- t.join
249
- end
250
-
251
- } # credsets.each_pair { |credset, acct_regions|
100
+ cleanCloud(cloud, habitats, regions, credsets_inner)
252
101
  } # cloudthreads << Thread.new(provider, credsets) { |cloud, credsets_outer|
253
102
  cloudthreads.each do |t|
254
103
  t.join
@@ -260,24 +109,21 @@ module MU
260
109
  # once they're all done.
261
110
  creds.each_pair { |provider, credsets_inner|
262
111
  credsets_inner.keys.each { |credset|
263
- next if credsused and !credsused.include?(credset)
112
+ next if @credsused and !@credsused.include?(credset)
264
113
  ["Habitat", "Folder"].each { |t|
265
114
  flags = {
266
115
  "onlycloud" => @onlycloud,
267
116
  "skipsnapshots" => @skipsnapshots
268
117
  }
269
- if !self.call_cleanup(t, credset, provider, flags, nil)
118
+ if !call_cleanup(t, credset, provider, flags, nil)
270
119
  had_failures = true
271
120
  end
272
121
  }
273
122
  }
274
123
  }
275
124
 
276
- MU::Cloud::Google.removeDeploySecretsAndRoles(MU.deploy_id)
277
- # XXX port AWS equivalent behavior and add a MU::Cloud wrapper
278
-
279
125
  creds.each_pair { |provider, credsets_inner|
280
- cloudclass = Object.const_get("MU").const_get("Cloud").const_get(provider)
126
+ cloudclass = MU::Cloud.cloudClass(provider)
281
127
  credsets_inner.keys.each { |c|
282
128
  cloudclass.cleanDeploy(MU.deploy_id, credentials: c, noop: @noop)
283
129
  }
@@ -285,44 +131,16 @@ module MU
285
131
  end
286
132
 
287
133
  # Scrub any residual Chef records with matching tags
288
- if !@onlycloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0) and !(Gem.paths and Gem.paths.home and !Dir.exist?("/opt/mu/lib"))
289
- begin
290
- MU::Groomer::Chef.loadChefLib
291
- if File.exist?(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
292
- Chef::Config.from_file(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
293
- end
294
- deadnodes = []
295
- Chef::Config[:environment] = MU.environment
296
- q = Chef::Search::Query.new
297
- begin
298
- q.search("node", "tags_MU-ID:#{MU.deploy_id}").each { |item|
299
- next if item.is_a?(Integer)
300
- item.each { |node|
301
- deadnodes << node.name
302
- }
303
- }
304
- rescue Net::HTTPServerException
305
- end
306
-
307
- begin
308
- q.search("node", "name:#{MU.deploy_id}-*").each { |item|
309
- next if item.is_a?(Integer)
310
- item.each { |node|
311
- deadnodes << node.name
312
- }
313
- }
314
- rescue Net::HTTPServerException
315
- end
316
- MU.log "Missed some Chef resources in node cleanup, purging now", MU::NOTICE if deadnodes.size > 0
317
- deadnodes.uniq.each { |node|
318
- MU::Groomer::Chef.cleanup(node, [], noop)
319
- }
320
- rescue LoadError
321
- end
134
+ if !@onlycloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0) and !@noop
135
+ MU.supportedGroomers.each { |g|
136
+ groomer = MU::Groomer.loadGroomer(g)
137
+ groomer.cleanup(MU.deploy_id, @noop)
138
+ }
322
139
  end
323
140
 
324
141
  if had_failures
325
142
  MU.log "Had cleanup failures, exiting", MU::ERR
143
+ File.unlink("#{deploy_dir}/.cleanup") if !@noop
326
144
  exit 1
327
145
  end
328
146
 
@@ -330,134 +148,231 @@ module MU
330
148
  @mommacat.purge!
331
149
  end
332
150
 
333
- myhome = Etc.getpwuid(Process.uid).dir
334
- sshdir = "#{myhome}/.ssh"
335
- sshconf = "#{sshdir}/config"
336
- ssharchive = "#{sshdir}/archive"
337
-
338
- Dir.mkdir(sshdir, 0700) if !Dir.exist?(sshdir) and !@noop
339
- Dir.mkdir(ssharchive, 0700) if !Dir.exist?(ssharchive) and !@noop
151
+ if !@onlycloud
152
+ MU::Master.purgeDeployFromSSH(MU.deploy_id, noop: @noop)
153
+ end
340
154
 
341
- keyname = "deploy-#{MU.deploy_id}"
342
- if File.exist?("#{sshdir}/#{keyname}")
343
- MU.log "Moving #{sshdir}/#{keyname} to #{ssharchive}/#{keyname}"
344
- if !@noop
345
- File.rename("#{sshdir}/#{keyname}", "#{ssharchive}/#{keyname}")
346
- end
155
+ if !@noop and !@skipcloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0)
156
+ # MU::Master.syncMonitoringConfig
347
157
  end
348
158
 
349
- if File.exist?(sshconf) and File.open(sshconf).read.match(/\/deploy\-#{MU.deploy_id}$/)
350
- MU.log "Expunging #{MU.deploy_id} from #{sshconf}"
351
- if !@noop
352
- FileUtils.copy(sshconf, "#{ssharchive}/config-#{MU.deploy_id}")
353
- File.open(sshconf, File::CREAT|File::RDWR, 0600) { |f|
354
- f.flock(File::LOCK_EX)
355
- newlines = Array.new
356
- delete_block = false
357
- f.readlines.each { |line|
358
- if line.match(/^Host #{MU.deploy_id}\-/)
359
- delete_block = true
360
- elsif line.match(/^Host /)
361
- delete_block = false
362
- end
363
- newlines << line if !delete_block
364
- }
365
- f.rewind
366
- f.truncate(0)
367
- f.puts(newlines)
368
- f.flush
369
- f.flock(File::LOCK_UN)
159
+ end
160
+
161
+ def self.listUsedCredentials(credsets)
162
+ creds = {}
163
+ MU::Cloud.availableClouds.each { |cloud|
164
+ cloudclass = MU::Cloud.cloudClass(cloud)
165
+ if $MU_CFG[cloud.downcase] and $MU_CFG[cloud.downcase].size > 0
166
+ creds[cloud] ||= {}
167
+ cloudclass.listCredentials.each { |credset|
168
+ next if credsets and credsets.size > 0 and !credsets.include?(credset)
169
+ next if @credsused and @credsused.size > 0 and !@credsused.include?(credset)
170
+ MU.log "Will scan #{cloud} with credentials #{credset}"
171
+ creds[cloud][credset] = cloudclass.listRegions(credentials: credset)
370
172
  }
173
+ else
174
+ if cloudclass.hosted?
175
+ creds[cloud] ||= {}
176
+ creds[cloud]["#default"] = cloudclass.listRegions
177
+ end
371
178
  end
372
- end
373
-
374
- # XXX refactor with above? They're similar, ish.
375
- hostsfile = "/etc/hosts"
376
- if File.open(hostsfile).read.match(/ #{MU.deploy_id}\-/)
377
- if Process.uid == 0
378
- MU.log "Expunging traces of #{MU.deploy_id} from #{hostsfile}"
379
- if !@noop
380
- FileUtils.copy(hostsfile, "#{hostsfile}.cleanup-#{deploy_id}")
381
- File.open(hostsfile, File::CREAT|File::RDWR, 0644) { |f|
382
- f.flock(File::LOCK_EX)
383
- newlines = Array.new
384
- f.readlines.each { |line|
385
- newlines << line if !line.match(/ #{MU.deploy_id}\-/)
386
- }
387
- f.rewind
388
- f.truncate(0)
389
- f.puts(newlines)
390
- f.flush
391
- f.flock(File::LOCK_UN)
392
- }
179
+ }
180
+ creds
181
+ end
182
+ private_class_method :listUsedCredentials
183
+
184
+ def self.cleanCloud(cloud, habitats, regions, credsets)
185
+ cloudclass = MU::Cloud.cloudClass(cloud)
186
+ credsets.each_pair { |credset, acct_regions|
187
+ next if @credsused and !@credsused.include?(credset)
188
+ global_vs_region_semaphore = Mutex.new
189
+ global_done = {}
190
+ regionthreads = []
191
+ acct_regions.each { |r|
192
+ if @regionsused
193
+ if @regionsused.size > 0
194
+ next if !@regionsused.include?(r)
195
+ else
196
+ next if r != cloudclass.myRegion(credset)
197
+ end
393
198
  end
394
- else
395
- MU.log "Residual /etc/hosts entries for #{MU.deploy_id} must be removed by root user", MU::WARN
199
+ if regions and !regions.empty?
200
+ next if !regions.include?(r)
201
+ MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}...", MU::NOTICE
202
+ end
203
+ regionthreads << Thread.new {
204
+ Thread.abort_on_exception = false
205
+ MU.setVar("curRegion", r)
206
+ cleanRegion(cloud, credset, r, global_vs_region_semaphore, global_done, habitats)
207
+ } # regionthreads << Thread.new {
208
+ } # acct_regions.each { |r|
209
+ regionthreads.each do |t|
210
+ t.join
211
+ end
212
+ }
213
+ end
214
+ private_class_method :cleanCloud
215
+
216
+ def self.cleanRegion(cloud, credset, region, global_vs_region_semaphore, global_done, habitats)
217
+ had_failures = false
218
+ cloudclass = MU::Cloud.cloudClass(cloud)
219
+ habitatclass = MU::Cloud.resourceClass(cloud, "Habitat")
220
+
221
+ if !habitats
222
+ habitats = []
223
+ if $MU_CFG and $MU_CFG[cloud.downcase] and
224
+ $MU_CFG[cloud.downcase][credset] and
225
+ $MU_CFG[cloud.downcase][credset]["project"]
226
+ # XXX GCP credential schema needs an array for projects
227
+ habitats << $MU_CFG[cloud.downcase][credset]["project"]
228
+ end
229
+ begin
230
+ habitats.concat(cloudclass.listHabitats(credset, use_cache: false))
231
+ rescue NoMethodError
396
232
  end
397
233
  end
398
234
 
399
- if !@noop and !@skipcloud
400
- if $MU_CFG['aws'] and $MU_CFG['aws']['account_number']
401
- MU::Cloud::AWS.s3(region: MU.myRegion).delete_object(
402
- bucket: MU.adminBucketName,
403
- key: "#{MU.deploy_id}-secret"
404
- )
235
+ if habitats == []
236
+ habitats << "" # dummy
237
+ MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{region}", MU::NOTICE
238
+ end
239
+ habitats.uniq!
240
+
241
+ # We do these in an order that unrolls dependent resources
242
+ # sensibly, and we hit :Collection twice because AWS
243
+ # CloudFormation sometimes fails internally.
244
+ habitat_threads = []
245
+ habitats.each { |habitat|
246
+ if habitats and !habitats.empty? and habitat != ""
247
+ next if !habitats.include?(habitat)
405
248
  end
406
- if $MU_CFG['google'] and $MU_CFG['google']['project']
407
- begin
408
- MU::Cloud::Google.storage.delete_object(
409
- MU.adminBucketName,
410
- "#{MU.deploy_id}-secret"
411
- )
412
- rescue ::Google::Apis::ClientError => e
413
- raise e if !e.message.match(/^notFound: /)
414
- end
249
+ if @habitatsused and !@habitatsused.empty? and habitat != ""
250
+ next if !@habitatsused.include?(habitat)
415
251
  end
416
- if MU.myCloud == "AWS"
417
- MU::Cloud::AWS.openFirewallForClients # XXX add the other clouds, or abstract
252
+ next if !habitatclass.isLive?(habitat, credset)
253
+
254
+ habitat_threads << Thread.new {
255
+ Thread.current.thread_variable_set("name", "#{cloud}/#{credset}/#{habitat}/#{region}")
256
+ Thread.abort_on_exception = false
257
+ if !cleanHabitat(cloud, credset, region, habitat, global_vs_region_semaphore, global_done)
258
+ had_failures = true
259
+ end
260
+ } # TYPES_IN_ORDER.each { |t|
261
+ } # habitats.each { |habitat|
262
+
263
+ last_checkin = Time.now
264
+ begin
265
+ deletia = []
266
+ habitat_threads.each { |t|
267
+ if !t.status
268
+ t.join
269
+ deletia << t
270
+ end
271
+ }
272
+ deletia.each { |t|
273
+ habitat_threads.delete(t)
274
+ }
275
+ if (Time.now - last_checkin) > 120
276
+ list = habitat_threads.map { |t|
277
+ t.thread_variable_get("name") + (t.thread_variable_get("type") ? "/"+t.thread_variable_get("type") : "")
278
+ }
279
+ MU.log "Waiting on #{habitat_threads.size.to_s} habitat#{habitat_threads.size > 1 ? "s" : ""} in region #{region}", MU::NOTICE, details: list
280
+ last_checkin = Time.now
418
281
  end
419
- end
282
+ sleep 10 if !habitat_threads.empty?
283
+ end while !habitat_threads.empty?
420
284
 
421
- if !@noop and !@skipcloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0)
422
- # MU::MommaCat.syncMonitoringConfig
285
+ had_failures
286
+ end
287
+ private_class_method :cleanRegion
288
+
289
+ def self.cleanHabitat(cloud, credset, region, habitat, global_vs_region_semaphore, global_done)
290
+ had_failures = false
291
+ if habitat != ""
292
+ MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{region}, habitat #{habitat}", MU::NOTICE
423
293
  end
424
294
 
425
- end
295
+ flags = {
296
+ "habitat" => habitat,
297
+ "onlycloud" => @onlycloud,
298
+ "skipsnapshots" => @skipsnapshots,
299
+ }
300
+ TYPES_IN_ORDER.each { |t|
301
+ begin
302
+ skipme = false
303
+ global_vs_region_semaphore.synchronize {
304
+ if MU::Cloud.resourceClass(cloud, t).isGlobal?
305
+ global_done[habitat] ||= []
306
+ if !global_done[habitat].include?(t)
307
+ global_done[habitat] << t
308
+ flags['global'] = true
309
+ else
310
+ skipme = true
311
+ end
312
+ end
313
+ }
314
+ next if skipme
315
+ rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented
316
+ next
317
+ rescue MU::MuError, NoMethodError => e
318
+ MU.log "While checking mu/providers/#{cloud.downcase}/#{cloudclass.cfg_name} for global-ness in cleanup: "+e.message, MU::WARN
319
+ next
320
+ rescue ::Aws::EC2::Errors::AuthFailure, ::Google::Apis::ClientError => e
321
+ MU.log e.message+" in "+region, MU::ERR
322
+ next
323
+ end
426
324
 
427
- private
325
+ begin
326
+ if !call_cleanup(t, credset, cloud, flags, region)
327
+ had_failures = true
328
+ end
329
+ rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented
330
+ next
331
+ end
332
+ }
428
333
 
334
+ had_failures
335
+ end
336
+ private_class_method :cleanHabitat
337
+
338
+ # Wrapper for dynamically invoking resource type cleanup methods.
339
+ # @param type [String]:
340
+ # @param credset [String]:
341
+ # @param provider [String]:
342
+ # @param flags [Hash]:
343
+ # @param region [String]:
429
344
  def self.call_cleanup(type, credset, provider, flags, region)
345
+ Thread.current.thread_variable_set("type", type)
430
346
  if @mommacat.nil? or @mommacat.numKittens(types: [type]) > 0
431
347
  if @mommacat
348
+
432
349
  found = @mommacat.findLitterMate(type: type, return_all: true, credentials: credset)
433
- flags['known'] ||= []
434
- if found.is_a?(Array)
435
- found.each { |k|
436
- flags['known'] << k.cloud_id
437
- }
438
- elsif found and found.is_a?(Hash)
439
- flags['known'] << found['cloud_id']
440
- elsif found
441
- flags['known'] << found.cloud_id
350
+
351
+ if found
352
+ flags['known'] = if found.is_a?(Array)
353
+ found.map { |k| k.cloud_id }
354
+ elsif found.is_a?(Hash)
355
+ found.each_value.map { |k| k.cloud_id }
356
+ else
357
+ [found.cloud_id]
358
+ end
442
359
  end
443
360
  end
444
- # begin
445
- resclass = Object.const_get("MU").const_get("Cloud").const_get(type)
446
-
447
- resclass.cleanup(
448
- noop: @noop,
449
- ignoremaster: @ignoremaster,
450
- region: region,
451
- cloud: provider,
452
- flags: flags,
453
- credentials: credset
454
- )
455
- # rescue ::Seahorse::Client::NetworkingError => e
456
- # MU.log "Service not available in AWS region #{r}, skipping", MU::DEBUG, details: e.message
457
- # end
361
+
362
+ MU::Cloud.loadBaseType(type).cleanup(
363
+ noop: @noop,
364
+ ignoremaster: @ignoremaster,
365
+ region: region,
366
+ cloud: provider,
367
+ flags: flags,
368
+ credentials: credset,
369
+ deploy_id: @deploy_id
370
+ )
458
371
  else
459
372
  true
460
373
  end
461
374
  end
375
+ private_class_method :call_cleanup
376
+
462
377
  end #class
463
378
  end #module