cloud-mu 3.1.4 → 3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +5 -1
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- 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/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +36 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/bin/mu-adopt +16 -12
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +52 -0
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-load-config.rb +2 -1
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +37 -12
- data/cloud-mu.gemspec +5 -3
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/libraries/helper.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +18 -13
- data/extras/image-generators/AWS/win2k16.yaml +18 -13
- data/extras/image-generators/AWS/win2k19.yaml +21 -0
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +158 -107
- data/modules/mu/adoption.rb +386 -59
- data/modules/mu/cleanup.rb +214 -303
- data/modules/mu/cloud.rb +128 -1632
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +44 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +926 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +169 -0
- data/modules/mu/config.rb +135 -82
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +32 -3
- data/modules/mu/config/cache_cluster.rb +2 -2
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/collection.rb +1 -1
- data/modules/mu/config/container_cluster.rb +7 -2
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +5 -4
- data/modules/mu/config/doc_helpers.rb +5 -6
- data/modules/mu/config/endpoint.rb +2 -1
- data/modules/mu/config/firewall_rule.rb +3 -19
- data/modules/mu/config/folder.rb +1 -1
- data/modules/mu/config/function.rb +17 -8
- data/modules/mu/config/group.rb +1 -1
- data/modules/mu/config/habitat.rb +1 -1
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +57 -11
- data/modules/mu/config/log.rb +1 -1
- data/modules/mu/config/msg_queue.rb +1 -1
- data/modules/mu/config/nosqldb.rb +1 -1
- data/modules/mu/config/notifier.rb +8 -19
- data/modules/mu/config/ref.rb +92 -14
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/schema_helpers.rb +38 -37
- data/modules/mu/config/search_domain.rb +1 -1
- data/modules/mu/config/server.rb +12 -13
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/config/server_pool.rb +3 -7
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +11 -0
- data/modules/mu/config/user.rb +1 -1
- data/modules/mu/config/vpc.rb +27 -23
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +91 -68
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +1 -0
- data/modules/mu/deploy.rb +33 -19
- data/modules/mu/groomer.rb +16 -1
- data/modules/mu/groomers/ansible.rb +123 -21
- data/modules/mu/groomers/chef.rb +64 -11
- data/modules/mu/logger.rb +120 -144
- data/modules/mu/master.rb +97 -4
- data/modules/mu/master/ssl.rb +0 -1
- data/modules/mu/mommacat.rb +154 -867
- data/modules/mu/mommacat/daemon.rb +23 -14
- data/modules/mu/mommacat/naming.rb +110 -3
- data/modules/mu/mommacat/search.rb +495 -0
- data/modules/mu/mommacat/storage.rb +225 -192
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +281 -64
- data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +708 -749
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +75 -57
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +212 -242
- data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/function.rb +289 -134
- data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
- data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
- data/modules/mu/providers/aws/job.rb +466 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +50 -41
- data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
- data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
- data/modules/mu/{clouds → providers}/aws/role.rb +94 -57
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +173 -42
- data/modules/mu/{clouds → providers}/aws/server.rb +782 -1107
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +36 -46
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
- data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
- data/modules/mu/{clouds → providers}/aws/vpc.rb +429 -849
- data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
- data/modules/mu/{clouds → providers}/azure.rb +13 -0
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
- data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
- data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
- data/modules/mu/{clouds → providers}/cloudformation.rb +10 -0
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +29 -6
- data/modules/mu/{clouds → providers}/google/bucket.rb +5 -5
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +59 -37
- data/modules/mu/{clouds → providers}/google/database.rb +5 -12
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +5 -5
- data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
- data/modules/mu/{clouds → providers}/google/function.rb +14 -8
- data/modules/mu/{clouds → providers}/google/group.rb +9 -17
- data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/google/role.rb +50 -31
- data/modules/mu/{clouds → providers}/google/server.rb +142 -55
- data/modules/mu/{clouds → providers}/google/server_pool.rb +14 -14
- data/modules/mu/{clouds → providers}/google/user.rb +34 -24
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +46 -15
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/centos6.yaml +15 -0
- data/modules/tests/centos7.yaml +15 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +23 -0
- data/modules/tests/eks.yaml +1 -1
- data/modules/tests/functions/node-function/lambda_function.js +10 -0
- data/modules/tests/functions/python-function/lambda_function.py +12 -0
- data/modules/tests/includes-and-params.yaml +2 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +2 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +3 -5
- data/modules/tests/win2k12.yaml +25 -0
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +169 -93
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/mu/clouds/aws/database.rb +0 -1974
- data/modules/mu/clouds/aws/endpoint.rb +0 -596
- data/modules/tests/needwork/win2k12.yaml +0 -13
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, regions: [], merge: false, pattern: nil)
|
34
34
|
@scraped = {}
|
35
35
|
@clouds = clouds
|
36
36
|
@types = types
|
@@ -44,7 +44,11 @@ module MU
|
|
44
44
|
@savedeploys = savedeploys
|
45
45
|
@diff = diff
|
46
46
|
@habitats = habitats
|
47
|
+
@regions = regions
|
47
48
|
@habitats ||= []
|
49
|
+
@scrub_mu_isms = scrub_mu_isms
|
50
|
+
@merge = merge
|
51
|
+
@pattern = pattern
|
48
52
|
end
|
49
53
|
|
50
54
|
# Walk cloud providers with available credentials to discover resources
|
@@ -52,7 +56,7 @@ module MU
|
|
52
56
|
@default_parent = nil
|
53
57
|
|
54
58
|
@clouds.each { |cloud|
|
55
|
-
cloudclass =
|
59
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
56
60
|
next if cloudclass.listCredentials.nil?
|
57
61
|
|
58
62
|
if cloud == "Google" and !@parent and @target_creds
|
@@ -64,6 +68,10 @@ module MU
|
|
64
68
|
|
65
69
|
cloudclass.listCredentials.each { |credset|
|
66
70
|
next if @sources and !@sources.include?(credset)
|
71
|
+
cfg = cloudclass.credConfig(credset)
|
72
|
+
if cfg and cfg['restrict_to_habitats']
|
73
|
+
cfg['restrict_to_habitats'] << cfg['project'] if cfg['project']
|
74
|
+
end
|
67
75
|
|
68
76
|
if @parent
|
69
77
|
# TODO handle different inputs (cloud_id, etc)
|
@@ -84,7 +92,7 @@ module MU
|
|
84
92
|
|
85
93
|
@types.each { |type|
|
86
94
|
begin
|
87
|
-
resclass =
|
95
|
+
resclass = MU::Cloud.resourceClass(cloud, type)
|
88
96
|
rescue ::MU::Cloud::MuCloudResourceNotImplemented
|
89
97
|
next
|
90
98
|
end
|
@@ -100,17 +108,31 @@ module MU
|
|
100
108
|
credentials: credset,
|
101
109
|
allow_multi: true,
|
102
110
|
habitats: @habitats.dup,
|
111
|
+
region: @regions,
|
103
112
|
dummy_ok: true,
|
104
|
-
|
105
|
-
|
113
|
+
skip_provider_owned: true,
|
114
|
+
# debug: false#,
|
106
115
|
)
|
107
116
|
|
108
117
|
|
109
118
|
if found and found.size > 0
|
119
|
+
if resclass.cfg_plural == "habitats"
|
120
|
+
found.reject! { |h|
|
121
|
+
!cloudclass.listHabitats(credset).include?(h.cloud_id)
|
122
|
+
}
|
123
|
+
end
|
110
124
|
MU.log "Found #{found.size.to_s} raw #{resclass.cfg_plural} in #{cloud}"
|
111
125
|
@scraped[type] ||= {}
|
112
126
|
found.each { |obj|
|
127
|
+
if obj.habitat and !cloudclass.listHabitats(credset).include?(obj.habitat)
|
128
|
+
next
|
129
|
+
end
|
130
|
+
|
113
131
|
# XXX apply any filters (e.g. MU-ID tags)
|
132
|
+
if obj.cloud_id.nil?
|
133
|
+
MU.log "This damn thing gave me no cloud id, what do I even do with that", MU::ERR, details: obj
|
134
|
+
exit
|
135
|
+
end
|
114
136
|
@scraped[type][obj.cloud_id] = obj
|
115
137
|
}
|
116
138
|
end
|
@@ -188,33 +210,62 @@ module MU
|
|
188
210
|
prefix = "mu" if prefix.empty? # so that appnames aren't ever empty
|
189
211
|
end
|
190
212
|
|
213
|
+
# Find any previous deploys with this particular profile, which we'll use
|
214
|
+
# later for --diff.
|
215
|
+
@existing_deploys = {}
|
216
|
+
@existing_deploys_by_id = {}
|
217
|
+
@origins = {}
|
218
|
+
@types_found_in = {}
|
191
219
|
groupings.each_pair { |appname, types|
|
192
|
-
bok = { "appname" => prefix+appname }
|
193
|
-
if @target_creds
|
194
|
-
bok["credentials"] = @target_creds
|
195
|
-
end
|
196
|
-
|
197
|
-
count = 0
|
198
220
|
allowed_types = @types.map { |t| MU::Cloud.resource_types[t][:cfg_plural] }
|
199
221
|
next if (types & allowed_types).size == 0
|
200
222
|
origin = {
|
201
|
-
"appname" =>
|
223
|
+
"appname" => prefix+appname,
|
202
224
|
"types" => (types & allowed_types).sort,
|
203
225
|
"habitats" => @habitats.sort,
|
204
226
|
"group_by" => @group_by.to_s
|
205
227
|
}
|
206
228
|
|
207
|
-
|
208
|
-
if @
|
209
|
-
|
210
|
-
|
229
|
+
@existing_deploys[appname] = MU::MommaCat.findMatchingDeploy(origin)
|
230
|
+
if @existing_deploys[appname]
|
231
|
+
@existing_deploys_by_id[@existing_deploys[appname].deploy_id] = @existing_deploys[appname]
|
232
|
+
@origins[appname] = origin
|
233
|
+
origin['types'].each { |t|
|
234
|
+
@types_found_in[t] = @existing_deploys[appname]
|
235
|
+
}
|
236
|
+
end
|
237
|
+
}
|
238
|
+
|
239
|
+
groupings.each_pair { |appname, types|
|
240
|
+
allowed_types = @types.map { |t| MU::Cloud.resource_types[t][:cfg_plural] }
|
241
|
+
next if (types & allowed_types).size == 0
|
242
|
+
|
243
|
+
bok = { "appname" => prefix+appname }
|
244
|
+
if @scrub_mu_isms
|
245
|
+
bok["scrub_mu_isms"] = true
|
246
|
+
end
|
247
|
+
if @target_creds
|
248
|
+
bok["credentials"] = @target_creds
|
249
|
+
end
|
250
|
+
|
251
|
+
count = 0
|
252
|
+
if @diff
|
253
|
+
if !@existing_deploys[appname]
|
254
|
+
MU.log "--diff was set but I failed to find a deploy like '#{appname}' to compare to (have #{@existing_deploys.keys.join(", ")})", MU::ERR, details: @origins[appname]
|
255
|
+
exit 1
|
256
|
+
else
|
257
|
+
MU.log "Will diff current live resources against #{@existing_deploys[appname].deploy_id}", MU::NOTICE, details: @origins[appname]
|
258
|
+
end
|
211
259
|
end
|
212
260
|
|
213
261
|
threads = []
|
262
|
+
timers = {}
|
263
|
+
walltimers = {}
|
214
264
|
@clouds.each { |cloud|
|
215
265
|
@scraped.each_pair { |type, resources|
|
266
|
+
typestart = Time.now
|
216
267
|
res_class = begin
|
217
|
-
MU::Cloud.
|
268
|
+
MU::Cloud.resourceClass(cloud, type)
|
218
269
|
rescue MU::Cloud::MuCloudResourceNotImplemented
|
219
270
|
# XXX I don't think this can actually happen
|
220
271
|
next
|
@@ -222,19 +273,35 @@ module MU
|
|
222
273
|
next if !types.include?(res_class.cfg_plural)
|
223
274
|
|
224
275
|
bok[res_class.cfg_plural] ||= []
|
276
|
+
timers[type] ||= {}
|
225
277
|
|
226
278
|
class_semaphore = Mutex.new
|
227
279
|
|
228
280
|
Thread.abort_on_exception = true
|
229
281
|
resources.values.each { |obj_thr|
|
282
|
+
obj_desc = nil
|
283
|
+
begin
|
284
|
+
obj_desc = obj_thr.cloud_desc
|
285
|
+
rescue StandardError
|
286
|
+
ensure
|
287
|
+
if !obj_desc
|
288
|
+
MU.log cloud+" "+type.to_s+" "+obj_thr.cloud_id+" did not return a cloud descriptor, skipping", MU::WARN
|
289
|
+
next
|
290
|
+
end
|
291
|
+
end
|
230
292
|
threads << Thread.new(obj_thr) { |obj|
|
293
|
+
start = Time.now
|
231
294
|
|
232
|
-
kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats)
|
233
|
-
if kitten_cfg
|
295
|
+
kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats, types: @types)
|
296
|
+
if kitten_cfg and (!@pattern or @pattern.match(kitten_cfg['name']))
|
234
297
|
print "."
|
235
298
|
kitten_cfg.delete("credentials") if @target_creds
|
236
299
|
class_semaphore.synchronize {
|
237
300
|
bok[res_class.cfg_plural] << kitten_cfg
|
301
|
+
if !kitten_cfg['cloud_id']
|
302
|
+
MU.log "No cloud id in this #{res_class.cfg_name} kitten!", MU::ERR, details: kitten_cfg
|
303
|
+
end
|
304
|
+
timers[type][kitten_cfg['cloud_id']] = (Time.now - start)
|
238
305
|
}
|
239
306
|
count += 1
|
240
307
|
end
|
@@ -245,6 +312,7 @@ module MU
|
|
245
312
|
threads.each { |t|
|
246
313
|
t.join
|
247
314
|
}
|
315
|
+
|
248
316
|
puts ""
|
249
317
|
bok[res_class.cfg_plural].sort! { |a, b|
|
250
318
|
strs = [a, b].map { |x|
|
@@ -266,24 +334,30 @@ module MU
|
|
266
334
|
bok[res_class.cfg_plural].each { |sibling|
|
267
335
|
next if kitten_cfg == sibling
|
268
336
|
if sibling['name'] == kitten_cfg['name']
|
269
|
-
MU.
|
270
|
-
if kitten_cfg['parent'] and kitten_cfg['parent'].respond_to?(:id) and kitten_cfg['parent'].id
|
271
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['parent'].id
|
272
|
-
elsif kitten_cfg['project']
|
273
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['project']
|
274
|
-
elsif kitten_cfg['region']
|
275
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['region']
|
276
|
-
elsif kitten_cfg['cloud_id']
|
277
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['cloud_id'].gsub(/[^a-z0-9]/i, "-")
|
278
|
-
else
|
279
|
-
raise MU::Config::DuplicateNameError, "Saw duplicate #{res_class.cfg_name} name #{sibling['name']} and couldn't come up with a good way to differentiate them"
|
280
|
-
end
|
337
|
+
MU::Adoption.deDuplicateName(kitten_cfg, res_class)
|
281
338
|
MU.log "De-duplication: Renamed #{res_class.cfg_name} name '#{sibling['name']}' => '#{kitten_cfg['name']}'", MU::NOTICE
|
282
339
|
break
|
283
340
|
end
|
284
341
|
}
|
285
342
|
}
|
343
|
+
walltimers[type] ||= 0
|
344
|
+
walltimers[type] += (Time.now - typestart)
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
timers.each_pair { |type, resources|
|
349
|
+
next if resources.empty?
|
350
|
+
total = resources.values.sum
|
351
|
+
top_5 = resources.keys.sort { |a, b|
|
352
|
+
resources[b] <=> resources[a]
|
353
|
+
}.slice(0, 5).map { |k|
|
354
|
+
k.to_s+": "+sprintf("%.2fs", resources[k])
|
286
355
|
}
|
356
|
+
if walltimers[type] < 45
|
357
|
+
MU.log "Kittened #{resources.size.to_s} eligible #{type}s in #{sprintf("%.2fs", walltimers[type])}"
|
358
|
+
else
|
359
|
+
MU.log "Kittened #{resources.size.to_s} eligible #{type}s in #{sprintf("%.2fs", walltimers[type])} (CPU time #{sprintf("%.2fs", total)}, avg #{sprintf("%.2fs", total/resources.size)}). Top 5:", MU::NOTICE, details: top_5
|
360
|
+
end
|
287
361
|
}
|
288
362
|
|
289
363
|
# No matching resources isn't necessarily an error
|
@@ -292,23 +366,36 @@ module MU
|
|
292
366
|
# Now walk through all of the Refs in these objects, resolve them, and minimize
|
293
367
|
# their config footprint
|
294
368
|
MU.log "Minimizing footprint of #{count.to_s} found resources", MU::DEBUG
|
295
|
-
@boks[bok['appname']] = vacuum(bok, origin: origin, save: @savedeploys)
|
296
369
|
|
297
|
-
|
370
|
+
generated_deploy = generateStubDeploy(bok)
|
371
|
+
@boks[bok['appname']] = vacuum(bok, origin: @origins[appname], deploy: generated_deploy, save: @savedeploys)
|
372
|
+
|
373
|
+
if @diff and !@existing_deploys[appname]
|
298
374
|
MU.log "diff flag set, but no comparable deploy provided for #{bok['appname']}", MU::ERR
|
299
375
|
exit 1
|
300
376
|
end
|
301
377
|
|
302
|
-
if
|
303
|
-
|
378
|
+
if @diff
|
379
|
+
prev_vacuumed = vacuum(@existing_deploys[appname].original_config, deploy: @existing_deploys[appname], keep_missing: true, copy_from: generated_deploy)
|
380
|
+
prevcfg = MU::Config.manxify(prev_vacuumed)
|
304
381
|
if !prevcfg
|
305
|
-
MU.log "#{
|
382
|
+
MU.log "#{@existing_deploys[appname].deploy_id} didn't have a working original config for me to compare", MU::ERR
|
306
383
|
exit 1
|
307
384
|
end
|
308
385
|
newcfg = MU::Config.manxify(@boks[bok['appname']])
|
386
|
+
report = prevcfg.diff(newcfg)
|
387
|
+
|
388
|
+
if report
|
389
|
+
|
390
|
+
if MU.muCfg['adopt_change_notify']
|
391
|
+
notifyChanges(@existing_deploys[appname], report.freeze)
|
392
|
+
end
|
393
|
+
if @merge
|
394
|
+
MU.log "Saving changes to #{@existing_deploys[appname].deploy_id}"
|
395
|
+
@existing_deploys[appname].updateBasketofKittens(newcfg, save_now: true)
|
396
|
+
end
|
397
|
+
end
|
309
398
|
|
310
|
-
prevcfg.diff(newcfg)
|
311
|
-
exit
|
312
399
|
end
|
313
400
|
}
|
314
401
|
@boks
|
@@ -316,6 +403,183 @@ module MU
|
|
316
403
|
|
317
404
|
private
|
318
405
|
|
406
|
+
# @param tier [Hash]
|
407
|
+
# @param parent_key [String]
|
408
|
+
def crawlChangeReport(tier, parent_key = nil, indent: "")
|
409
|
+
report = []
|
410
|
+
if tier.is_a?(Array)
|
411
|
+
tier.each { |a|
|
412
|
+
sub_report = crawlChangeReport(a, parent_key)
|
413
|
+
report.concat(sub_report) if sub_report and !sub_report.empty?
|
414
|
+
}
|
415
|
+
elsif tier.is_a?(Hash)
|
416
|
+
if tier[:action]
|
417
|
+
preposition = if tier[:action] == :added
|
418
|
+
"to"
|
419
|
+
elsif tier[:action] == :removed
|
420
|
+
"from"
|
421
|
+
else
|
422
|
+
"in"
|
423
|
+
end
|
424
|
+
|
425
|
+
name = ""
|
426
|
+
type_of = parent_key.sub(/s$|\[.*/, '') if parent_key
|
427
|
+
loc = tier[:habitat]
|
428
|
+
|
429
|
+
if tier[:value] and tier[:value].is_a?(Hash)
|
430
|
+
name, loc = MU::MommaCat.getChunkName(tier[:value], type_of)
|
431
|
+
elsif parent_key
|
432
|
+
name = parent_key
|
433
|
+
end
|
434
|
+
|
435
|
+
path_str = []
|
436
|
+
slack_path_str = ""
|
437
|
+
if tier[:parents] and tier[:parents].size > 2
|
438
|
+
path = tier[:parents].clone
|
439
|
+
slack_path_str += "#{preposition} \*"+path.join(" ⇨ ")+"\*" if path.size > 0
|
440
|
+
path.shift
|
441
|
+
path.shift
|
442
|
+
path.pop if path.last == name
|
443
|
+
for c in (0..(path.size-1)) do
|
444
|
+
path_str << (" " * (c+2)) + (path[c] || "<nil>")
|
445
|
+
end
|
446
|
+
end
|
447
|
+
path_str << "" if !path_str.empty?
|
448
|
+
|
449
|
+
plain = (name ? name : type_of) if name or type_of
|
450
|
+
plain ||= "" # XXX but this is a problem
|
451
|
+
slack = "`"+plain+"`"
|
452
|
+
|
453
|
+
plain += " ("+loc+")" if loc and !loc.empty?
|
454
|
+
color = plain
|
455
|
+
|
456
|
+
if tier[:action] == :added
|
457
|
+
color = "+ ".green + plain
|
458
|
+
plain = "+ " + plain
|
459
|
+
slack += " added"
|
460
|
+
elsif tier[:action] == :removed
|
461
|
+
color = "- ".red + plain
|
462
|
+
plain = "- " + plain
|
463
|
+
slack += " removed"
|
464
|
+
end
|
465
|
+
|
466
|
+
slack += " #{tier[:action]} #{preposition} \*#{loc}\*" if loc and !loc.empty? and [Array, Hash].include?(tier[:value].class)
|
467
|
+
|
468
|
+
plain = path_str.join(" => \n") + indent + plain
|
469
|
+
color = path_str.join(" => \n") + indent + color
|
470
|
+
|
471
|
+
slack += " "+slack_path_str if !slack_path_str.empty?
|
472
|
+
myreport = {
|
473
|
+
"slack" => slack,
|
474
|
+
"plain" => plain,
|
475
|
+
"color" => color
|
476
|
+
}
|
477
|
+
|
478
|
+
append = ""
|
479
|
+
if tier[:value] and (tier[:value].is_a?(Array) or tier[:value].is_a?(Hash))
|
480
|
+
if tier[:value].is_a?(Hash)
|
481
|
+
if name
|
482
|
+
tier[:value].delete("entity")
|
483
|
+
tier[:value].delete(name.sub(/\[.*/, '')) if name
|
484
|
+
end
|
485
|
+
if (tier[:value].keys - ["id", "name", "type"]).size > 0
|
486
|
+
myreport["details"] = tier[:value].clone
|
487
|
+
append = PP.pp(tier[:value], '').gsub(/(^|\n)/, '\1'+indent)
|
488
|
+
end
|
489
|
+
else
|
490
|
+
append = indent+"["+tier[:value].map { |v| MU::MommaCat.getChunkName(v, type_of).reverse.join("/") || v.to_s.light_blue }.join(", ")+"]"
|
491
|
+
slack += " #{tier[:action].to_s}: "+tier[:value].map { |v| MU::MommaCat.getChunkName(v, type_of).reverse.join("/") || v.to_s }.join(", ")
|
492
|
+
end
|
493
|
+
else
|
494
|
+
tier[:value] ||= "<nil>"
|
495
|
+
if ![:removed].include?(tier[:action])
|
496
|
+
myreport["slack"] += ". New #{tier[:field] ? "`"+tier[:field]+"`" : :value}: \*#{tier[:value]}\*"
|
497
|
+
else
|
498
|
+
myreport["slack"] += " (was \*#{tier[:value]}\*)"
|
499
|
+
end
|
500
|
+
append = tier[:value].to_s.bold
|
501
|
+
end
|
502
|
+
|
503
|
+
if append and !append.empty?
|
504
|
+
myreport["plain"] += " =>\n "+indent+append
|
505
|
+
myreport["color"] += " =>\n "+indent+append
|
506
|
+
end
|
507
|
+
|
508
|
+
report << myreport if tier[:action]
|
509
|
+
end
|
510
|
+
|
511
|
+
# Just because we've got changes at this level doesn't mean there aren't
|
512
|
+
# more further down.
|
513
|
+
tier.each_pair { |k, v|
|
514
|
+
next if !(v.is_a?(Hash) or v.is_a?(Array))
|
515
|
+
sub_report = crawlChangeReport(v, k, indent: indent+" ")
|
516
|
+
report.concat(sub_report) if sub_report and !sub_report.empty?
|
517
|
+
}
|
518
|
+
end
|
519
|
+
|
520
|
+
report
|
521
|
+
end
|
522
|
+
|
523
|
+
|
524
|
+
def notifyChanges(deploy, report)
|
525
|
+
snippet_threshold = (MU.muCfg['adopt_change_notify'] && MU.muCfg['adopt_change_notify']['slack_snippet_threshold']) || 5
|
526
|
+
|
527
|
+
report.each_pair { |res_type, resources|
|
528
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(res_type, false)
|
529
|
+
next if !shortclass # we don't really care about Mu metadata changes
|
530
|
+
resources.each_pair { |name, data|
|
531
|
+
if MU::MommaCat.getChunkName(data[:value], res_type).first.nil?
|
532
|
+
symbol = if data[:action] == :added
|
533
|
+
"+".green
|
534
|
+
elsif data[:action] == :removed
|
535
|
+
"-".red
|
536
|
+
else
|
537
|
+
"~".yellow
|
538
|
+
end
|
539
|
+
puts (symbol+" "+res_type+"["+name+"]")
|
540
|
+
end
|
541
|
+
|
542
|
+
noun = shortclass ? shortclass.to_s : res_type.capitalize
|
543
|
+
verb = if data[:action]
|
544
|
+
data[:action].to_s
|
545
|
+
else
|
546
|
+
"modified"
|
547
|
+
end
|
548
|
+
|
549
|
+
changes = crawlChangeReport(data.freeze, res_type)
|
550
|
+
|
551
|
+
slacktext = "#{noun} \*#{name}\* was #{verb}"
|
552
|
+
if data[:habitat]
|
553
|
+
slacktext += " in \*#{data[:habitat]}\*"
|
554
|
+
end
|
555
|
+
snippets = []
|
556
|
+
|
557
|
+
if [:added, :removed].include?(data[:action]) and data[:value]
|
558
|
+
snippets << { text: "```"+JSON.pretty_generate(data[:value])+"```" }
|
559
|
+
else
|
560
|
+
changes.each { |c|
|
561
|
+
slacktext += "\n • "+c["slack"]
|
562
|
+
if c["details"]
|
563
|
+
details = JSON.pretty_generate(c["details"])
|
564
|
+
snippets << { text: "```"+JSON.pretty_generate(c["details"])+"```" }
|
565
|
+
end
|
566
|
+
}
|
567
|
+
end
|
568
|
+
|
569
|
+
changes.each { |c|
|
570
|
+
puts c["color"]
|
571
|
+
}
|
572
|
+
puts ""
|
573
|
+
|
574
|
+
if MU.muCfg['adopt_change_notify'] and MU.muCfg['adopt_change_notify']['slack']
|
575
|
+
deploy.sendAdminSlack(slacktext, scrub_mu_isms: MU.muCfg['adopt_scrub_mu_isms'], snippets: snippets, noop: false)
|
576
|
+
end
|
577
|
+
|
578
|
+
}
|
579
|
+
}
|
580
|
+
|
581
|
+
end
|
582
|
+
|
319
583
|
def scrubSchemaDefaults(conf_chunk, schema_chunk, depth = 0, type: nil)
|
320
584
|
return if schema_chunk.nil?
|
321
585
|
|
@@ -323,7 +587,7 @@ module MU
|
|
323
587
|
deletia = []
|
324
588
|
schema_chunk["properties"].each_pair { |key, subschema|
|
325
589
|
next if !conf_chunk[key]
|
326
|
-
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key)
|
590
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key, false)
|
327
591
|
|
328
592
|
if subschema["default_if"]
|
329
593
|
subschema["default_if"].each { |cond|
|
@@ -347,8 +611,7 @@ module MU
|
|
347
611
|
# theory
|
348
612
|
realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"] and MU::Cloud.supportedClouds.include?(item['cloud'])
|
349
613
|
|
350
|
-
|
351
|
-
_toplevel_required, cloudschema = cloudclass.schema(self)
|
614
|
+
_toplevel_required, cloudschema = MU::Cloud.resourceClass(item['cloud'], type).schema(self)
|
352
615
|
|
353
616
|
newschema = schema_chunk["items"].dup
|
354
617
|
newschema["properties"].merge!(cloudschema)
|
@@ -372,8 +635,7 @@ module MU
|
|
372
635
|
# Do the same for our main objects: if they all use the same credentials,
|
373
636
|
# for example, remove the explicit +credentials+ attributes and set that
|
374
637
|
# value globally, once.
|
375
|
-
def vacuum(bok, origin: nil, save: false, deploy: nil)
|
376
|
-
deploy ||= generateStubDeploy(bok)
|
638
|
+
def vacuum(bok, origin: nil, save: false, deploy: nil, copy_from: nil, keep_missing: false)
|
377
639
|
|
378
640
|
globals = {
|
379
641
|
'cloud' => {},
|
@@ -393,11 +655,24 @@ module MU
|
|
393
655
|
end
|
394
656
|
}
|
395
657
|
obj = deploy.findLitterMate(type: attrs[:cfg_plural], name: resource['name'])
|
658
|
+
inject_metadata = save
|
659
|
+
if obj.nil? and copy_from
|
660
|
+
obj = copy_from.findLitterMate(type: attrs[:cfg_plural], name: resource['name'])
|
661
|
+
if obj
|
662
|
+
inject_metadata = true
|
663
|
+
obj.intoDeploy(deploy, force: true)
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
396
667
|
begin
|
397
668
|
raise Incomplete if obj.nil?
|
669
|
+
if inject_metadata
|
670
|
+
deploydata = obj.notify
|
671
|
+
deploy.notify(attrs[:cfg_plural], resource['name'], deploydata, triggering_node: obj)
|
672
|
+
end
|
398
673
|
new_cfg = resolveReferences(resource, deploy, obj)
|
399
674
|
new_cfg.delete("cloud_id")
|
400
|
-
cred_cfg = MU::Cloud.
|
675
|
+
cred_cfg = MU::Cloud.cloudClass(obj.cloud).credConfig(obj.credentials)
|
401
676
|
if cred_cfg['region'] == new_cfg['region']
|
402
677
|
new_cfg.delete('region')
|
403
678
|
end
|
@@ -407,6 +682,11 @@ module MU
|
|
407
682
|
end
|
408
683
|
processed << new_cfg
|
409
684
|
rescue Incomplete
|
685
|
+
if keep_missing
|
686
|
+
processed << resource
|
687
|
+
else
|
688
|
+
MU.log "#{attrs[:cfg_name]} #{resource['name']} didn't show up from findLitterMate", MU::WARN, details: deploy.original_config[attrs[:cfg_plural]].reject { |r| r['name'] != "" }
|
689
|
+
end
|
410
690
|
end
|
411
691
|
}
|
412
692
|
|
@@ -417,24 +697,23 @@ module MU
|
|
417
697
|
|
418
698
|
# Pare out global values like +cloud+ or +region+ that appear to be
|
419
699
|
# universal in the deploy we're creating.
|
420
|
-
|
700
|
+
scrub_globals = Proc.new { |h, field|
|
421
701
|
if h.is_a?(Hash)
|
422
702
|
newhash = {}
|
423
703
|
h.each_pair { |k, v|
|
424
704
|
next if k == field
|
425
|
-
newhash[k] = scrub_globals(v, field)
|
705
|
+
newhash[k] = scrub_globals.call(v, field)
|
426
706
|
}
|
427
707
|
h = newhash
|
428
708
|
elsif h.is_a?(Array)
|
429
709
|
newarr = []
|
430
710
|
h.each { |v|
|
431
|
-
newarr << scrub_globals(v, field)
|
711
|
+
newarr << scrub_globals.call(v, field)
|
432
712
|
}
|
433
|
-
h = newarr
|
713
|
+
h = newarr.uniq
|
434
714
|
end
|
435
|
-
|
436
715
|
h
|
437
|
-
|
716
|
+
}
|
438
717
|
|
439
718
|
globals.each_pair { |field, counts|
|
440
719
|
next if counts.size != 1
|
@@ -444,7 +723,7 @@ module MU
|
|
444
723
|
if bok[attrs[:cfg_plural]]
|
445
724
|
new_resources = []
|
446
725
|
bok[attrs[:cfg_plural]].each { |resource|
|
447
|
-
new_resources << scrub_globals(resource, field)
|
726
|
+
new_resources << scrub_globals.call(resource, field)
|
448
727
|
}
|
449
728
|
bok[attrs[:cfg_plural]] = new_resources
|
450
729
|
end
|
@@ -462,9 +741,33 @@ module MU
|
|
462
741
|
end
|
463
742
|
|
464
743
|
def resolveReferences(cfg, deploy, parent)
|
744
|
+
mask_deploy_id = false
|
745
|
+
|
746
|
+
check_deploy_id = Proc.new { |cfgblob|
|
747
|
+
(deploy and
|
748
|
+
(cfgblob.is_a?(MU::Config::Ref) or cfgblob.is_a?(Hash)) and
|
749
|
+
cfgblob['deploy_id'] and
|
750
|
+
cfgblob['deploy_id'] != deploy.deploy_id and
|
751
|
+
@diff and
|
752
|
+
@types_found_in[cfgblob['type']] and
|
753
|
+
@types_found_in[cfgblob['type']].deploy_id == cfgblob['deploy_id']
|
754
|
+
)
|
755
|
+
}
|
756
|
+
|
757
|
+
mask_deploy_id = check_deploy_id.call(cfg)
|
758
|
+
|
465
759
|
if cfg.is_a?(MU::Config::Ref)
|
760
|
+
if mask_deploy_id
|
761
|
+
cfg.delete("deploy_id")
|
762
|
+
cfg.delete("mommacat")
|
763
|
+
cfg.kitten(deploy)
|
764
|
+
else
|
765
|
+
cfg.kitten(deploy) || cfg.kitten
|
766
|
+
end
|
767
|
+
|
466
768
|
hashcfg = cfg.to_h
|
467
|
-
|
769
|
+
|
770
|
+
if cfg.kitten
|
468
771
|
littermate = deploy.findLitterMate(type: cfg.type, name: cfg.name, cloud_id: cfg.id, habitat: cfg.habitat)
|
469
772
|
|
470
773
|
if littermate and littermate.config['name']
|
@@ -486,16 +789,15 @@ module MU
|
|
486
789
|
hashcfg.delete("name") if cfg.id and !cfg.deploy_id
|
487
790
|
end
|
488
791
|
end
|
489
|
-
elsif hashcfg["id"]
|
792
|
+
elsif hashcfg["id"] and !hashcfg["name"]
|
490
793
|
hashcfg.delete("deploy_id")
|
491
|
-
hashcfg.delete("name")
|
492
794
|
else
|
493
|
-
|
494
|
-
raise Incomplete, "Failed to resolve reference on behalf of #{parent}"
|
795
|
+
raise Incomplete.new "Failed to resolve reference on behalf of #{parent}", details: hashcfg
|
495
796
|
end
|
496
797
|
hashcfg.delete("deploy_id") if hashcfg['deploy_id'] == deploy.deploy_id
|
798
|
+
|
497
799
|
if parent and parent.config
|
498
|
-
cred_cfg = MU::Cloud.
|
800
|
+
cred_cfg = MU::Cloud.cloudClass(parent.cloud).credConfig(parent.credentials)
|
499
801
|
|
500
802
|
if parent.config['region'] == hashcfg['region'] or
|
501
803
|
cred_cfg['region'] == hashcfg['region']
|
@@ -554,7 +856,12 @@ module MU
|
|
554
856
|
MU.log "Dropping unresolved value", MU::WARN, details: value
|
555
857
|
end
|
556
858
|
}
|
557
|
-
cfg = new_array
|
859
|
+
cfg = new_array.uniq
|
860
|
+
end
|
861
|
+
|
862
|
+
if mask_deploy_id or check_deploy_id.call(cfg)
|
863
|
+
cfg.delete("deploy_id")
|
864
|
+
MU.log "#{parent} in #{deploy.deploy_id} references something in #{@types_found_in[cfg['type']].deploy_id}, ditching extraneous deploy_id", MU::DEBUG, details: cfg.to_h
|
558
865
|
end
|
559
866
|
|
560
867
|
cfg
|
@@ -604,6 +911,10 @@ module MU
|
|
604
911
|
|
605
912
|
if !@scraped[typename][kitten['cloud_id']]
|
606
913
|
MU.log "No object in scraped tree for #{attrs[:cfg_name]} #{kitten['cloud_id']} (#{kitten['name']})", MU::ERR, details: kitten
|
914
|
+
if kitten['cloud_id'].nil?
|
915
|
+
pp caller
|
916
|
+
exit
|
917
|
+
end
|
607
918
|
next
|
608
919
|
end
|
609
920
|
|
@@ -614,7 +925,8 @@ module MU
|
|
614
925
|
deploy.addKitten(
|
615
926
|
attrs[:cfg_plural],
|
616
927
|
kitten['name'],
|
617
|
-
@scraped[typename][kitten['cloud_id']]
|
928
|
+
@scraped[typename][kitten['cloud_id']],
|
929
|
+
do_notify: true
|
618
930
|
)
|
619
931
|
}
|
620
932
|
end
|
@@ -623,6 +935,21 @@ module MU
|
|
623
935
|
deploy
|
624
936
|
end
|
625
937
|
|
938
|
+
def self.deDuplicateName(kitten_cfg, res_class)
|
939
|
+
orig_name = kitten_cfg['name'].dup
|
940
|
+
if kitten_cfg['parent'] and kitten_cfg['parent'].respond_to?(:id) and kitten_cfg['parent'].id
|
941
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['parent'].id
|
942
|
+
elsif kitten_cfg['project']
|
943
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['project']
|
944
|
+
elsif kitten_cfg['region']
|
945
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['region']
|
946
|
+
elsif kitten_cfg['cloud_id']
|
947
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['cloud_id'].gsub(/[^a-z0-9]/i, "-")
|
948
|
+
else
|
949
|
+
raise MU::Config::DuplicateNameError, "Saw duplicate #{res_class.cfg_name} name #{orig_name} and couldn't come up with a good way to differentiate them"
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
626
953
|
# Go through everything we've scraped and update our mappings of cloud ids
|
627
954
|
# and bare name fields, so that resources can reference one another
|
628
955
|
# portably by name.
|