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
@@ -19,6 +19,34 @@ module MU
|
|
19
19
|
# the normal synchronous deploy sequence invoked by *mu-deploy*.
|
20
20
|
class MommaCat
|
21
21
|
|
22
|
+
# Given a cloud provider's native descriptor for a resource, make some
|
23
|
+
# reasonable guesses about what the thing's name should be.
|
24
|
+
def self.guessName(desc, resourceclass, cloud_id: nil, tag_value: nil)
|
25
|
+
if desc.respond_to?(:tags) and
|
26
|
+
desc.tags.is_a?(Array) and
|
27
|
+
desc.tags.first.respond_to?(:key) and
|
28
|
+
desc.tags.map { |t| t.key }.include?("Name")
|
29
|
+
desc.tags.select { |t| t.key == "Name" }.first.value
|
30
|
+
else
|
31
|
+
try = nil
|
32
|
+
# Various GCP fields
|
33
|
+
[:display_name, :name, (resourceclass.cfg_name+"_name").to_sym].each { |field|
|
34
|
+
if desc.respond_to?(field) and desc.send(field).is_a?(String)
|
35
|
+
try = desc.send(field)
|
36
|
+
break
|
37
|
+
end
|
38
|
+
|
39
|
+
}
|
40
|
+
try ||= if !tag_value.nil?
|
41
|
+
tag_value
|
42
|
+
else
|
43
|
+
cloud_id
|
44
|
+
end
|
45
|
+
try
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
22
50
|
# Generate a three-character string which can be used to unique-ify the
|
23
51
|
# names of resources which might potentially collide, e.g. Windows local
|
24
52
|
# hostnames, Amazon Elastic Load Balancers, or server pool instances.
|
@@ -0,0 +1,463 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2020 eGlobalTech, Inc., all rights reserved
|
2
|
+
#
|
3
|
+
# Licensed under the BSD-3 license (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License in the root of the project or at
|
6
|
+
#
|
7
|
+
# http://egt-labs.com/mu/LICENSE.html
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module MU
|
16
|
+
|
17
|
+
# MommaCat is in charge of managing metadata about resources we've created,
|
18
|
+
# as well as orchestrating amongst them and bootstrapping nodes outside of
|
19
|
+
# the normal synchronous deploy sequence invoked by *mu-deploy*.
|
20
|
+
class MommaCat
|
21
|
+
|
22
|
+
@@desc_semaphore = Mutex.new
|
23
|
+
|
24
|
+
# A search which returned multiple matches, but is not allowed to
|
25
|
+
class MultipleMatches < MuError
|
26
|
+
def initialize(message = nil)
|
27
|
+
super(message, silent: true)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Locate a resource that's either a member of another deployment, or of no
|
32
|
+
# deployment at all, and return a {MU::Cloud} object for it.
|
33
|
+
# @param cloud [String]: The Cloud provider to use.
|
34
|
+
# @param type [String]: The resource type. Can be the full class name, symbolic name, or Basket of Kittens configuration shorthand for the resource type.
|
35
|
+
# @param deploy_id [String]: The identifier of an outside deploy to search.
|
36
|
+
# @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field, typically used in conjunction with deploy_id.
|
37
|
+
# @param mu_name [String]: The fully-resolved and deployed name of the resource, typically used in conjunction with deploy_id.
|
38
|
+
# @param cloud_id [String]: A cloud provider identifier for this resource.
|
39
|
+
# @param region [String]: The cloud provider region
|
40
|
+
# @param tag_key [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_value.
|
41
|
+
# @param tag_value [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_key.
|
42
|
+
# @param allow_multi [Boolean]: Permit an array of matching resources to be returned (if applicable) instead of just one.
|
43
|
+
# @param dummy_ok [Boolean]: Permit return of a faked {MU::Cloud} object if we don't have enough information to identify a real live one.
|
44
|
+
# @return [Array<MU::Cloud>]
|
45
|
+
def self.findStray(cloud, type,
|
46
|
+
dummy_ok: false,
|
47
|
+
no_deploy_search: false,
|
48
|
+
allow_multi: false,
|
49
|
+
deploy_id: nil,
|
50
|
+
name: nil,
|
51
|
+
mu_name: nil,
|
52
|
+
cloud_id: nil,
|
53
|
+
credentials: nil,
|
54
|
+
region: nil,
|
55
|
+
tag_key: nil,
|
56
|
+
tag_value: nil,
|
57
|
+
calling_deploy: MU.mommacat,
|
58
|
+
habitats: [],
|
59
|
+
**flags
|
60
|
+
)
|
61
|
+
_shortclass, _cfg_name, type, _classname, _attrs = MU::Cloud.getResourceNames(type, true)
|
62
|
+
|
63
|
+
cloudclass = MU::Cloud.assertSupportedCloud(cloud)
|
64
|
+
return nil if cloudclass.virtual?
|
65
|
+
|
66
|
+
if (tag_key and !tag_value) or (!tag_key and tag_value)
|
67
|
+
raise MuError, "Can't call findStray with only one of tag_key and tag_value set, must be both or neither"
|
68
|
+
end
|
69
|
+
|
70
|
+
credlist = credentials ? [credentials] : cloudclass.listCredentials
|
71
|
+
|
72
|
+
# Help ourselves by making more refined parameters out of mu_name, if
|
73
|
+
# they weren't passed explicitly
|
74
|
+
if mu_name
|
75
|
+
# We can extract a deploy_id from mu_name if we don't have one already
|
76
|
+
deploy_id ||= mu_name.sub(/^(\w+-\w+-\d{10}-[A-Z]{2})-/, '\1')
|
77
|
+
if !tag_key and !tag_value
|
78
|
+
tag_key = "Name"
|
79
|
+
tag_value = mu_name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# See if the thing we're looking for is a member of the deploy that's
|
84
|
+
# asking after it.
|
85
|
+
if !deploy_id.nil? and !calling_deploy.nil? and
|
86
|
+
calling_deploy.deploy_id == deploy_id and (!name.nil? or !mu_name.nil?)
|
87
|
+
kitten = calling_deploy.findLitterMate(type: type, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
|
88
|
+
return [kitten] if !kitten.nil?
|
89
|
+
end
|
90
|
+
|
91
|
+
# See if we have it in deployment metadata generally
|
92
|
+
kittens = {}
|
93
|
+
if !no_deploy_search and (deploy_id or name or mu_name or cloud_id)
|
94
|
+
kittens = search_my_deploys(type, deploy_id: deploy_id, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
|
95
|
+
return kittens.values if kittens.size == 1
|
96
|
+
|
97
|
+
# We can't refine any further by asking the cloud provider...
|
98
|
+
if kittens.size > 1 and !allow_multi and
|
99
|
+
!cloud_id and !tag_key and !tag_value
|
100
|
+
raise MultipleMatches, "Multiple matches in MU::MommaCat.findStray where none allowed from #{cloud}, #{type}, name: #{name}, mu_name: #{mu_name}, cloud_id: #{cloud_id}, credentials: #{credentials}, habitats: #{habitats} (#{caller(1..1)})"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if !cloud_id and !(tag_key and tag_value) and (name or mu_name or deploy_id)
|
105
|
+
return kittens.values
|
106
|
+
end
|
107
|
+
matches = []
|
108
|
+
|
109
|
+
credlist.each { |creds|
|
110
|
+
cloud_descs = search_cloud_provider(type, cloud, habitats, region, cloud_id: cloud_id, tag_key: tag_key, tag_value: tag_value, credentials: creds, flags: flags)
|
111
|
+
|
112
|
+
cloud_descs.each_pair.each { |p, regions|
|
113
|
+
regions.each_pair.each { |r, results|
|
114
|
+
results.each_pair { |kitten_cloud_id, descriptor|
|
115
|
+
# We already have a MU::Cloud object for this guy, use it
|
116
|
+
if kittens.has_key?(kitten_cloud_id)
|
117
|
+
matches << kittens[kitten_cloud_id]
|
118
|
+
elsif dummy_ok and kittens.empty?
|
119
|
+
# XXX this is why this was threaded
|
120
|
+
matches << generate_dummy_object(type, cloud, name, mu_name, kitten_cloud_id, descriptor, r, p, tag_value, calling_deploy, creds)
|
121
|
+
end
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
matches
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return the resource object of another member of this deployment
|
131
|
+
# @param type [String,Symbol]: The type of resource
|
132
|
+
# @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field
|
133
|
+
# @param mu_name [String]: The fully-resolved and deployed name of the resource
|
134
|
+
# @param cloud_id [String]: The cloud provider's unique identifier for this resource
|
135
|
+
# @param created_only [Boolean]: Only return the littermate if its cloud_id method returns a value
|
136
|
+
# @param return_all [Boolean]: Return a Hash of matching objects indexed by their mu_name, instead of a single match. Only valid for resource types where has_multiples is true.
|
137
|
+
# @return [MU::Cloud]
|
138
|
+
def findLitterMate(type: nil, name: nil, mu_name: nil, cloud_id: nil, created_only: false, return_all: false, credentials: nil, habitat: nil, **flags)
|
139
|
+
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
|
140
|
+
|
141
|
+
# If we specified a habitat, which we may also have done by its shorthand
|
142
|
+
# sibling name, or a Ref. Convert to something we can use.
|
143
|
+
habitat = resolve_habitat(habitat, credentials: credentials)
|
144
|
+
|
145
|
+
nofilter = (mu_name.nil? and cloud_id.nil? and credentials.nil?)
|
146
|
+
|
147
|
+
does_match = Proc.new { |obj|
|
148
|
+
|
149
|
+
(!created_only or !obj.cloud_id.nil?) and (nofilter or (
|
150
|
+
(mu_name and obj.mu_name and mu_name.to_s == obj.mu_name) or
|
151
|
+
(cloud_id and obj.cloud_id and cloud_id.to_s == obj.cloud_id.to_s) or
|
152
|
+
(credentials and obj.credentials and credentials.to_s == obj.credentials.to_s) and
|
153
|
+
!(
|
154
|
+
(mu_name and obj.mu_name and mu_name.to_s != obj.mu_name) or
|
155
|
+
(cloud_id and obj.cloud_id and cloud_id.to_s != obj.cloud_id.to_s) or
|
156
|
+
(credentials and obj.credentials and credentials.to_s != obj.credentials.to_s)
|
157
|
+
)
|
158
|
+
))
|
159
|
+
}
|
160
|
+
|
161
|
+
@kitten_semaphore.synchronize {
|
162
|
+
return nil if !@kittens.has_key?(type)
|
163
|
+
matches = []
|
164
|
+
|
165
|
+
@kittens[type].each { |habitat_group, sib_classes|
|
166
|
+
next if habitat and habitat_group and habitat_group != habitat
|
167
|
+
sib_classes.each_pair { |sib_class, cloud_objs|
|
168
|
+
if attrs[:has_multiples]
|
169
|
+
next if !name.nil? and name != sib_class or cloud_objs.empty?
|
170
|
+
if !name.nil?
|
171
|
+
if return_all
|
172
|
+
return cloud_objs.dup
|
173
|
+
elsif cloud_objs.size == 1 and does_match.call(cloud_objs.values.first)
|
174
|
+
return cloud_objs.values.first
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
cloud_objs.each_value { |obj|
|
179
|
+
if does_match.call(obj)
|
180
|
+
return (return_all ? cloud_objs.clone : obj.clone)
|
181
|
+
end
|
182
|
+
}
|
183
|
+
# has_multiples is false
|
184
|
+
elsif (name.nil? and does_match.call(cloud_objs)) or [sib_class, cloud_objs.virtual_name(name)].include?(name.to_s)
|
185
|
+
matches << cloud_objs.clone
|
186
|
+
end
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
return matches.first if matches.size == 1
|
191
|
+
|
192
|
+
return matches if return_all and matches.size > 1
|
193
|
+
}
|
194
|
+
|
195
|
+
return nil
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
def resolve_habitat(habitat, credentials: nil, debug: false)
|
202
|
+
return nil if habitat.nil?
|
203
|
+
if habitat.is_a?(MU::Config::Ref) and habitat.id
|
204
|
+
return habitat.id
|
205
|
+
else
|
206
|
+
realhabitat = findLitterMate(type: "habitat", name: habitat, credentials: credentials)
|
207
|
+
if realhabitat and realhabitat.mu_name
|
208
|
+
return realhabitat.cloud_id
|
209
|
+
elsif debug
|
210
|
+
MU.log "Failed to resolve habitat name #{habitat}", MU::WARN
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.generate_dummy_object(type, cloud, name, mu_name, cloud_id, desc, region, habitat, tag_value, calling_deploy, credentials)
|
216
|
+
resourceclass = MU::Cloud.loadCloudType(cloud, type)
|
217
|
+
|
218
|
+
use_name = if (name.nil? or name.empty?)
|
219
|
+
if !mu_name.nil?
|
220
|
+
mu_name
|
221
|
+
else
|
222
|
+
guessName(desc, resourceclass, cloud_id: cloud_id, tag_value: tag_value)
|
223
|
+
end
|
224
|
+
else
|
225
|
+
name
|
226
|
+
end
|
227
|
+
|
228
|
+
if use_name.nil?
|
229
|
+
return
|
230
|
+
end
|
231
|
+
|
232
|
+
cfg = {
|
233
|
+
"name" => use_name,
|
234
|
+
"cloud" => cloud,
|
235
|
+
"credentials" => credentials
|
236
|
+
}
|
237
|
+
if !region.nil? and !resourceclass.isGlobal?
|
238
|
+
cfg["region"] = region
|
239
|
+
end
|
240
|
+
|
241
|
+
if resourceclass.canLiveIn.include?(:Habitat) and habitat
|
242
|
+
cfg["project"] = habitat
|
243
|
+
end
|
244
|
+
|
245
|
+
# If we can at least find the config from the deploy this will
|
246
|
+
# belong with, use that, even if it's an ungroomed resource.
|
247
|
+
if !calling_deploy.nil? and
|
248
|
+
!calling_deploy.original_config.nil? and
|
249
|
+
!calling_deploy.original_config[type+"s"].nil?
|
250
|
+
calling_deploy.original_config[type+"s"].each { |s|
|
251
|
+
if s["name"] == use_name
|
252
|
+
cfg = s.dup
|
253
|
+
break
|
254
|
+
end
|
255
|
+
}
|
256
|
+
|
257
|
+
return resourceclass.new(mommacat: calling_deploy, kitten_cfg: cfg, cloud_id: cloud_id)
|
258
|
+
else
|
259
|
+
if !@@dummy_cache[type] or !@@dummy_cache[type][cfg.to_s]
|
260
|
+
newobj = resourceclass.new(mu_name: use_name, kitten_cfg: cfg, cloud_id: cloud_id, from_cloud_desc: desc)
|
261
|
+
@@desc_semaphore.synchronize {
|
262
|
+
@@dummy_cache[type] ||= {}
|
263
|
+
@@dummy_cache[type][cfg.to_s] = newobj
|
264
|
+
}
|
265
|
+
end
|
266
|
+
return @@dummy_cache[type][cfg.to_s]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
private_class_method :generate_dummy_object
|
270
|
+
|
271
|
+
def self.search_cloud_provider(type, cloud, habitats, region, cloud_id: nil, tag_key: nil, tag_value: nil, credentials: nil, flags: nil)
|
272
|
+
cloudclass = MU::Cloud.assertSupportedCloud(cloud)
|
273
|
+
resourceclass = MU::Cloud.loadCloudType(cloud, type)
|
274
|
+
|
275
|
+
# Decide what regions we'll search, if applicable for this resource
|
276
|
+
# type.
|
277
|
+
regions = if resourceclass.isGlobal?
|
278
|
+
[nil]
|
279
|
+
else
|
280
|
+
region ? [region] : cloudclass.listRegions(credentials: credentials)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Decide what habitats (accounts/projects/subscriptions) we'll
|
284
|
+
# search, if applicable for this resource type.
|
285
|
+
habitats ||= []
|
286
|
+
if habitats.empty?
|
287
|
+
if resourceclass.canLiveIn.include?(nil)
|
288
|
+
habitats << nil
|
289
|
+
end
|
290
|
+
if resourceclass.canLiveIn.include?(:Habitat)
|
291
|
+
habitats.concat(cloudclass.listHabitats(credentials))
|
292
|
+
end
|
293
|
+
end
|
294
|
+
habitats << nil if habitats.empty?
|
295
|
+
habitats.uniq!
|
296
|
+
|
297
|
+
cloud_descs = {}
|
298
|
+
|
299
|
+
thread_waiter = Proc.new { |threads, threshold|
|
300
|
+
begin
|
301
|
+
threads.each { |t| t.join(0.1) }
|
302
|
+
threads.reject! { |t| t.nil? or !t.alive? or !t.status }
|
303
|
+
sleep 1 if threads.size > threshold
|
304
|
+
end while threads.size > threshold
|
305
|
+
}
|
306
|
+
|
307
|
+
habitat_threads = []
|
308
|
+
found_the_thing = false
|
309
|
+
habitats.each { |hab|
|
310
|
+
break if found_the_thing
|
311
|
+
thread_waiter.call(habitat_threads, 5)
|
312
|
+
|
313
|
+
habitat_threads << Thread.new(hab) { |habitat|
|
314
|
+
cloud_descs[habitat] = {}
|
315
|
+
region_threads = []
|
316
|
+
regions.each { |reg|
|
317
|
+
break if found_the_thing
|
318
|
+
region_threads << Thread.new(reg) { |r|
|
319
|
+
found = resourceclass.find(cloud_id: cloud_id, region: r, tag_key: tag_key, tag_value: tag_value, credentials: credentials, habitat: habitat, flags: flags)
|
320
|
+
|
321
|
+
if found
|
322
|
+
@@desc_semaphore.synchronize {
|
323
|
+
cloud_descs[habitat][r] = found
|
324
|
+
}
|
325
|
+
end
|
326
|
+
# Stop if you found the thing by a specific cloud_id
|
327
|
+
if cloud_id and found and !found.empty?
|
328
|
+
found_the_thing = true
|
329
|
+
end
|
330
|
+
}
|
331
|
+
}
|
332
|
+
thread_waiter.call(region_threads, 0)
|
333
|
+
}
|
334
|
+
}
|
335
|
+
thread_waiter.call(habitat_threads, 0)
|
336
|
+
|
337
|
+
cloud_descs
|
338
|
+
end
|
339
|
+
private_class_method :search_cloud_provider
|
340
|
+
|
341
|
+
def self.search_my_deploys(type, deploy_id: nil, name: nil, mu_name: nil, cloud_id: nil, credentials: nil)
|
342
|
+
kittens = {}
|
343
|
+
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type, true)
|
344
|
+
|
345
|
+
# Check our in-memory cache of live deploys before resorting to
|
346
|
+
# metadata
|
347
|
+
littercache = nil
|
348
|
+
# Sometimes we're called inside a locked thread, sometimes not. Deal
|
349
|
+
# with locking gracefully.
|
350
|
+
begin
|
351
|
+
@@litter_semaphore.synchronize {
|
352
|
+
littercache = @@litters.dup
|
353
|
+
}
|
354
|
+
rescue ThreadError => e
|
355
|
+
raise e if !e.message.match(/recursive locking/)
|
356
|
+
littercache = @@litters.dup
|
357
|
+
end
|
358
|
+
|
359
|
+
# First, see what we have in deploys that already happen to be loaded in
|
360
|
+
# memory.
|
361
|
+
littercache.each_pair { |cur_deploy, momma|
|
362
|
+
next if deploy_id and deploy_id != cur_deploy
|
363
|
+
|
364
|
+
@@deploy_struct_semaphore.synchronize {
|
365
|
+
@deploy_cache[deploy_id] = {
|
366
|
+
"mtime" => Time.now,
|
367
|
+
"data" => momma.deployment
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
straykitten = momma.findLitterMate(type: type, cloud_id: cloud_id, name: name, mu_name: mu_name, credentials: credentials, created_only: true)
|
372
|
+
if straykitten
|
373
|
+
MU.log "Found matching kitten #{straykitten.mu_name} in-memory - #{sprintf("%.2fs", (Time.now-start))}", MU::DEBUG
|
374
|
+
# Peace out if we found the exact resource we want
|
375
|
+
if cloud_id and straykitten.cloud_id.to_s == cloud_id.to_s
|
376
|
+
return { straykitten.cloud_id => straykitten }
|
377
|
+
elsif mu_name and straykitten.mu_name == mu_name
|
378
|
+
return { straykitten.cloud_id => straykitten }
|
379
|
+
else
|
380
|
+
kittens[straykitten.cloud_id] ||= straykitten
|
381
|
+
end
|
382
|
+
end
|
383
|
+
}
|
384
|
+
|
385
|
+
# Now go rifle metadata from any other deploys we have on disk, if they
|
386
|
+
# weren't already there in memory.
|
387
|
+
cacheDeployMetadata(deploy_id) # freshen up @@deploy_cache
|
388
|
+
mu_descs = {}
|
389
|
+
if deploy_id.nil?
|
390
|
+
@@deploy_cache.each_key { |deploy|
|
391
|
+
next if littercache[deploy]
|
392
|
+
next if !@@deploy_cache[deploy].has_key?('data')
|
393
|
+
next if !@@deploy_cache[deploy]['data'].has_key?(type)
|
394
|
+
if !name.nil?
|
395
|
+
next if @@deploy_cache[deploy]['data'][type][name].nil?
|
396
|
+
mu_descs[deploy] ||= []
|
397
|
+
mu_descs[deploy] << @@deploy_cache[deploy]['data'][type][name].dup
|
398
|
+
else
|
399
|
+
mu_descs[deploy] ||= []
|
400
|
+
mu_descs[deploy].concat(@@deploy_cache[deploy]['data'][type].values)
|
401
|
+
end
|
402
|
+
}
|
403
|
+
elsif !@@deploy_cache[deploy_id].nil?
|
404
|
+
if !@@deploy_cache[deploy_id]['data'].nil? and
|
405
|
+
!@@deploy_cache[deploy_id]['data'][type].nil?
|
406
|
+
if !name.nil? and !@@deploy_cache[deploy_id]['data'][type][name].nil?
|
407
|
+
mu_descs[deploy_id] ||= []
|
408
|
+
mu_descs[deploy_id] << @@deploy_cache[deploy_id]['data'][type][name].dup
|
409
|
+
else
|
410
|
+
mu_descs[deploy_id] = @@deploy_cache[deploy_id]['data'][type].values
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
mu_descs.each_pair { |deploy, matches|
|
416
|
+
next if matches.nil? or matches.size == 0
|
417
|
+
momma = MU::MommaCat.getLitter(deploy)
|
418
|
+
|
419
|
+
# If we found exactly one match in this deploy, use its metadata to
|
420
|
+
# guess at resource names we weren't told.
|
421
|
+
straykitten = if matches.size > 1 and cloud_id
|
422
|
+
momma.findLitterMate(type: type, cloud_id: cloud_id, credentials: credentials, created_only: true)
|
423
|
+
elsif matches.size == 1 and (!attrs[:has_multiples] or matches.first.size == 1) and name.nil? and mu_name.nil?
|
424
|
+
actual_data = attrs[:has_multiples] ? matches.first.values.first : matches.first
|
425
|
+
if cloud_id.nil?
|
426
|
+
momma.findLitterMate(type: type, name: (actual_data["name"] || actual_data["MU_NODE_CLASS"]), cloud_id: actual_data["cloud_id"], credentials: credentials)
|
427
|
+
else
|
428
|
+
momma.findLitterMate(type: type, name: (actual_data["name"] || actual_data["MU_NODE_CLASS"]), cloud_id: cloud_id, credentials: credentials)
|
429
|
+
end
|
430
|
+
else
|
431
|
+
# There's more than one of this type of resource in the target
|
432
|
+
# deploy, so see if findLitterMate can narrow it down for us
|
433
|
+
momma.findLitterMate(type: type, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
|
434
|
+
end
|
435
|
+
|
436
|
+
next if straykitten.nil?
|
437
|
+
straykitten.intoDeploy(momma)
|
438
|
+
|
439
|
+
if straykitten.cloud_id.nil?
|
440
|
+
MU.log "findStray: kitten #{straykitten.mu_name} came back with nil cloud_id", MU::WARN
|
441
|
+
next
|
442
|
+
end
|
443
|
+
next if cloud_id and straykitten.cloud_id.to_s != cloud_id.to_s
|
444
|
+
|
445
|
+
# Peace out if we found the exact resource we want
|
446
|
+
if (cloud_id and straykitten.cloud_id.to_s == cloud_id.to_s) or
|
447
|
+
(mu_descs.size == 1 and matches.size == 1) or
|
448
|
+
(credentials and straykitten.credentials == credentials)
|
449
|
+
# XXX strictly speaking this last check is only valid if findStray is searching
|
450
|
+
# exactly one set of credentials
|
451
|
+
|
452
|
+
return { straykitten.cloud_id => straykitten }
|
453
|
+
end
|
454
|
+
|
455
|
+
kittens[straykitten.cloud_id] ||= straykitten
|
456
|
+
}
|
457
|
+
|
458
|
+
kittens
|
459
|
+
end
|
460
|
+
private_class_method :search_my_deploys
|
461
|
+
|
462
|
+
end #class
|
463
|
+
end #module
|