cloud-mu 3.1.5 → 3.1.6
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.
- checksums.yaml +4 -4
- data/Dockerfile +5 -1
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -0
- data/ansible/roles/mu-windows/tasks/main.yml +16 -0
- data/bin/mu-adopt +2 -1
- data/bin/mu-configure +16 -0
- data/bin/mu-node-manage +15 -16
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/windows-client.rb +25 -22
- data/extras/clean-stock-amis +25 -19
- data/extras/image-generators/AWS/win2k12.yaml +2 -0
- data/extras/image-generators/AWS/win2k16.yaml +2 -0
- data/extras/image-generators/AWS/win2k19.yaml +2 -0
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +6 -5
- data/modules/mu/adoption.rb +19 -4
- data/modules/mu/cleanup.rb +181 -293
- data/modules/mu/cloud.rb +58 -17
- data/modules/mu/clouds/aws.rb +36 -1
- data/modules/mu/clouds/aws/container_cluster.rb +30 -21
- data/modules/mu/clouds/aws/role.rb +1 -1
- data/modules/mu/clouds/aws/vpc.rb +5 -1
- data/modules/mu/clouds/azure.rb +10 -0
- data/modules/mu/clouds/cloudformation.rb +10 -0
- data/modules/mu/clouds/google.rb +18 -4
- data/modules/mu/clouds/google/bucket.rb +2 -2
- data/modules/mu/clouds/google/container_cluster.rb +10 -7
- data/modules/mu/clouds/google/database.rb +3 -3
- data/modules/mu/clouds/google/firewall_rule.rb +3 -3
- data/modules/mu/clouds/google/function.rb +3 -3
- data/modules/mu/clouds/google/loadbalancer.rb +4 -4
- data/modules/mu/clouds/google/role.rb +18 -9
- data/modules/mu/clouds/google/server.rb +16 -14
- data/modules/mu/clouds/google/server_pool.rb +4 -4
- data/modules/mu/clouds/google/user.rb +2 -2
- data/modules/mu/clouds/google/vpc.rb +9 -13
- data/modules/mu/config.rb +1 -1
- data/modules/mu/config/container_cluster.rb +5 -0
- data/modules/mu/config/doc_helpers.rb +1 -1
- data/modules/mu/config/ref.rb +12 -6
- data/modules/mu/config/schema_helpers.rb +8 -3
- data/modules/mu/config/server.rb +7 -0
- data/modules/mu/config/tail.rb +1 -0
- data/modules/mu/config/vpc.rb +15 -7
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +48 -48
- data/modules/mu/deploy.rb +1 -1
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -4
- data/modules/mu/groomers/chef.rb +48 -4
- data/modules/mu/master.rb +75 -3
- data/modules/mu/mommacat.rb +104 -855
- data/modules/mu/mommacat/naming.rb +28 -0
- data/modules/mu/mommacat/search.rb +463 -0
- data/modules/mu/mommacat/storage.rb +185 -183
- data/modules/tests/super_simple_bok.yml +1 -3
- metadata +8 -5
data/modules/mommacat.ru
CHANGED
data/modules/mu.rb
CHANGED
@@ -273,8 +273,8 @@ module MU
|
|
273
273
|
# Wrapper class for fatal Exceptions. Gives our internals something to
|
274
274
|
# inherit that will log an error message appropriately before bubbling up.
|
275
275
|
class MuError < StandardError
|
276
|
-
def initialize(message = nil)
|
277
|
-
MU.log message, MU::ERR, details: caller[2] if !message.nil?
|
276
|
+
def initialize(message = nil, silent: false)
|
277
|
+
MU.log message, MU::ERR, details: caller[2] if !message.nil? and !silent
|
278
278
|
if MU.verbosity == MU::Logger::SILENT
|
279
279
|
super ""
|
280
280
|
else
|
@@ -286,8 +286,8 @@ module MU
|
|
286
286
|
# Wrapper class for temporary Exceptions. Gives our internals something to
|
287
287
|
# inherit that will log a notice message appropriately before bubbling up.
|
288
288
|
class MuNonFatal < StandardError
|
289
|
-
def initialize(message = nil)
|
290
|
-
MU.log message, MU::NOTICE if !message.nil?
|
289
|
+
def initialize(message = nil, silent: false)
|
290
|
+
MU.log message, MU::NOTICE if !message.nil? and !silent
|
291
291
|
if MU.verbosity == MU::Logger::SILENT
|
292
292
|
super ""
|
293
293
|
else
|
@@ -598,9 +598,10 @@ module MU
|
|
598
598
|
end
|
599
599
|
|
600
600
|
# Shortcut to invoke {MU::Logger#log}
|
601
|
-
def self.log(msg, level = MU::INFO, details: nil, html: false, verbosity: nil, color: true)
|
601
|
+
def self.log(msg, level = MU::INFO, shorthand_details = nil, details: nil, html: false, verbosity: nil, color: true)
|
602
602
|
return if (level == MU::DEBUG and verbosity and verbosity <= MU::Logger::LOUD)
|
603
603
|
return if verbosity and verbosity == MU::Logger::SILENT
|
604
|
+
details ||= shorthand_details
|
604
605
|
|
605
606
|
if (level == MU::ERR or
|
606
607
|
level == MU::WARN or
|
data/modules/mu/adoption.rb
CHANGED
@@ -30,7 +30,7 @@ module MU
|
|
30
30
|
:omnibus => "Jam everything into one monolothic configuration"
|
31
31
|
}
|
32
32
|
|
33
|
-
def initialize(clouds: MU::Cloud.supportedClouds, types: MU::Cloud.resource_types.keys, parent: nil, billing: nil, sources: nil, credentials: nil, group_by: :logical, savedeploys: false, diff: false, habitats: [])
|
33
|
+
def initialize(clouds: MU::Cloud.supportedClouds, types: MU::Cloud.resource_types.keys, parent: nil, billing: nil, sources: nil, credentials: nil, group_by: :logical, savedeploys: false, diff: false, habitats: [], scrub_mu_isms: false)
|
34
34
|
@scraped = {}
|
35
35
|
@clouds = clouds
|
36
36
|
@types = types
|
@@ -45,6 +45,7 @@ module MU
|
|
45
45
|
@diff = diff
|
46
46
|
@habitats = habitats
|
47
47
|
@habitats ||= []
|
48
|
+
@scrub_mu_isms = scrub_mu_isms
|
48
49
|
end
|
49
50
|
|
50
51
|
# Walk cloud providers with available credentials to discover resources
|
@@ -65,6 +66,11 @@ module MU
|
|
65
66
|
cloudclass.listCredentials.each { |credset|
|
66
67
|
next if @sources and !@sources.include?(credset)
|
67
68
|
|
69
|
+
cfg = cloudclass.credConfig(credset)
|
70
|
+
if cfg and cfg['restrict_to_habitats']
|
71
|
+
cfg['restrict_to_habitats'] << cfg['project'] if cfg['project']
|
72
|
+
end
|
73
|
+
|
68
74
|
if @parent
|
69
75
|
# TODO handle different inputs (cloud_id, etc)
|
70
76
|
# TODO do something about vague matches
|
@@ -101,15 +107,21 @@ module MU
|
|
101
107
|
allow_multi: true,
|
102
108
|
habitats: @habitats.dup,
|
103
109
|
dummy_ok: true,
|
104
|
-
|
105
|
-
|
110
|
+
skip_provider_owned: true,
|
111
|
+
# debug: false#,
|
106
112
|
)
|
107
113
|
|
108
114
|
|
109
115
|
if found and found.size > 0
|
116
|
+
if resclass.cfg_plural == "habitats"
|
117
|
+
found.reject! { |h| !cloudclass.listHabitats(credset).include?(h) }
|
118
|
+
end
|
110
119
|
MU.log "Found #{found.size.to_s} raw #{resclass.cfg_plural} in #{cloud}"
|
111
120
|
@scraped[type] ||= {}
|
112
121
|
found.each { |obj|
|
122
|
+
if obj.habitat and !cloudclass.listHabitats(credset).include?(obj.habitat)
|
123
|
+
next
|
124
|
+
end
|
113
125
|
# XXX apply any filters (e.g. MU-ID tags)
|
114
126
|
@scraped[type][obj.cloud_id] = obj
|
115
127
|
}
|
@@ -190,6 +202,9 @@ module MU
|
|
190
202
|
|
191
203
|
groupings.each_pair { |appname, types|
|
192
204
|
bok = { "appname" => prefix+appname }
|
205
|
+
if @scrub_mu_isms
|
206
|
+
bok["scrub_mu_isms"] = true
|
207
|
+
end
|
193
208
|
if @target_creds
|
194
209
|
bok["credentials"] = @target_creds
|
195
210
|
end
|
@@ -333,7 +348,7 @@ module MU
|
|
333
348
|
deletia = []
|
334
349
|
schema_chunk["properties"].each_pair { |key, subschema|
|
335
350
|
next if !conf_chunk[key]
|
336
|
-
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key)
|
351
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key, false)
|
337
352
|
|
338
353
|
if subschema["default_if"]
|
339
354
|
subschema["default_if"].each { |cond|
|
data/modules/mu/cleanup.rb
CHANGED
@@ -30,6 +30,8 @@ module MU
|
|
30
30
|
@onlycloud = false
|
31
31
|
@skipcloud = false
|
32
32
|
|
33
|
+
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"]
|
34
|
+
|
33
35
|
# Purge all resources associated with a deployment.
|
34
36
|
# @param deploy_id [String]: The identifier of the deployment to remove (typically seen in the MU-ID tag on a resource).
|
35
37
|
# @param noop [Boolean]: Do not delete resources, merely list what would be deleted.
|
@@ -54,14 +56,7 @@ module MU
|
|
54
56
|
@noop = true
|
55
57
|
end
|
56
58
|
|
57
|
-
|
58
|
-
MU.setVar("dataDir", Etc.getpwnam(MU.mu_user).dir+"/.mu/var")
|
59
|
-
else
|
60
|
-
MU.setVar("dataDir", MU.mainDataDir)
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
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"]
|
59
|
+
MU.setVar("dataDir", (MU.mu_user == "mu" ? MU.mainDataDir : Etc.getpwnam(MU.mu_user).dir+"/.mu/var"))
|
65
60
|
|
66
61
|
# Load up our deployment metadata
|
67
62
|
if !mommacat.nil?
|
@@ -82,172 +77,24 @@ module MU
|
|
82
77
|
rescue StandardError => e
|
83
78
|
MU.log "Can't load a deploy record for #{deploy_id} (#{e.inspect}), cleaning up resources by guesswork", MU::WARN, details: e.backtrace
|
84
79
|
MU.setVar("deploy_id", deploy_id)
|
85
|
-
|
86
80
|
end
|
87
81
|
end
|
88
82
|
|
89
|
-
regionsused = @mommacat.regionsUsed if @mommacat
|
90
|
-
credsused = @mommacat.credsUsed if @mommacat
|
91
|
-
habitatsused = @mommacat.habitatsUsed if @mommacat
|
83
|
+
@regionsused = @mommacat.regionsUsed if @mommacat
|
84
|
+
@credsused = @mommacat.credsUsed if @mommacat
|
85
|
+
@habitatsused = @mommacat.habitatsUsed if @mommacat
|
92
86
|
|
93
87
|
if !@skipcloud
|
94
|
-
creds =
|
95
|
-
MU::Cloud.availableClouds.each { |cloud|
|
96
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
97
|
-
if $MU_CFG[cloud.downcase] and $MU_CFG[cloud.downcase].size > 0
|
98
|
-
creds[cloud] ||= {}
|
99
|
-
cloudclass.listCredentials.each { |credset|
|
100
|
-
next if credsets and credsets.size > 0 and !credsets.include?(credset)
|
101
|
-
next if credsused and credsused.size > 0 and !credsused.include?(credset)
|
102
|
-
MU.log "Will scan #{cloud} with credentials #{credset}"
|
103
|
-
creds[cloud][credset] = cloudclass.listRegions(credentials: credset)
|
104
|
-
}
|
105
|
-
else
|
106
|
-
if cloudclass.hosted?
|
107
|
-
creds[cloud] ||= {}
|
108
|
-
creds[cloud]["#default"] = cloudclass.listRegions
|
109
|
-
end
|
110
|
-
end
|
111
|
-
}
|
88
|
+
creds = listUsedCredentials(credsets)
|
112
89
|
|
113
|
-
parent_thread_id = Thread.current.object_id
|
114
90
|
cloudthreads = []
|
115
|
-
|
91
|
+
|
116
92
|
had_failures = false
|
117
93
|
|
118
94
|
creds.each_pair { |provider, credsets_outer|
|
119
95
|
cloudthreads << Thread.new(provider, credsets_outer) { |cloud, credsets_inner|
|
120
|
-
MU.dupGlobals(parent_thread_id)
|
121
96
|
Thread.abort_on_exception = false
|
122
|
-
|
123
|
-
habitatclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get("Habitat")
|
124
|
-
credsets_inner.each_pair { |credset, acct_regions|
|
125
|
-
next if credsused and !credsused.include?(credset)
|
126
|
-
global_vs_region_semaphore = Mutex.new
|
127
|
-
global_done = {}
|
128
|
-
regionthreads = []
|
129
|
-
acct_regions.each { |r|
|
130
|
-
if regionsused
|
131
|
-
if regionsused.size > 0
|
132
|
-
next if !regionsused.include?(r)
|
133
|
-
else
|
134
|
-
next if r != cloudclass.myRegion(credset)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
if regions and !regions.empty?
|
138
|
-
next if !regions.include?(r)
|
139
|
-
MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}...", MU::NOTICE
|
140
|
-
end
|
141
|
-
regionthreads << Thread.new {
|
142
|
-
MU.dupGlobals(parent_thread_id)
|
143
|
-
Thread.abort_on_exception = false
|
144
|
-
MU.setVar("curRegion", r)
|
145
|
-
projects = []
|
146
|
-
if habitats
|
147
|
-
projects = habitats
|
148
|
-
else
|
149
|
-
if $MU_CFG and $MU_CFG[cloud.downcase] and
|
150
|
-
$MU_CFG[cloud.downcase][credset] and
|
151
|
-
$MU_CFG[cloud.downcase][credset]["project"]
|
152
|
-
# XXX GCP credential schema needs an array for projects
|
153
|
-
projects << $MU_CFG[cloud.downcase][credset]["project"]
|
154
|
-
end
|
155
|
-
begin
|
156
|
-
projects.concat(cloudclass.listProjects(credset))
|
157
|
-
rescue NoMethodError
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
if projects == []
|
162
|
-
projects << "" # dummy
|
163
|
-
MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}", MU::NOTICE
|
164
|
-
end
|
165
|
-
projects.uniq!
|
166
|
-
|
167
|
-
# We do these in an order that unrolls dependent resources
|
168
|
-
# sensibly, and we hit :Collection twice because AWS
|
169
|
-
# CloudFormation sometimes fails internally.
|
170
|
-
projectthreads = []
|
171
|
-
projects.each { |project|
|
172
|
-
if habitats and !habitats.empty? and project != ""
|
173
|
-
next if !habitats.include?(project)
|
174
|
-
end
|
175
|
-
if habitatsused and !habitatsused.empty? and project != ""
|
176
|
-
next if !habitatsused.include?(project)
|
177
|
-
end
|
178
|
-
next if !habitatclass.isLive?(project, credset)
|
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
|
-
begin
|
196
|
-
skipme = false
|
197
|
-
global_vs_region_semaphore.synchronize {
|
198
|
-
MU::Cloud.loadCloudType(cloud, t)
|
199
|
-
if Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(t).isGlobal?
|
200
|
-
global_done[project] ||= []
|
201
|
-
if !global_done[project].include?(t)
|
202
|
-
global_done[project] << t
|
203
|
-
flags['global'] = true
|
204
|
-
else
|
205
|
-
skipme = true
|
206
|
-
end
|
207
|
-
end
|
208
|
-
}
|
209
|
-
next if skipme
|
210
|
-
rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented => e
|
211
|
-
next
|
212
|
-
rescue MU::MuError, NoMethodError => e
|
213
|
-
MU.log "While checking mu/clouds/#{cloud.downcase}/#{cloudclass.cfg_name} for global-ness in cleanup: "+e.message, MU::WARN
|
214
|
-
next
|
215
|
-
rescue ::Aws::EC2::Errors::AuthFailure, ::Google::Apis::ClientError => e
|
216
|
-
MU.log e.message+" in "+r, MU::ERR
|
217
|
-
next
|
218
|
-
end
|
219
|
-
|
220
|
-
begin
|
221
|
-
if !self.call_cleanup(t, credset, cloud, flags, r)
|
222
|
-
had_failures = true
|
223
|
-
end
|
224
|
-
rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented => e
|
225
|
-
next
|
226
|
-
end
|
227
|
-
}
|
228
|
-
} # types_in_order.each { |t|
|
229
|
-
} # projects.each { |project|
|
230
|
-
projectthreads.each do |t|
|
231
|
-
t.join
|
232
|
-
end
|
233
|
-
|
234
|
-
# XXX move to MU::AWS
|
235
|
-
if cloud == "AWS"
|
236
|
-
resp = MU::Cloud::AWS.ec2(region: r, credentials: credset).describe_key_pairs(
|
237
|
-
filters: [{name: "key-name", values: [keyname]}]
|
238
|
-
)
|
239
|
-
resp.data.key_pairs.each { |keypair|
|
240
|
-
MU.log "Deleting key pair #{keypair.key_name} from #{r}"
|
241
|
-
MU::Cloud::AWS.ec2(region: r, credentials: credset).delete_key_pair(key_name: keypair.key_name) if !@noop
|
242
|
-
}
|
243
|
-
end
|
244
|
-
} # regionthreads << Thread.new {
|
245
|
-
} # acct_regions.each { |r|
|
246
|
-
regionthreads.each do |t|
|
247
|
-
t.join
|
248
|
-
end
|
249
|
-
|
250
|
-
} # credsets.each_pair { |credset, acct_regions|
|
97
|
+
cleanCloud(cloud, habitats, regions, credsets_inner)
|
251
98
|
} # cloudthreads << Thread.new(provider, credsets) { |cloud, credsets_outer|
|
252
99
|
cloudthreads.each do |t|
|
253
100
|
t.join
|
@@ -259,22 +106,19 @@ module MU
|
|
259
106
|
# once they're all done.
|
260
107
|
creds.each_pair { |provider, credsets_inner|
|
261
108
|
credsets_inner.keys.each { |credset|
|
262
|
-
next if credsused and
|
109
|
+
next if @credsused and !@credsused.include?(credset)
|
263
110
|
["Habitat", "Folder"].each { |t|
|
264
111
|
flags = {
|
265
112
|
"onlycloud" => @onlycloud,
|
266
113
|
"skipsnapshots" => @skipsnapshots
|
267
114
|
}
|
268
|
-
if !
|
115
|
+
if !call_cleanup(t, credset, provider, flags, nil)
|
269
116
|
had_failures = true
|
270
117
|
end
|
271
118
|
}
|
272
119
|
}
|
273
120
|
}
|
274
121
|
|
275
|
-
MU::Cloud::Google.removeDeploySecretsAndRoles(MU.deploy_id)
|
276
|
-
# XXX port AWS equivalent behavior and add a MU::Cloud wrapper
|
277
|
-
|
278
122
|
creds.each_pair { |provider, credsets_inner|
|
279
123
|
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(provider)
|
280
124
|
credsets_inner.keys.each { |c|
|
@@ -284,44 +128,16 @@ module MU
|
|
284
128
|
end
|
285
129
|
|
286
130
|
# Scrub any residual Chef records with matching tags
|
287
|
-
if !@onlycloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0) and
|
288
|
-
|
289
|
-
MU::Groomer
|
290
|
-
|
291
|
-
|
292
|
-
end
|
293
|
-
deadnodes = []
|
294
|
-
Chef::Config[:environment] = MU.environment
|
295
|
-
q = Chef::Search::Query.new
|
296
|
-
begin
|
297
|
-
q.search("node", "tags_MU-ID:#{MU.deploy_id}").each { |item|
|
298
|
-
next if item.is_a?(Integer)
|
299
|
-
item.each { |node|
|
300
|
-
deadnodes << node.name
|
301
|
-
}
|
302
|
-
}
|
303
|
-
rescue Net::HTTPServerException
|
304
|
-
end
|
305
|
-
|
306
|
-
begin
|
307
|
-
q.search("node", "name:#{MU.deploy_id}-*").each { |item|
|
308
|
-
next if item.is_a?(Integer)
|
309
|
-
item.each { |node|
|
310
|
-
deadnodes << node.name
|
311
|
-
}
|
312
|
-
}
|
313
|
-
rescue Net::HTTPServerException
|
314
|
-
end
|
315
|
-
MU.log "Missed some Chef resources in node cleanup, purging now", MU::NOTICE if deadnodes.size > 0
|
316
|
-
deadnodes.uniq.each { |node|
|
317
|
-
MU::Groomer::Chef.cleanup(node, [], noop)
|
318
|
-
}
|
319
|
-
rescue LoadError
|
320
|
-
end
|
131
|
+
if !@onlycloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0) and !@noop
|
132
|
+
MU.supportedGroomers.each { |g|
|
133
|
+
groomer = MU::Groomer.loadGroomer(g)
|
134
|
+
groomer.cleanup(MU.deploy_id, @noop)
|
135
|
+
}
|
321
136
|
end
|
322
137
|
|
323
138
|
if had_failures
|
324
139
|
MU.log "Had cleanup failures, exiting", MU::ERR
|
140
|
+
File.unlink("#{deploy_dir}/.cleanup") if !@noop
|
325
141
|
exit 1
|
326
142
|
end
|
327
143
|
|
@@ -329,99 +145,174 @@ module MU
|
|
329
145
|
@mommacat.purge!
|
330
146
|
end
|
331
147
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
ssharchive = "#{sshdir}/archive"
|
336
|
-
|
337
|
-
Dir.mkdir(sshdir, 0700) if !Dir.exist?(sshdir) and !@noop
|
338
|
-
Dir.mkdir(ssharchive, 0700) if !Dir.exist?(ssharchive) and !@noop
|
148
|
+
if !@onlycloud
|
149
|
+
MU::Master.purgeDeployFromSSH(MU.deploy_id, noop: @noop)
|
150
|
+
end
|
339
151
|
|
340
|
-
|
341
|
-
|
342
|
-
MU.log "Moving #{sshdir}/#{keyname} to #{ssharchive}/#{keyname}"
|
343
|
-
if !@noop
|
344
|
-
File.rename("#{sshdir}/#{keyname}", "#{ssharchive}/#{keyname}")
|
345
|
-
end
|
152
|
+
if !@noop and !@skipcloud and (@mommacat.nil? or @mommacat.numKittens(types: ["Server", "ServerPool"]) > 0)
|
153
|
+
# MU::Master.syncMonitoringConfig
|
346
154
|
end
|
347
155
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
end
|
362
|
-
newlines << line if !delete_block
|
363
|
-
}
|
364
|
-
f.rewind
|
365
|
-
f.truncate(0)
|
366
|
-
f.puts(newlines)
|
367
|
-
f.flush
|
368
|
-
f.flock(File::LOCK_UN)
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.listUsedCredentials(credsets)
|
159
|
+
creds = {}
|
160
|
+
MU::Cloud.availableClouds.each { |cloud|
|
161
|
+
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
162
|
+
if $MU_CFG[cloud.downcase] and $MU_CFG[cloud.downcase].size > 0
|
163
|
+
creds[cloud] ||= {}
|
164
|
+
cloudclass.listCredentials.each { |credset|
|
165
|
+
next if credsets and credsets.size > 0 and !credsets.include?(credset)
|
166
|
+
next if @credsused and @credsused.size > 0 and !@credsused.include?(credset)
|
167
|
+
MU.log "Will scan #{cloud} with credentials #{credset}"
|
168
|
+
creds[cloud][credset] = cloudclass.listRegions(credentials: credset)
|
369
169
|
}
|
170
|
+
else
|
171
|
+
if cloudclass.hosted?
|
172
|
+
creds[cloud] ||= {}
|
173
|
+
creds[cloud]["#default"] = cloudclass.listRegions
|
174
|
+
end
|
370
175
|
end
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
f.flock(File::LOCK_UN)
|
391
|
-
}
|
176
|
+
}
|
177
|
+
creds
|
178
|
+
end
|
179
|
+
private_class_method :listUsedCredentials
|
180
|
+
|
181
|
+
def self.cleanCloud(cloud, habitats, regions, credsets)
|
182
|
+
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
183
|
+
credsets.each_pair { |credset, acct_regions|
|
184
|
+
next if @credsused and !@credsused.include?(credset)
|
185
|
+
global_vs_region_semaphore = Mutex.new
|
186
|
+
global_done = {}
|
187
|
+
regionthreads = []
|
188
|
+
acct_regions.each { |r|
|
189
|
+
if @regionsused
|
190
|
+
if @regionsused.size > 0
|
191
|
+
next if !@regionsused.include?(r)
|
192
|
+
else
|
193
|
+
next if r != cloudclass.myRegion(credset)
|
194
|
+
end
|
392
195
|
end
|
393
|
-
|
394
|
-
|
196
|
+
if regions and !regions.empty?
|
197
|
+
next if !regions.include?(r)
|
198
|
+
MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{r}...", MU::NOTICE
|
199
|
+
end
|
200
|
+
regionthreads << Thread.new {
|
201
|
+
Thread.abort_on_exception = false
|
202
|
+
MU.setVar("curRegion", r)
|
203
|
+
cleanRegion(cloud, credset, r, global_vs_region_semaphore, global_done, habitats)
|
204
|
+
} # regionthreads << Thread.new {
|
205
|
+
} # acct_regions.each { |r|
|
206
|
+
regionthreads.each do |t|
|
207
|
+
t.join
|
395
208
|
end
|
396
|
-
|
209
|
+
}
|
210
|
+
end
|
211
|
+
private_class_method :cleanCloud
|
397
212
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
213
|
+
def self.cleanRegion(cloud, credset, region, global_vs_region_semaphore, global_done, habitats)
|
214
|
+
had_failures = false
|
215
|
+
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
216
|
+
habitatclass = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get("Habitat")
|
217
|
+
|
218
|
+
projects = []
|
219
|
+
if habitats
|
220
|
+
projects = habitats
|
221
|
+
else
|
222
|
+
if $MU_CFG and $MU_CFG[cloud.downcase] and
|
223
|
+
$MU_CFG[cloud.downcase][credset] and
|
224
|
+
$MU_CFG[cloud.downcase][credset]["project"]
|
225
|
+
# XXX GCP credential schema needs an array for projects
|
226
|
+
projects << $MU_CFG[cloud.downcase][credset]["project"]
|
404
227
|
end
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
228
|
+
begin
|
229
|
+
projects.concat(cloudclass.listHabitats(credset))
|
230
|
+
rescue NoMethodError
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
if projects == []
|
235
|
+
projects << "" # dummy
|
236
|
+
MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{region}", MU::NOTICE
|
237
|
+
end
|
238
|
+
projects.uniq!
|
239
|
+
|
240
|
+
# We do these in an order that unrolls dependent resources
|
241
|
+
# sensibly, and we hit :Collection twice because AWS
|
242
|
+
# CloudFormation sometimes fails internally.
|
243
|
+
projectthreads = []
|
244
|
+
projects.each { |project|
|
245
|
+
if habitats and !habitats.empty? and project != ""
|
246
|
+
next if !habitats.include?(project)
|
414
247
|
end
|
415
|
-
if
|
416
|
-
|
248
|
+
if @habitatsused and !@habitatsused.empty? and project != ""
|
249
|
+
next if !@habitatsused.include?(project)
|
417
250
|
end
|
251
|
+
next if !habitatclass.isLive?(project, credset)
|
252
|
+
|
253
|
+
projectthreads << Thread.new {
|
254
|
+
Thread.abort_on_exception = false
|
255
|
+
if !cleanHabitat(cloud, credset, region, project, global_vs_region_semaphore, global_done)
|
256
|
+
had_failures = true
|
257
|
+
end
|
258
|
+
} # TYPES_IN_ORDER.each { |t|
|
259
|
+
} # projects.each { |project|
|
260
|
+
projectthreads.each do |t|
|
261
|
+
t.join
|
418
262
|
end
|
419
263
|
|
420
|
-
|
421
|
-
|
264
|
+
had_failures
|
265
|
+
end
|
266
|
+
private_class_method :cleanRegion
|
267
|
+
|
268
|
+
def self.cleanHabitat(cloud, credset, region, habitat, global_vs_region_semaphore, global_done)
|
269
|
+
had_failures = false
|
270
|
+
if habitat != ""
|
271
|
+
MU.log "Checking for #{cloud}/#{credset} resources from #{MU.deploy_id} in #{region}, habitat #{habitat}", MU::NOTICE
|
422
272
|
end
|
423
273
|
|
274
|
+
flags = {
|
275
|
+
"habitat" => habitat,
|
276
|
+
"onlycloud" => @onlycloud,
|
277
|
+
"skipsnapshots" => @skipsnapshots,
|
278
|
+
}
|
279
|
+
TYPES_IN_ORDER.each { |t|
|
280
|
+
begin
|
281
|
+
skipme = false
|
282
|
+
global_vs_region_semaphore.synchronize {
|
283
|
+
MU::Cloud.loadCloudType(cloud, t)
|
284
|
+
if Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(t).isGlobal?
|
285
|
+
global_done[habitat] ||= []
|
286
|
+
if !global_done[habitat].include?(t)
|
287
|
+
global_done[habitat] << t
|
288
|
+
flags['global'] = true
|
289
|
+
else
|
290
|
+
skipme = true
|
291
|
+
end
|
292
|
+
end
|
293
|
+
}
|
294
|
+
next if skipme
|
295
|
+
rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented
|
296
|
+
next
|
297
|
+
rescue MU::MuError, NoMethodError => e
|
298
|
+
MU.log "While checking mu/clouds/#{cloud.downcase}/#{cloudclass.cfg_name} for global-ness in cleanup: "+e.message, MU::WARN
|
299
|
+
next
|
300
|
+
rescue ::Aws::EC2::Errors::AuthFailure, ::Google::Apis::ClientError => e
|
301
|
+
MU.log e.message+" in "+region, MU::ERR
|
302
|
+
next
|
303
|
+
end
|
304
|
+
|
305
|
+
begin
|
306
|
+
if !call_cleanup(t, credset, cloud, flags, region)
|
307
|
+
had_failures = true
|
308
|
+
end
|
309
|
+
rescue MU::Cloud::MuDefunctHabitat, MU::Cloud::MuCloudResourceNotImplemented
|
310
|
+
next
|
311
|
+
end
|
312
|
+
}
|
313
|
+
had_failures = true
|
424
314
|
end
|
315
|
+
private_class_method :cleanHabitat
|
425
316
|
|
426
317
|
# Wrapper for dynamically invoking resource type cleanup methods.
|
427
318
|
# @param type [String]:
|
@@ -444,24 +335,21 @@ module MU
|
|
444
335
|
flags['known'] << found.cloud_id
|
445
336
|
end
|
446
337
|
end
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
)
|
458
|
-
# rescue ::Seahorse::Client::NetworkingError => e
|
459
|
-
# MU.log "Service not available in AWS region #{r}, skipping", MU::DEBUG, details: e.message
|
460
|
-
# end
|
338
|
+
resclass = Object.const_get("MU").const_get("Cloud").const_get(type)
|
339
|
+
|
340
|
+
resclass.cleanup(
|
341
|
+
noop: @noop,
|
342
|
+
ignoremaster: @ignoremaster,
|
343
|
+
region: region,
|
344
|
+
cloud: provider,
|
345
|
+
flags: flags,
|
346
|
+
credentials: credset
|
347
|
+
)
|
461
348
|
else
|
462
349
|
true
|
463
350
|
end
|
464
|
-
|
465
351
|
end
|
352
|
+
private_class_method :call_cleanup
|
353
|
+
|
466
354
|
end #class
|
467
355
|
end #module
|