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/mu/master.rb
CHANGED
@@ -386,6 +386,7 @@ module MU
|
|
386
386
|
best = nil
|
387
387
|
best_version = nil
|
388
388
|
paths.uniq.each { |path|
|
389
|
+
path.sub!(/^~/, MY_HOME)
|
389
390
|
if File.exist?(path+"/kubectl")
|
390
391
|
version = %x{#{path}/kubectl version --short --client}.chomp.sub(/.*Client version:\s+v/i, '')
|
391
392
|
next if !$?.success?
|
@@ -546,7 +547,7 @@ module MU
|
|
546
547
|
rescue Errno::ECONNRESET, Errno::ECONNREFUSED
|
547
548
|
end
|
548
549
|
if response != "ok"
|
549
|
-
MU.log "
|
550
|
+
MU.log "Unable to add #{public_ip} to /etc/hosts via MommaCat request", MU::WARN
|
550
551
|
end
|
551
552
|
return
|
552
553
|
end
|
@@ -709,6 +710,77 @@ module MU
|
|
709
710
|
end
|
710
711
|
end
|
711
712
|
|
713
|
+
# Evict ssh keys associated with a particular deploy from our ssh config
|
714
|
+
# and key directory.
|
715
|
+
# @param deploy_id [String]
|
716
|
+
# @param noop [Boolean]
|
717
|
+
def self.purgeDeployFromSSH(deploy_id, noop: false)
|
718
|
+
myhome = Etc.getpwuid(Process.uid).dir
|
719
|
+
sshdir = "#{myhome}/.ssh"
|
720
|
+
sshconf = "#{sshdir}/config"
|
721
|
+
ssharchive = "#{sshdir}/archive"
|
722
|
+
|
723
|
+
Dir.mkdir(sshdir, 0700) if !Dir.exist?(sshdir) and !noop
|
724
|
+
Dir.mkdir(ssharchive, 0700) if !Dir.exist?(ssharchive) and !noop
|
725
|
+
|
726
|
+
keyname = "deploy-#{deploy_id}"
|
727
|
+
if File.exist?("#{sshdir}/#{keyname}")
|
728
|
+
MU.log "Moving #{sshdir}/#{keyname} to #{ssharchive}/#{keyname}"
|
729
|
+
if !noop
|
730
|
+
File.rename("#{sshdir}/#{keyname}", "#{ssharchive}/#{keyname}")
|
731
|
+
end
|
732
|
+
end
|
733
|
+
if File.exist?(sshconf) and File.open(sshconf).read.match(/\/deploy\-#{deploy_id}$/)
|
734
|
+
MU.log "Expunging #{deploy_id} from #{sshconf}"
|
735
|
+
if !noop
|
736
|
+
FileUtils.copy(sshconf, "#{ssharchive}/config-#{deploy_id}")
|
737
|
+
File.open(sshconf, File::CREAT|File::RDWR, 0600) { |f|
|
738
|
+
f.flock(File::LOCK_EX)
|
739
|
+
newlines = Array.new
|
740
|
+
delete_block = false
|
741
|
+
f.readlines.each { |line|
|
742
|
+
if line.match(/^Host #{deploy_id}\-/)
|
743
|
+
delete_block = true
|
744
|
+
elsif line.match(/^Host /)
|
745
|
+
delete_block = false
|
746
|
+
end
|
747
|
+
newlines << line if !delete_block
|
748
|
+
}
|
749
|
+
f.rewind
|
750
|
+
f.truncate(0)
|
751
|
+
f.puts(newlines)
|
752
|
+
f.flush
|
753
|
+
f.flock(File::LOCK_UN)
|
754
|
+
}
|
755
|
+
end
|
756
|
+
end
|
757
|
+
# XXX refactor with above? They're similar, ish.
|
758
|
+
hostsfile = "/etc/hosts"
|
759
|
+
if File.open(hostsfile).read.match(/ #{deploy_id}\-/)
|
760
|
+
if Process.uid == 0
|
761
|
+
MU.log "Expunging traces of #{deploy_id} from #{hostsfile}"
|
762
|
+
if !noop
|
763
|
+
FileUtils.copy(hostsfile, "#{hostsfile}.cleanup-#{deploy_id}")
|
764
|
+
File.open(hostsfile, File::CREAT|File::RDWR, 0644) { |f|
|
765
|
+
f.flock(File::LOCK_EX)
|
766
|
+
newlines = Array.new
|
767
|
+
f.readlines.each { |line|
|
768
|
+
newlines << line if !line.match(/ #{deploy_id}\-/)
|
769
|
+
}
|
770
|
+
f.rewind
|
771
|
+
f.truncate(0)
|
772
|
+
f.puts(newlines)
|
773
|
+
f.flush
|
774
|
+
f.flock(File::LOCK_UN)
|
775
|
+
}
|
776
|
+
end
|
777
|
+
else
|
778
|
+
MU.log "Residual /etc/hosts entries for #{deploy_id} must be removed by root user", MU::WARN
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
end
|
783
|
+
|
712
784
|
# Ensure that the Nagios configuration local to the MU master has been
|
713
785
|
# updated, and make sure Nagios has all of the ssh keys it needs to tunnel
|
714
786
|
# to client nodes.
|
@@ -738,7 +810,7 @@ module MU
|
|
738
810
|
ssh_conf.puts " IdentityFile #{NAGIOS_HOME}/.ssh/id_rsa"
|
739
811
|
ssh_conf.puts " StrictHostKeyChecking no"
|
740
812
|
ssh_conf.close
|
741
|
-
FileUtils.cp("#{
|
813
|
+
FileUtils.cp("#{Etc.getpwuid(Process.uid).dir}/.ssh/id_rsa", "#{NAGIOS_HOME}/.ssh/id_rsa")
|
742
814
|
File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/id_rsa")
|
743
815
|
threads = []
|
744
816
|
|
@@ -751,7 +823,7 @@ module MU
|
|
751
823
|
MU.log "Failed to extract ssh key name from #{deploy_id} in syncMonitoringConfig", MU::ERR if deploy.kittens.has_key?("servers")
|
752
824
|
next
|
753
825
|
end
|
754
|
-
FileUtils.cp("#{
|
826
|
+
FileUtils.cp("#{Etc.getpwuid(Process.uid).dir}/.ssh/#{deploy.ssh_key_name}", "#{NAGIOS_HOME}/.ssh/#{deploy.ssh_key_name}")
|
755
827
|
File.chown(Etc.getpwnam("nagios").uid, Etc.getpwnam("nagios").gid, "#{NAGIOS_HOME}/.ssh/#{deploy.ssh_key_name}")
|
756
828
|
if deploy.kittens.has_key?("servers")
|
757
829
|
deploy.kittens["servers"].values.each { |nodeclasses|
|
data/modules/mu/mommacat.rb
CHANGED
@@ -19,6 +19,7 @@ require 'stringio'
|
|
19
19
|
require 'securerandom'
|
20
20
|
require 'timeout'
|
21
21
|
require 'mu/mommacat/storage'
|
22
|
+
require 'mu/mommacat/search'
|
22
23
|
require 'mu/mommacat/daemon'
|
23
24
|
require 'mu/mommacat/naming'
|
24
25
|
|
@@ -154,7 +155,7 @@ module MU
|
|
154
155
|
if @mu_user == "root"
|
155
156
|
@chef_user = "mu"
|
156
157
|
else
|
157
|
-
@chef_user = @mu_user.dup.
|
158
|
+
@chef_user = @mu_user.dup.delete(".")
|
158
159
|
@mu_user = "root" if @mu_user == "mu"
|
159
160
|
end
|
160
161
|
@kitten_semaphore = Mutex.new
|
@@ -187,54 +188,10 @@ module MU
|
|
187
188
|
end
|
188
189
|
|
189
190
|
if create and !@no_artifacts
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
end
|
194
|
-
path = File.expand_path(MU.dataDir+"/deployments")+"/"+@deploy_id
|
195
|
-
if !Dir.exist?(path)
|
196
|
-
MU.log "Creating #{path}", MU::DEBUG
|
197
|
-
Dir.mkdir(path, 0700)
|
198
|
-
end
|
199
|
-
if @original_config.nil? or !@original_config.is_a?(Hash)
|
200
|
-
raise DeployInitializeError, "New MommaCat repository requires config hash"
|
201
|
-
end
|
202
|
-
credsets = {}
|
203
|
-
|
204
|
-
MU::Cloud.resource_types.values.each { |attrs|
|
205
|
-
if !@original_config[attrs[:cfg_plural]].nil? and @original_config[attrs[:cfg_plural]].size > 0
|
206
|
-
@original_config[attrs[:cfg_plural]].each { |resource|
|
207
|
-
|
208
|
-
credsets[resource['cloud']] ||= []
|
209
|
-
credsets[resource['cloud']] << resource['credentials']
|
210
|
-
@clouds[resource['cloud']] = 0 if !@clouds.has_key?(resource['cloud'])
|
211
|
-
@clouds[resource['cloud']] = @clouds[resource['cloud']] + 1
|
212
|
-
|
213
|
-
}
|
214
|
-
end
|
215
|
-
}
|
216
|
-
|
217
|
-
@ssh_key_name, @ssh_private_key, @ssh_public_key = self.SSHKey
|
218
|
-
if !File.exist?(deploy_dir+"/private_key")
|
219
|
-
@private_key, @public_key = createDeployKey
|
220
|
-
end
|
221
|
-
MU.log "Creating deploy secret for #{MU.deploy_id}"
|
222
|
-
@deploy_secret = Password.random(256)
|
223
|
-
if !@original_config['scrub_mu_isms'] and !@no_artifacts
|
224
|
-
credsets.each_pair { |cloud, creds|
|
225
|
-
creds.uniq!
|
226
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
227
|
-
creds.each { |credentials|
|
228
|
-
cloudclass.writeDeploySecret(@deploy_id, @deploy_secret, credentials: credentials)
|
229
|
-
}
|
230
|
-
}
|
231
|
-
end
|
232
|
-
if set_context_to_me
|
233
|
-
MU::MommaCat.setThreadContext(self)
|
234
|
-
end
|
235
|
-
|
191
|
+
initDeployDirectory
|
192
|
+
setDeploySecret
|
193
|
+
MU::MommaCat.setThreadContext(self) if set_context_to_me
|
236
194
|
save!
|
237
|
-
|
238
195
|
end
|
239
196
|
|
240
197
|
@appname ||= MU.appname
|
@@ -242,10 +199,8 @@ module MU
|
|
242
199
|
@environment ||= MU.environment
|
243
200
|
|
244
201
|
loadDeploy(set_context_to_me: set_context_to_me)
|
245
|
-
if !deploy_secret.nil?
|
246
|
-
|
247
|
-
raise DeployInitializeError, "Client request did not include a valid deploy authorization secret. Verify that userdata runs correctly?"
|
248
|
-
end
|
202
|
+
if !deploy_secret.nil? and !authKey(deploy_secret)
|
203
|
+
raise DeployInitializeError, "Client request did not include a valid deploy authorization secret. Verify that userdata runs correctly?"
|
249
204
|
end
|
250
205
|
|
251
206
|
|
@@ -257,86 +212,7 @@ module MU
|
|
257
212
|
# deploy, IF it already exists, which is to say if we're loading an
|
258
213
|
# existing deploy instead of creating a new one.
|
259
214
|
if !create and @deployment and @original_config and !skip_resource_objects
|
260
|
-
|
261
|
-
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
262
|
-
type = attrs[:cfg_plural]
|
263
|
-
if @deployment.has_key?(type)
|
264
|
-
|
265
|
-
@deployment[type].each_pair { |res_name, data|
|
266
|
-
orig_cfg = nil
|
267
|
-
if @original_config.has_key?(type)
|
268
|
-
@original_config[type].each { |resource|
|
269
|
-
if resource["name"] == res_name
|
270
|
-
orig_cfg = resource
|
271
|
-
break
|
272
|
-
end
|
273
|
-
}
|
274
|
-
end
|
275
|
-
|
276
|
-
# Some Server objects originated from ServerPools, get their
|
277
|
-
# configs from there
|
278
|
-
if type == "servers" and orig_cfg.nil? and
|
279
|
-
@original_config.has_key?("server_pools")
|
280
|
-
@original_config["server_pools"].each { |resource|
|
281
|
-
if resource["name"] == res_name
|
282
|
-
orig_cfg = resource
|
283
|
-
break
|
284
|
-
end
|
285
|
-
}
|
286
|
-
end
|
287
|
-
|
288
|
-
if orig_cfg.nil?
|
289
|
-
MU.log "Failed to locate original config for #{attrs[:cfg_name]} #{res_name} in #{@deploy_id}", MU::WARN if !["firewall_rules", "databases", "storage_pools", "cache_clusters", "alarms"].include?(type) # XXX shaddap
|
290
|
-
next
|
291
|
-
end
|
292
|
-
|
293
|
-
if orig_cfg['vpc'] and orig_cfg['vpc'].is_a?(Hash)
|
294
|
-
ref = if orig_cfg['vpc']['id'] and orig_cfg['vpc']['id'].is_a?(Hash)
|
295
|
-
orig_cfg['vpc']['id']['mommacat'] = self
|
296
|
-
MU::Config::Ref.get(orig_cfg['vpc']['id'])
|
297
|
-
else
|
298
|
-
orig_cfg['vpc']['mommacat'] = self
|
299
|
-
MU::Config::Ref.get(orig_cfg['vpc'])
|
300
|
-
end
|
301
|
-
orig_cfg['vpc'].delete('mommacat')
|
302
|
-
orig_cfg['vpc'] = ref if ref.kitten(shallow: true)
|
303
|
-
end
|
304
|
-
|
305
|
-
begin
|
306
|
-
# Load up MU::Cloud objects for all our kittens in this deploy
|
307
|
-
orig_cfg['environment'] = @environment # not always set in old deploys
|
308
|
-
if attrs[:has_multiples]
|
309
|
-
data.keys.each { |mu_name|
|
310
|
-
attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: mu_name, delay_descriptor_load: delay_descriptor_load)
|
311
|
-
}
|
312
|
-
else
|
313
|
-
# XXX hack for old deployments, this can go away some day
|
314
|
-
if data['mu_name'].nil? or data['mu_name'].empty?
|
315
|
-
if res_type.to_s == "LoadBalancer" and !data['awsname'].nil?
|
316
|
-
data['mu_name'] = data['awsname'].dup
|
317
|
-
elsif res_type.to_s == "FirewallRule" and !data['group_name'].nil?
|
318
|
-
data['mu_name'] = data['group_name'].dup
|
319
|
-
elsif res_type.to_s == "Database" and !data['identifier'].nil?
|
320
|
-
data['mu_name'] = data['identifier'].dup.upcase
|
321
|
-
elsif res_type.to_s == "VPC"
|
322
|
-
# VPC names are deterministic, just generate the things
|
323
|
-
data['mu_name'] = getResourceName(data['name'])
|
324
|
-
end
|
325
|
-
end
|
326
|
-
if data['mu_name'].nil?
|
327
|
-
raise MuError, "Unable to find or guess a Mu name for #{res_type}: #{res_name} in #{@deploy_id}"
|
328
|
-
end
|
329
|
-
attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: data['mu_name'], cloud_id: data['cloud_id'])
|
330
|
-
end
|
331
|
-
rescue StandardError => e
|
332
|
-
if e.class != MU::Cloud::MuCloudResourceNotImplemented
|
333
|
-
MU.log "Failed to load an existing resource of type '#{type}' in #{@deploy_id}: #{e.inspect}", MU::WARN, details: e.backtrace
|
334
|
-
end
|
335
|
-
end
|
336
|
-
}
|
337
|
-
|
338
|
-
end
|
339
|
-
}
|
215
|
+
loadObjects(delay_descriptor_load)
|
340
216
|
end
|
341
217
|
|
342
218
|
@initializing = false
|
@@ -349,7 +225,7 @@ module MU
|
|
349
225
|
def cloudsUsed
|
350
226
|
seen = []
|
351
227
|
seen << @original_config['cloud'] if @original_config['cloud']
|
352
|
-
MU::Cloud.resource_types.
|
228
|
+
MU::Cloud.resource_types.each_value { |attrs|
|
353
229
|
type = attrs[:cfg_plural]
|
354
230
|
if @original_config[type]
|
355
231
|
@original_config[type].each { |resource|
|
@@ -369,18 +245,15 @@ module MU
|
|
369
245
|
# clouds = []
|
370
246
|
seen << @original_config['credentials'] if @original_config['credentials']
|
371
247
|
# defaultcloud = @original_config['cloud']
|
372
|
-
MU::Cloud.resource_types.
|
248
|
+
MU::Cloud.resource_types.each_value { |attrs|
|
373
249
|
type = attrs[:cfg_plural]
|
374
250
|
if @original_config[type]
|
375
251
|
@original_config[type].each { |resource|
|
376
252
|
if resource['credentials']
|
377
253
|
seen << resource['credentials']
|
378
254
|
else
|
379
|
-
|
380
|
-
|
381
|
-
else
|
382
|
-
Object.const_get("MU").const_get("Cloud").const_get(MU::Config.defaultCloud)
|
383
|
-
end
|
255
|
+
cloudconst = @original_config['cloud'] ? @original_config['cloud'] : MU::Config.defaultCloud
|
256
|
+
Object.const_get("MU").const_get("Cloud").const_get(cloudconst)
|
384
257
|
seen << cloudclass.credConfig(name_only: true)
|
385
258
|
end
|
386
259
|
}
|
@@ -404,7 +277,7 @@ module MU
|
|
404
277
|
end
|
405
278
|
end
|
406
279
|
|
407
|
-
MU::Cloud.resource_types.
|
280
|
+
MU::Cloud.resource_types.each_value { |attrs|
|
408
281
|
type = attrs[:cfg_plural]
|
409
282
|
if @original_config[type]
|
410
283
|
@original_config[type].each { |resource|
|
@@ -481,7 +354,7 @@ module MU
|
|
481
354
|
end
|
482
355
|
|
483
356
|
count = 0
|
484
|
-
MU::Cloud.resource_types.
|
357
|
+
MU::Cloud.resource_types.each_value { |data|
|
485
358
|
next if @original_config[data[:cfg_plural]].nil?
|
486
359
|
next if realtypes.size > 0 and (!negate and !realtypes.include?(data[:cfg_plural]))
|
487
360
|
@original_config[data[:cfg_plural]].each { |resource|
|
@@ -499,13 +372,13 @@ module MU
|
|
499
372
|
raise MuError, "Nil arguments to removeKitten are not allowed"
|
500
373
|
end
|
501
374
|
@kitten_semaphore.synchronize {
|
502
|
-
MU::Cloud.resource_types.
|
375
|
+
MU::Cloud.resource_types.each_value { |attrs|
|
503
376
|
type = attrs[:cfg_plural]
|
504
377
|
next if !@kittens.has_key?(type)
|
505
378
|
tmplitter = @kittens[type].values.dup
|
506
379
|
tmplitter.each { |nodeclass, data|
|
507
380
|
if data.is_a?(Hash)
|
508
|
-
data.
|
381
|
+
data.each_key { |mu_name|
|
509
382
|
if data == object
|
510
383
|
@kittens[type][nodeclass].delete(mu_name)
|
511
384
|
return
|
@@ -534,13 +407,12 @@ module MU
|
|
534
407
|
end
|
535
408
|
|
536
409
|
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
|
537
|
-
has_multiples = attrs[:has_multiples]
|
538
410
|
object.intoDeploy(self)
|
539
411
|
|
540
412
|
@kitten_semaphore.synchronize {
|
541
413
|
@kittens[type] ||= {}
|
542
414
|
@kittens[type][object.habitat] ||= {}
|
543
|
-
if has_multiples
|
415
|
+
if attrs[:has_multiples]
|
544
416
|
@kittens[type][object.habitat][name] ||= {}
|
545
417
|
@kittens[type][object.habitat][name][object.mu_name] = object
|
546
418
|
else
|
@@ -577,7 +449,7 @@ module MU
|
|
577
449
|
loadDeploy(true) # make sure we're not trampling deployment data
|
578
450
|
@secret_semaphore.synchronize {
|
579
451
|
if @secrets[type].nil?
|
580
|
-
raise SecretError, "'#{type}' is not a valid secret type (valid types: #{@secrets.keys.
|
452
|
+
raise SecretError, "'#{type}' is not a valid secret type (valid types: #{@secrets.keys.join(", ")})"
|
581
453
|
end
|
582
454
|
@secrets[type][instance_id] = encryptWithDeployKey(raw_secret)
|
583
455
|
}
|
@@ -593,7 +465,7 @@ module MU
|
|
593
465
|
@secret_semaphore.synchronize {
|
594
466
|
if @secrets[type].nil?
|
595
467
|
return nil if quiet
|
596
|
-
raise SecretError, "'#{type}' is not a valid secret type (valid types: #{@secrets.keys.
|
468
|
+
raise SecretError, "'#{type}' is not a valid secret type (valid types: #{@secrets.keys.join(", ")})"
|
597
469
|
end
|
598
470
|
if @secrets[type][instance_id].nil?
|
599
471
|
return nil if quiet
|
@@ -654,645 +526,88 @@ module MU
|
|
654
526
|
|
655
527
|
@@dummy_cache = {}
|
656
528
|
|
657
|
-
# Locate a resource that's either a member of another deployment, or of no
|
658
|
-
# deployment at all, and return a {MU::Cloud} object for it.
|
659
|
-
# @param cloud [String]: The Cloud provider to use.
|
660
|
-
# @param type [String]: The resource type. Can be the full class name, symbolic name, or Basket of Kittens configuration shorthand for the resource type.
|
661
|
-
# @param deploy_id [String]: The identifier of an outside deploy to search.
|
662
|
-
# @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field, typically used in conjunction with deploy_id.
|
663
|
-
# @param mu_name [String]: The fully-resolved and deployed name of the resource, typically used in conjunction with deploy_id.
|
664
|
-
# @param cloud_id [String]: A cloud provider identifier for this resource.
|
665
|
-
# @param region [String]: The cloud provider region
|
666
|
-
# @param tag_key [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_value.
|
667
|
-
# @param tag_value [String]: A cloud provider tag to help identify the resource, used in conjunction with tag_key.
|
668
|
-
# @param allow_multi [Boolean]: Permit an array of matching resources to be returned (if applicable) instead of just one.
|
669
|
-
# @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.
|
670
|
-
# @param flags [Hash]: Other cloud or resource type specific options to pass to that resource's find() method
|
671
|
-
# @return [Array<MU::Cloud>]
|
672
|
-
def self.findStray(
|
673
|
-
cloud,
|
674
|
-
type,
|
675
|
-
deploy_id: nil,
|
676
|
-
name: nil,
|
677
|
-
mu_name: nil,
|
678
|
-
cloud_id: nil,
|
679
|
-
credentials: nil,
|
680
|
-
region: nil,
|
681
|
-
tag_key: nil,
|
682
|
-
tag_value: nil,
|
683
|
-
allow_multi: false,
|
684
|
-
calling_deploy: MU.mommacat,
|
685
|
-
flags: {},
|
686
|
-
habitats: [],
|
687
|
-
dummy_ok: false,
|
688
|
-
debug: false,
|
689
|
-
no_deploy_search: false
|
690
|
-
)
|
691
|
-
start = Time.now
|
692
|
-
callstr = "findStray(cloud: #{cloud}, type: #{type}, deploy_id: #{deploy_id}, calling_deploy: #{calling_deploy.deploy_id if !calling_deploy.nil?}, name: #{name}, cloud_id: #{cloud_id}, tag_key: #{tag_key}, tag_value: #{tag_value}, credentials: #{credentials}, habitats: #{habitats ? habitats.to_s : "[]"}, dummy_ok: #{dummy_ok.to_s}, flags: #{flags.to_s}) from #{caller[0]}"
|
693
|
-
# callstack = caller.dup
|
694
|
-
|
695
|
-
return nil if cloud == "CloudFormation" and !cloud_id.nil?
|
696
|
-
shortclass, _cfg_name, cfg_plural, classname, _attrs = MU::Cloud.getResourceNames(type)
|
697
|
-
if !MU::Cloud.supportedClouds.include?(cloud) or shortclass.nil?
|
698
|
-
MU.log "findStray was called with bogus cloud argument '#{cloud}'", MU::WARN, details: callstr
|
699
|
-
return nil
|
700
|
-
end
|
701
|
-
|
702
|
-
begin
|
703
|
-
# TODO this is dumb as hell, clean this up.. and while we're at it
|
704
|
-
# .dup everything so we don't mangle referenced values from the caller
|
705
|
-
deploy_id = deploy_id.to_s if deploy_id.class.to_s == "MU::Config::Tail"
|
706
|
-
name = name.to_s if name.class.to_s == "MU::Config::Tail"
|
707
|
-
cloud_id = cloud_id.to_s if !cloud_id.nil?
|
708
|
-
mu_name = mu_name.to_s if mu_name.class.to_s == "MU::Config::Tail"
|
709
|
-
tag_key = tag_key.to_s if tag_key.class.to_s == "MU::Config::Tail"
|
710
|
-
tag_value = tag_value.to_s if tag_value.class.to_s == "MU::Config::Tail"
|
711
|
-
type = cfg_plural
|
712
|
-
resourceclass = MU::Cloud.loadCloudType(cloud, shortclass)
|
713
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
714
|
-
|
715
|
-
credlist = if credentials
|
716
|
-
[credentials]
|
717
|
-
else
|
718
|
-
cloudclass.listCredentials
|
719
|
-
end
|
720
|
-
|
721
|
-
if (tag_key and !tag_value) or (!tag_key and tag_value)
|
722
|
-
raise MuError, "Can't call findStray with only one of tag_key and tag_value set, must be both or neither"
|
723
|
-
end
|
724
|
-
# Help ourselves by making more refined parameters out of mu_name, if
|
725
|
-
# they weren't passed explicitly
|
726
|
-
if mu_name
|
727
|
-
if !tag_key and !tag_value
|
728
|
-
# XXX "Name" is an AWS-ism, perhaps those plugins should do this bit?
|
729
|
-
tag_key="Name"
|
730
|
-
tag_value=mu_name
|
731
|
-
end
|
732
|
-
# We can extract a deploy_id from mu_name if we don't have one already
|
733
|
-
if !deploy_id and mu_name
|
734
|
-
deploy_id = mu_name.sub(/^(\w+-\w+-\d{10}-[A-Z]{2})-/, '\1')
|
735
|
-
end
|
736
|
-
end
|
737
|
-
loglevel = debug ? MU::NOTICE : MU::DEBUG
|
738
|
-
|
739
|
-
MU.log callstr, loglevel, details: caller
|
740
|
-
|
741
|
-
# See if the thing we're looking for is a member of the deploy that's
|
742
|
-
# asking after it.
|
743
|
-
if !deploy_id.nil? and !calling_deploy.nil? and
|
744
|
-
calling_deploy.deploy_id == deploy_id and (!name.nil? or !mu_name.nil?)
|
745
|
-
handle = calling_deploy.findLitterMate(type: type, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
|
746
|
-
return [handle] if !handle.nil?
|
747
|
-
end
|
748
|
-
|
749
|
-
kittens = {}
|
750
|
-
# Search our other deploys for matching resources
|
751
|
-
if !no_deploy_search and (deploy_id or name or mu_name or cloud_id)
|
752
|
-
MU.log "findStray: searching my deployments (#{cfg_plural}, name: #{name}, deploy_id: #{deploy_id}, mu_name: #{mu_name}) - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
753
|
-
|
754
|
-
# Check our in-memory cache of live deploys before resorting to
|
755
|
-
# metadata
|
756
|
-
littercache = nil
|
757
|
-
# Sometimes we're called inside a locked thread, sometimes not. Deal
|
758
|
-
# with locking gracefully.
|
759
|
-
begin
|
760
|
-
@@litter_semaphore.synchronize {
|
761
|
-
littercache = @@litters.dup
|
762
|
-
}
|
763
|
-
rescue ThreadError => e
|
764
|
-
raise e if !e.message.match(/recursive locking/)
|
765
|
-
littercache = @@litters.dup
|
766
|
-
end
|
767
|
-
|
768
|
-
littercache.each_pair { |cur_deploy, momma|
|
769
|
-
next if deploy_id and deploy_id != cur_deploy
|
770
|
-
|
771
|
-
straykitten = momma.findLitterMate(type: type, cloud_id: cloud_id, name: name, mu_name: mu_name, credentials: credentials, created_only: true)
|
772
|
-
if straykitten
|
773
|
-
MU.log "Found matching kitten #{straykitten.mu_name} in-memory - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
774
|
-
# Peace out if we found the exact resource we want
|
775
|
-
if cloud_id and straykitten.cloud_id.to_s == cloud_id.to_s
|
776
|
-
return [straykitten]
|
777
|
-
elsif mu_name and straykitten.mu_name == mu_name
|
778
|
-
return [straykitten]
|
779
|
-
else
|
780
|
-
kittens[straykitten.cloud_id] ||= straykitten
|
781
|
-
end
|
782
|
-
end
|
783
|
-
}
|
784
|
-
|
785
|
-
mu_descs = MU::MommaCat.getResourceMetadata(cfg_plural, name: name, deploy_id: deploy_id, mu_name: mu_name)
|
786
|
-
MU.log "findStray: #{mu_descs.size.to_s} deploys had matches - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
787
|
-
|
788
|
-
mu_descs.each_pair { |cur_deploy_id, matches|
|
789
|
-
MU.log "findStray: #{cur_deploy_id} had #{matches.size.to_s} initial matches - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
790
|
-
next if matches.nil? or matches.size == 0
|
791
|
-
|
792
|
-
momma = MU::MommaCat.getLitter(cur_deploy_id)
|
793
|
-
|
794
|
-
straykitten = nil
|
795
|
-
|
796
|
-
# If we found exactly one match in this deploy, use its metadata to
|
797
|
-
# guess at resource names we weren't told.
|
798
|
-
if matches.size > 1 and cloud_id
|
799
|
-
MU.log "findStray: attempting to narrow down multiple matches with cloud_id #{cloud_id} - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
800
|
-
straykitten = momma.findLitterMate(type: type, cloud_id: cloud_id, credentials: credentials, created_only: true)
|
801
|
-
elsif matches.size == 1 and name.nil? and mu_name.nil?
|
802
|
-
if cloud_id.nil?
|
803
|
-
straykitten = momma.findLitterMate(type: type, name: matches.first["name"], cloud_id: matches.first["cloud_id"], credentials: credentials)
|
804
|
-
else
|
805
|
-
MU.log "findStray: fetching single match with cloud_id #{cloud_id} - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
806
|
-
straykitten = momma.findLitterMate(type: type, name: matches.first["name"], cloud_id: cloud_id, credentials: credentials)
|
807
|
-
end
|
808
|
-
# elsif !flags.nil? and !flags.empty? # XXX eh, maybe later
|
809
|
-
# # see if we can narrow it down further with some flags
|
810
|
-
# filtered = []
|
811
|
-
# matches.each { |m|
|
812
|
-
# f = resourceclass.find(cloud_id: m['mu_name'], flags: flags)
|
813
|
-
# filtered << m if !f.nil? and f.size > 0
|
814
|
-
# MU.log "RESULT FROM find(cloud_id: #{m['mu_name']}, flags: #{flags})", MU::WARN, details: f
|
815
|
-
# }
|
816
|
-
# if filtered.size == 1
|
817
|
-
# straykitten = momma.findLitterMate(type: type, name: matches.first["name"], cloud_id: filtered.first['cloud_id'])
|
818
|
-
# end
|
819
|
-
else
|
820
|
-
# There's more than one of this type of resource in the target
|
821
|
-
# deploy, so see if findLitterMate can narrow it down for us
|
822
|
-
straykitten = momma.findLitterMate(type: type, name: name, mu_name: mu_name, cloud_id: cloud_id, credentials: credentials)
|
823
|
-
end
|
824
|
-
|
825
|
-
next if straykitten.nil?
|
826
|
-
straykitten.intoDeploy(momma)
|
827
|
-
|
828
|
-
if straykitten.cloud_id.nil?
|
829
|
-
MU.log "findStray: kitten #{straykitten.mu_name} came back with nil cloud_id", MU::WARN
|
830
|
-
next
|
831
|
-
end
|
832
|
-
|
833
|
-
kittens[straykitten.cloud_id] ||= straykitten
|
834
|
-
|
835
|
-
# Peace out if we found the exact resource we want
|
836
|
-
if cloud_id and straykitten.cloud_id.to_s == cloud_id.to_s
|
837
|
-
return [straykitten]
|
838
|
-
# ...or if we've validated our one possible match
|
839
|
-
elsif !cloud_id and mu_descs.size == 1 and matches.size == 1
|
840
|
-
return [straykitten]
|
841
|
-
elsif credentials and credlist.size == 1 and straykitten.credentials == credentials
|
842
|
-
return [straykitten]
|
843
|
-
end
|
844
|
-
}
|
845
|
-
|
846
|
-
|
847
|
-
# if !mu_descs.nil? and mu_descs.size > 0 and !deploy_id.nil? and !deploy_id.empty? and !mu_descs.first.empty?
|
848
|
-
# MU.log "I found descriptions that might match #{resourceclass.cfg_plural} name: #{name}, deploy_id: #{deploy_id}, mu_name: #{mu_name}, but couldn't isolate my target kitten", MU::WARN, details: caller
|
849
|
-
# puts File.read(deploy_dir(deploy_id)+"/deployment.json")
|
850
|
-
# end
|
851
|
-
|
852
|
-
# We can't refine any further by asking the cloud provider...
|
853
|
-
if !cloud_id and !tag_key and !tag_value and kittens.size > 1
|
854
|
-
if !allow_multi
|
855
|
-
raise MuError, "Multiple matches in MU::MommaCat.findStray where none allowed from deploy_id: '#{deploy_id}', name: '#{name}', mu_name: '#{mu_name}' (#{caller[0]})"
|
856
|
-
else
|
857
|
-
return kittens.values
|
858
|
-
end
|
859
|
-
end
|
860
|
-
end
|
861
|
-
|
862
|
-
matches = []
|
863
|
-
|
864
|
-
found_the_thing = false
|
865
|
-
credlist.each { |creds|
|
866
|
-
break if found_the_thing
|
867
|
-
if cloud_id or (tag_key and tag_value) or !flags.empty? or allow_multi
|
868
|
-
|
869
|
-
regions = begin
|
870
|
-
region ? [region] : cloudclass.listRegions(credentials: creds)
|
871
|
-
rescue NoMethodError # Not all cloud providers have regions
|
872
|
-
[nil]
|
873
|
-
end
|
874
|
-
|
875
|
-
# ..not all resource types care about regions either
|
876
|
-
if resourceclass.isGlobal?
|
877
|
-
regions = [nil]
|
878
|
-
end
|
879
|
-
|
880
|
-
# Decide what habitats (accounts/projects/subscriptions) we'll
|
881
|
-
# search, if applicable for this resource type.
|
882
|
-
habitats ||= []
|
883
|
-
begin
|
884
|
-
if flags["project"] # backwards-compat
|
885
|
-
habitats << flags["project"]
|
886
|
-
end
|
887
|
-
if habitats.empty?
|
888
|
-
if resourceclass.canLiveIn.include?(nil)
|
889
|
-
habitats << nil
|
890
|
-
end
|
891
|
-
if resourceclass.canLiveIn.include?(:Habitat)
|
892
|
-
habitats.concat(cloudclass.listProjects(creds))
|
893
|
-
end
|
894
|
-
end
|
895
|
-
rescue NoMethodError # we only expect this to work on Google atm
|
896
|
-
end
|
897
|
-
|
898
|
-
if habitats.empty?
|
899
|
-
habitats << nil
|
900
|
-
end
|
901
|
-
habitats.uniq!
|
902
|
-
|
903
|
-
habitat_threads = []
|
904
|
-
desc_semaphore = Mutex.new
|
905
|
-
|
906
|
-
cloud_descs = {}
|
907
|
-
habitats.each { |hab|
|
908
|
-
begin
|
909
|
-
habitat_threads.each { |t| t.join(0.1) }
|
910
|
-
habitat_threads.reject! { |t| t.nil? or !t.status }
|
911
|
-
sleep 1 if habitat_threads.size > 5
|
912
|
-
end while habitat_threads.size > 5
|
913
|
-
habitat_threads << Thread.new(hab) { |p|
|
914
|
-
MU.log "findStray: Searching #{p} (#{habitat_threads.size.to_s} habitat threads running) - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
915
|
-
cloud_descs[p] = {}
|
916
|
-
region_threads = []
|
917
|
-
regions.each { |reg| region_threads << Thread.new(reg) { |r|
|
918
|
-
MU.log "findStray: Searching #{r} in #{p} (#{region_threads.size.to_s} region threads running) - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
919
|
-
MU.log "findStray: calling #{classname}.find(cloud_id: #{cloud_id}, region: #{r}, tag_key: #{tag_key}, tag_value: #{tag_value}, flags: #{flags}, credentials: #{creds}, project: #{p}) - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
920
|
-
found = resourceclass.find(cloud_id: cloud_id, region: r, tag_key: tag_key, tag_value: tag_value, flags: flags, credentials: creds, habitat: p)
|
921
|
-
MU.log "findStray: #{found ? found.size.to_s : "nil"} results - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
922
|
-
|
923
|
-
if found
|
924
|
-
desc_semaphore.synchronize {
|
925
|
-
cloud_descs[p][r] = found
|
926
|
-
}
|
927
|
-
end
|
928
|
-
# Stop if you found the thing by a specific cloud_id
|
929
|
-
if cloud_id and found and !found.empty?
|
930
|
-
found_the_thing = true
|
931
|
-
Thread.exit
|
932
|
-
end
|
933
|
-
} }
|
934
|
-
begin
|
935
|
-
region_threads.each { |t| t.join(0.1) }
|
936
|
-
region_threads.reject! { |t| t.nil? or !t.status }
|
937
|
-
if region_threads.size > 0
|
938
|
-
MU.log "#{region_threads.size.to_s} regions still running in #{p}", loglevel
|
939
|
-
sleep 3
|
940
|
-
end
|
941
|
-
end while region_threads.size > 0
|
942
|
-
}
|
943
|
-
}
|
944
|
-
begin
|
945
|
-
habitat_threads.each { |t| t.join(0.1) }
|
946
|
-
habitat_threads.reject! { |t| t.nil? or !t.status }
|
947
|
-
if habitat_threads.size > 0
|
948
|
-
MU.log "#{habitat_threads.size.to_s} habitats still running", loglevel
|
949
|
-
sleep 3
|
950
|
-
end
|
951
|
-
end while habitat_threads.size > 0
|
952
|
-
|
953
|
-
habitat_threads = []
|
954
|
-
habitats.each { |hab| habitat_threads << Thread.new(hab) { |p|
|
955
|
-
region_threads = []
|
956
|
-
regions.each { |reg| region_threads << Thread.new(reg) { |r|
|
957
|
-
next if cloud_descs[p][r].nil?
|
958
|
-
cloud_descs[p][r].each_pair { |kitten_cloud_id, descriptor|
|
959
|
-
|
960
|
-
# We already have a MU::Cloud object for this guy, use it
|
961
|
-
if kittens.has_key?(kitten_cloud_id)
|
962
|
-
desc_semaphore.synchronize {
|
963
|
-
matches << kittens[kitten_cloud_id]
|
964
|
-
}
|
965
|
-
elsif kittens.size == 0
|
966
|
-
if !dummy_ok
|
967
|
-
next
|
968
|
-
end
|
969
|
-
|
970
|
-
# If we don't have a MU::Cloud object, manufacture a dummy
|
971
|
-
# one. Give it a fake name if we have to and have decided
|
972
|
-
# that's ok. Wild inferences from the cloud descriptor are
|
973
|
-
# ok to try here.
|
974
|
-
use_name = if (name.nil? or name.empty?)
|
975
|
-
if !dummy_ok
|
976
|
-
nil
|
977
|
-
elsif !mu_name.nil?
|
978
|
-
mu_name
|
979
|
-
# AWS-style tags
|
980
|
-
elsif descriptor.respond_to?(:tags) and
|
981
|
-
descriptor.tags.is_a?(Array) and
|
982
|
-
descriptor.tags.first.respond_to?(:key) and
|
983
|
-
descriptor.tags.map { |t| t.key }.include?("Name")
|
984
|
-
descriptor.tags.select { |t| t.key == "Name" }.first.value
|
985
|
-
else
|
986
|
-
try = nil
|
987
|
-
# Various GCP fields
|
988
|
-
[:display_name, :name, (resourceclass.cfg_name+"_name").to_sym].each { |field|
|
989
|
-
if descriptor.respond_to?(field) and descriptor.send(field).is_a?(String)
|
990
|
-
try = descriptor.send(field)
|
991
|
-
break
|
992
|
-
end
|
993
|
-
|
994
|
-
}
|
995
|
-
try ||= if !tag_value.nil?
|
996
|
-
tag_value
|
997
|
-
else
|
998
|
-
kitten_cloud_id
|
999
|
-
end
|
1000
|
-
try
|
1001
|
-
end
|
1002
|
-
else
|
1003
|
-
name
|
1004
|
-
end
|
1005
|
-
if use_name.nil?
|
1006
|
-
MU.log "Found cloud provider data for #{cloud} #{type} #{kitten_cloud_id}, but without a name I can't manufacture a proper #{type} object to return - #{sprintf("%.2fs", (Time.now-start))}", loglevel, details: caller
|
1007
|
-
next
|
1008
|
-
end
|
1009
|
-
cfg = {
|
1010
|
-
"name" => use_name,
|
1011
|
-
"cloud" => cloud,
|
1012
|
-
"credentials" => creds
|
1013
|
-
}
|
1014
|
-
if !r.nil? and !resourceclass.isGlobal?
|
1015
|
-
cfg["region"] = r
|
1016
|
-
end
|
1017
|
-
|
1018
|
-
if !p.nil? and resourceclass.canLiveIn.include?(:Habitat)
|
1019
|
-
cfg["project"] = p
|
1020
|
-
end
|
1021
|
-
# If we can at least find the config from the deploy this will
|
1022
|
-
# belong with, use that, even if it's an ungroomed resource.
|
1023
|
-
if !calling_deploy.nil? and
|
1024
|
-
!calling_deploy.original_config.nil? and
|
1025
|
-
!calling_deploy.original_config[type+"s"].nil?
|
1026
|
-
calling_deploy.original_config[type+"s"].each { |s|
|
1027
|
-
if s["name"] == use_name
|
1028
|
-
cfg = s.dup
|
1029
|
-
break
|
1030
|
-
end
|
1031
|
-
}
|
1032
|
-
|
1033
|
-
newkitten = resourceclass.new(mommacat: calling_deploy, kitten_cfg: cfg, cloud_id: kitten_cloud_id)
|
1034
|
-
desc_semaphore.synchronize {
|
1035
|
-
matches << newkitten
|
1036
|
-
}
|
1037
|
-
else
|
1038
|
-
if !@@dummy_cache[cfg_plural] or !@@dummy_cache[cfg_plural][cfg.to_s]
|
1039
|
-
MU.log "findStray: Generating dummy '#{resourceclass.to_s}' cloudobj with name: #{use_name}, cloud_id: #{kitten_cloud_id.to_s} - #{sprintf("%.2fs", (Time.now-start))}", loglevel, details: cfg
|
1040
|
-
resourceclass.new(mu_name: use_name, kitten_cfg: cfg, cloud_id: kitten_cloud_id.to_s, from_cloud_desc: descriptor)
|
1041
|
-
desc_semaphore.synchronize {
|
1042
|
-
@@dummy_cache[cfg_plural] ||= {}
|
1043
|
-
@@dummy_cache[cfg_plural][cfg.to_s] = resourceclass.new(mu_name: use_name, kitten_cfg: cfg, cloud_id: kitten_cloud_id.to_s, from_cloud_desc: descriptor)
|
1044
|
-
MU.log "findStray: Finished generating dummy '#{resourceclass.to_s}' cloudobj - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
1045
|
-
}
|
1046
|
-
end
|
1047
|
-
desc_semaphore.synchronize {
|
1048
|
-
matches << @@dummy_cache[cfg_plural][cfg.to_s]
|
1049
|
-
}
|
1050
|
-
end
|
1051
|
-
end
|
1052
|
-
}
|
1053
|
-
} }
|
1054
|
-
MU.log "findStray: tying up #{region_threads.size.to_s} region threads - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
1055
|
-
region_threads.each { |t|
|
1056
|
-
t.join
|
1057
|
-
}
|
1058
|
-
} }
|
1059
|
-
MU.log "findStray: tying up #{habitat_threads.size.to_s} habitat threads - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
1060
|
-
habitat_threads.each { |t|
|
1061
|
-
t.join
|
1062
|
-
}
|
1063
|
-
end
|
1064
|
-
}
|
1065
|
-
rescue StandardError => e
|
1066
|
-
MU.log e.inspect, MU::ERR, details: e.backtrace
|
1067
|
-
end
|
1068
|
-
MU.log "findStray: returning #{matches ? matches.size.to_s : "0"} matches - #{sprintf("%.2fs", (Time.now-start))}", loglevel
|
1069
|
-
|
1070
|
-
matches
|
1071
|
-
end
|
1072
|
-
|
1073
|
-
# Return the resource object of another member of this deployment
|
1074
|
-
# @param type [String,Symbol]: The type of resource
|
1075
|
-
# @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field
|
1076
|
-
# @param mu_name [String]: The fully-resolved and deployed name of the resource
|
1077
|
-
# @param cloud_id [String]: The cloud provider's unique identifier for this resource
|
1078
|
-
# @param created_only [Boolean]: Only return the littermate if its cloud_id method returns a value
|
1079
|
-
# @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.
|
1080
|
-
# @return [MU::Cloud]
|
1081
|
-
def findLitterMate(type: nil, name: nil, mu_name: nil, cloud_id: nil, created_only: false, return_all: false, credentials: nil, habitat: nil, debug: false, indent: "")
|
1082
|
-
shortclass, cfg_name, cfg_plural, classname, attrs = MU::Cloud.getResourceNames(type)
|
1083
|
-
type = cfg_plural
|
1084
|
-
has_multiples = attrs[:has_multiples]
|
1085
|
-
|
1086
|
-
loglevel = debug ? MU::NOTICE : MU::DEBUG
|
1087
|
-
|
1088
|
-
argstring = [:type, :name, :mu_name, :cloud_id, :created_only, :credentials, :habitat, :has_multiples].reject { |a|
|
1089
|
-
binding.local_variable_get(a).nil?
|
1090
|
-
}.map { |v|
|
1091
|
-
v.to_s+": "+binding.local_variable_get(v).to_s
|
1092
|
-
}.join(", ")
|
1093
|
-
|
1094
|
-
# Fun times: if we specified a habitat, which we may also have done by
|
1095
|
-
# its shorthand sibling name, let's... call ourselves first to make sure
|
1096
|
-
# we're fishing for the right thing.
|
1097
|
-
if habitat
|
1098
|
-
if habitat.is_a?(MU::Config::Ref) and habitat.id
|
1099
|
-
habitat = habitat.id
|
1100
|
-
else
|
1101
|
-
MU.log indent+"findLitterMate(#{argstring}): Attempting to resolve habitat name #{habitat}", loglevel
|
1102
|
-
realhabitat = findLitterMate(type: "habitat", name: habitat, debug: debug, credentials: credentials, indent: indent+" ")
|
1103
|
-
if realhabitat and realhabitat.mu_name
|
1104
|
-
MU.log indent+"findLitterMate: Resolved habitat name #{habitat} to #{realhabitat.mu_name}", loglevel, details: [realhabitat.mu_name, realhabitat.cloud_id, realhabitat.config.keys]
|
1105
|
-
habitat = realhabitat.cloud_id
|
1106
|
-
elsif debug
|
1107
|
-
MU.log indent+"findLitterMate(#{argstring}): Failed to resolve habitat name #{habitat}", MU::WARN
|
1108
|
-
end
|
1109
|
-
end
|
1110
|
-
end
|
1111
|
-
|
1112
|
-
|
1113
|
-
@kitten_semaphore.synchronize {
|
1114
|
-
if !@kittens.has_key?(type)
|
1115
|
-
if debug
|
1116
|
-
MU.log indent+"NO SUCH KEY #{type} findLitterMate(#{argstring})", MU::WARN, details: @kittens.keys
|
1117
|
-
end
|
1118
|
-
return nil
|
1119
|
-
end
|
1120
|
-
MU.log indent+"START findLitterMate(#{argstring}), caller: #{caller[2]}", loglevel, details: @kittens[type].keys.map { |hab| hab.to_s+": "+@kittens[type][hab].keys.join(", ") }
|
1121
|
-
matches = []
|
1122
|
-
|
1123
|
-
@kittens[type].each { |habitat_group, sib_classes|
|
1124
|
-
next if habitat and habitat_group != habitat and !habitat_group.nil?
|
1125
|
-
sib_classes.each_pair { |sib_class, data|
|
1126
|
-
virtual_name = nil
|
1127
|
-
|
1128
|
-
if !has_multiples and data and !data.is_a?(Hash) and data.config and data.config.is_a?(Hash) and data.config['virtual_name'] and name == data.config['virtual_name']
|
1129
|
-
virtual_name = data.config['virtual_name']
|
1130
|
-
elsif !name.nil? and name != sib_class
|
1131
|
-
next
|
1132
|
-
end
|
1133
|
-
if has_multiples
|
1134
|
-
if !name.nil?
|
1135
|
-
if return_all
|
1136
|
-
MU.log indent+"MULTI-MATCH RETURN_ALL findLitterMate(#{argstring})", loglevel, details: data.keys
|
1137
|
-
return data.dup
|
1138
|
-
end
|
1139
|
-
if data.size == 1 and (cloud_id.nil? or data.values.first.cloud_id == cloud_id)
|
1140
|
-
return data.values.first
|
1141
|
-
elsif mu_name.nil? and cloud_id.nil?
|
1142
|
-
MU.log indent+"#{@deploy_id}: Found multiple matches in findLitterMate based on #{type}: #{name}, and not enough info to narrow down further. Returning an arbitrary result. Caller: #{caller[2]}", MU::WARN, details: data.keys
|
1143
|
-
return data.values.first
|
1144
|
-
end
|
1145
|
-
end
|
1146
|
-
data.each_pair { |sib_mu_name, obj|
|
1147
|
-
if (!mu_name.nil? and mu_name == sib_mu_name) or
|
1148
|
-
(!cloud_id.nil? and cloud_id == obj.cloud_id) or
|
1149
|
-
(!credentials.nil? and credentials == obj.credentials)
|
1150
|
-
if !created_only or !obj.cloud_id.nil?
|
1151
|
-
if return_all
|
1152
|
-
MU.log indent+"MULTI-MATCH RETURN_ALL findLitterMate(#{argstring})", loglevel, details: data.keys
|
1153
|
-
return data.dup
|
1154
|
-
else
|
1155
|
-
MU.log indent+"MULTI-MATCH findLitterMate(#{argstring})", loglevel, details: data.keys
|
1156
|
-
return obj
|
1157
|
-
end
|
1158
|
-
end
|
1159
|
-
end
|
1160
|
-
}
|
1161
|
-
else
|
1162
|
-
|
1163
|
-
MU.log indent+"CHECKING AGAINST findLitterMate #{habitat_group}/#{type}/#{sib_class} data.cloud_id: #{data.cloud_id}, data.credentials: #{data.credentials}, sib_class: #{sib_class}, virtual_name: #{virtual_name}", loglevel, details: argstring
|
1164
|
-
|
1165
|
-
data_cloud_id = data.cloud_id.nil? ? nil : data.cloud_id.to_s
|
1166
|
-
|
1167
|
-
MU.log indent+"(name.nil? or sib_class == name or virtual_name == name)", loglevel, details: (name.nil? or sib_class == name or virtual_name == name).to_s
|
1168
|
-
MU.log indent+"(cloud_id.nil? or cloud_id[#{cloud_id.class.name}:#{cloud_id.to_s}] == data_cloud_id[#{data_cloud_id.class.name}:#{data_cloud_id}])", loglevel, details: (cloud_id.nil? or cloud_id == data_cloud_id).to_s
|
1169
|
-
MU.log indent+"(credentials.nil? or data.credentials.nil? or credentials[#{credentials.class.name}:#{credentials}] == data.credentials[#{data.credentials.class.name}:#{data.credentials}])", loglevel, details: (credentials.nil? or data.credentials.nil? or credentials == data.credentials).to_s
|
1170
|
-
|
1171
|
-
if (name.nil? or sib_class == name.to_s or virtual_name == name.to_s) and
|
1172
|
-
(cloud_id.nil? or cloud_id.to_s == data_cloud_id) and
|
1173
|
-
(credentials.nil? or data.credentials.nil? or credentials.to_s == data.credentials.to_s)
|
1174
|
-
MU.log indent+"OUTER MATCH PASSED, NEED !created_only (#{created_only.to_s}) or !data_cloud_id.nil? (#{data_cloud_id})", loglevel, details: (cloud_id.nil? or cloud_id == data_cloud_id).to_s
|
1175
|
-
if !created_only or !data_cloud_id.nil?
|
1176
|
-
MU.log indent+"SINGLE MATCH findLitterMate(#{argstring})", loglevel, details: [data.mu_name, data_cloud_id, data.config.keys]
|
1177
|
-
matches << data
|
1178
|
-
end
|
1179
|
-
end
|
1180
|
-
end
|
1181
|
-
}
|
1182
|
-
}
|
1183
|
-
|
1184
|
-
return matches.first if matches.size == 1
|
1185
|
-
if return_all and matches.size > 1
|
1186
|
-
return matches
|
1187
|
-
end
|
1188
|
-
}
|
1189
|
-
|
1190
|
-
MU.log indent+"NO MATCH findLitterMate(#{argstring})", loglevel
|
1191
|
-
|
1192
|
-
return nil
|
1193
|
-
end
|
1194
|
-
|
1195
529
|
# Add or remove a resource's metadata to this deployment's structure and
|
1196
530
|
# flush it to disk.
|
1197
531
|
# @param type [String]: The type of resource (e.g. *server*, *database*).
|
1198
532
|
# @param key [String]: The name field of this resource.
|
533
|
+
# @param mu_name [String]: The mu_name of this resource.
|
1199
534
|
# @param data [Hash]: The resource's metadata.
|
535
|
+
# @param triggering_node [MU::Cloud]: A cloud object calling this notify, usually on behalf of itself
|
1200
536
|
# @param remove [Boolean]: Remove this resource from the deploy structure, instead of adding it.
|
1201
537
|
# @return [void]
|
1202
538
|
def notify(type, key, data, mu_name: nil, remove: false, triggering_node: nil, delayed_save: false)
|
1203
539
|
return if @no_artifacts
|
1204
|
-
MU::MommaCat.lock("deployment-notification")
|
1205
540
|
|
1206
|
-
|
1207
|
-
|
1208
|
-
end
|
541
|
+
begin
|
542
|
+
MU::MommaCat.lock("deployment-notification")
|
1209
543
|
|
1210
|
-
|
1211
|
-
|
544
|
+
if !@need_deploy_flush or @deployment.nil? or @deployment.empty?
|
545
|
+
loadDeploy(true) # make sure we're saving the latest and greatest
|
546
|
+
end
|
1212
547
|
|
1213
|
-
|
1214
|
-
|
1215
|
-
if cfg_plural
|
1216
|
-
type = cfg_plural
|
1217
|
-
has_multiples = attrs[:has_multiples]
|
1218
|
-
end
|
548
|
+
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type, false)
|
549
|
+
has_multiples = attrs[:has_multiples] ? true : false
|
1219
550
|
|
1220
|
-
|
1221
|
-
|
1222
|
-
mu_name = data["mu_name"]
|
551
|
+
mu_name ||= if !data.nil? and !data["mu_name"].nil?
|
552
|
+
data["mu_name"]
|
1223
553
|
elsif !triggering_node.nil? and !triggering_node.mu_name.nil?
|
1224
|
-
|
554
|
+
triggering_node.mu_name
|
1225
555
|
end
|
1226
556
|
if mu_name.nil? and has_multiples
|
1227
|
-
MU.log "MU::MommaCat.notify called to modify deployment struct for a type (#{type}) with :has_multiples, but no mu_name available to look under #{key}. Call was #{caller
|
1228
|
-
MU::MommaCat.unlock("deployment-notification")
|
557
|
+
MU.log "MU::MommaCat.notify called to modify deployment struct for a type (#{type}) with :has_multiples, but no mu_name available to look under #{key}. Call was #{caller(1..1)}", MU::WARN, details: data
|
1229
558
|
return
|
1230
559
|
end
|
1231
|
-
end
|
1232
560
|
|
1233
|
-
|
561
|
+
@need_deploy_flush = true
|
1234
562
|
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
end
|
1241
|
-
@notify_semaphore.synchronize {
|
1242
|
-
@deployment[type] ||= {}
|
1243
|
-
}
|
1244
|
-
if has_multiples
|
563
|
+
if !remove
|
564
|
+
if data.nil?
|
565
|
+
MU.log "MU::MommaCat.notify called to modify deployment struct, but no data provided", MU::WARN
|
566
|
+
return
|
567
|
+
end
|
1245
568
|
@notify_semaphore.synchronize {
|
1246
|
-
@deployment[type]
|
569
|
+
@deployment[type] ||= {}
|
1247
570
|
}
|
1248
|
-
# fix has_multiples classes that weren't tiered correctly
|
1249
|
-
if @deployment[type][key].is_a?(Hash) and @deployment[type][key].has_key?("mu_name")
|
1250
|
-
olddata = @deployment[type][key].dup
|
1251
|
-
@deployment[type][key][olddata["mu_name"]] = olddata
|
1252
|
-
end
|
1253
|
-
@deployment[type][key][mu_name] = data
|
1254
|
-
MU.log "Adding to @deployment[#{type}][#{key}][#{mu_name}]", MU::DEBUG, details: data
|
1255
|
-
else
|
1256
|
-
@deployment[type][key] = data
|
1257
|
-
MU.log "Adding to @deployment[#{type}][#{key}]", MU::DEBUG, details: data
|
1258
|
-
end
|
1259
|
-
save!(key) if !delayed_save
|
1260
|
-
else
|
1261
|
-
have_deploy = true
|
1262
|
-
if @deployment[type].nil? or @deployment[type][key].nil?
|
1263
|
-
|
1264
571
|
if has_multiples
|
1265
|
-
|
572
|
+
@notify_semaphore.synchronize {
|
573
|
+
@deployment[type][key] ||= {}
|
574
|
+
}
|
575
|
+
@deployment[type][key][mu_name] = data
|
576
|
+
MU.log "Adding to @deployment[#{type}][#{key}][#{mu_name}]", MU::DEBUG, details: data
|
1266
577
|
else
|
1267
|
-
|
578
|
+
@deployment[type][key] = data
|
579
|
+
MU.log "Adding to @deployment[#{type}][#{key}]", MU::DEBUG, details: data
|
580
|
+
end
|
581
|
+
save!(key) if !delayed_save
|
582
|
+
else
|
583
|
+
have_deploy = true
|
584
|
+
if @deployment[type].nil? or @deployment[type][key].nil?
|
585
|
+
MU.log "MU::MommaCat.notify called to remove #{type} #{key}#{has_multiples ? " "+mu_name : ""} deployment struct, but no such data exist", MU::DEBUG
|
586
|
+
return
|
1268
587
|
end
|
1269
|
-
MU::MommaCat.unlock("deployment-notification")
|
1270
588
|
|
1271
|
-
|
1272
|
-
|
589
|
+
if have_deploy
|
590
|
+
@notify_semaphore.synchronize {
|
591
|
+
if has_multiples
|
592
|
+
MU.log "Removing @deployment[#{type}][#{key}][#{mu_name}]", MU::DEBUG, details: @deployment[type][key][mu_name]
|
593
|
+
@deployment[type][key].delete(mu_name)
|
594
|
+
end
|
1273
595
|
|
1274
|
-
|
1275
|
-
|
1276
|
-
if has_multiples
|
1277
|
-
MU.log "Removing @deployment[#{type}][#{key}][#{mu_name}]", MU::DEBUG, details: @deployment[type][key][mu_name]
|
1278
|
-
@deployment[type][key].delete(mu_name)
|
1279
|
-
if @deployment[type][key].size == 0
|
596
|
+
if @deployment[type][key].empty? or !has_multiples
|
597
|
+
MU.log "Removing @deployment[#{type}][#{key}]", MU::DEBUG, details: @deployment[type][key]
|
1280
598
|
@deployment[type].delete(key)
|
1281
599
|
end
|
1282
|
-
else
|
1283
|
-
MU.log "Removing @deployment[#{type}][#{key}]", MU::DEBUG, details: @deployment[type][key]
|
1284
|
-
@deployment[type].delete(key)
|
1285
|
-
end
|
1286
|
-
if @deployment[type].size == 0
|
1287
|
-
@deployment.delete(type)
|
1288
|
-
end
|
1289
|
-
}
|
1290
|
-
end
|
1291
|
-
save! if !delayed_save
|
1292
600
|
|
601
|
+
if @deployment[type].empty?
|
602
|
+
@deployment.delete(type)
|
603
|
+
end
|
604
|
+
}
|
605
|
+
end
|
606
|
+
save! if !delayed_save
|
607
|
+
end
|
608
|
+
ensure
|
609
|
+
MU::MommaCat.unlock("deployment-notification")
|
1293
610
|
end
|
1294
|
-
|
1295
|
-
MU::MommaCat.unlock("deployment-notification")
|
1296
611
|
end
|
1297
612
|
|
1298
613
|
# Send a Slack notification to a deployment's administrators.
|
@@ -1331,13 +646,13 @@ module MU
|
|
1331
646
|
to << "#{admin['name']} <#{admin['email']}>"
|
1332
647
|
}
|
1333
648
|
end
|
1334
|
-
message = <<
|
649
|
+
message = <<MAIL_HEAD_END
|
1335
650
|
From: #{MU.handle} <root@localhost>
|
1336
651
|
To: #{to.join(",")}
|
1337
652
|
Subject: #{subject}
|
1338
653
|
|
1339
654
|
#{msg}
|
1340
|
-
|
655
|
+
MAIL_HEAD_END
|
1341
656
|
if !kitten.nil? and kitten.kind_of?(MU::Cloud)
|
1342
657
|
message = message + "\n\n**** #{kitten}:\n"
|
1343
658
|
if !kitten.report.nil?
|
@@ -1425,124 +740,58 @@ MESSAGE_END
|
|
1425
740
|
MU::Master::SSL.sign(csr_path, sans, for_user: MU.mu_user)
|
1426
741
|
end
|
1427
742
|
|
1428
|
-
# Make sure deployment data is synchronized to/from each
|
743
|
+
# Make sure deployment data is synchronized to/from each +Server+ in the
|
1429
744
|
# currently-loaded deployment.
|
745
|
+
# @param nodeclasses [Array<String>]
|
746
|
+
# @param triggering_node [String,MU::Cloud::Server]
|
747
|
+
# @param save_only [Boolean]
|
1430
748
|
def syncLitter(nodeclasses = [], triggering_node: nil, save_only: false)
|
1431
|
-
|
1432
|
-
# inferences from dependencies or something?
|
1433
|
-
|
1434
|
-
return if MU.syncLitterThread
|
749
|
+
return if MU.syncLitterThread # don't run recursively by accident
|
1435
750
|
return if !Dir.exist?(deploy_dir)
|
1436
|
-
svrs = MU::Cloud.resource_types[:Server][:cfg_plural] # legibility shorthand
|
1437
|
-
if !triggering_node.nil? and nodeclasses.size > 0
|
1438
|
-
nodeclasses.reject! { |n| n == triggering_node.to_s }
|
1439
|
-
return if nodeclasses.size == 0
|
1440
|
-
end
|
1441
|
-
|
1442
|
-
@kitten_semaphore.synchronize {
|
1443
|
-
if @kittens.nil? or
|
1444
|
-
@kittens[svrs].nil?
|
1445
|
-
MU.log "No #{svrs} as yet available in #{@deploy_id}", MU::DEBUG, details: @kittens
|
1446
|
-
return
|
1447
|
-
end
|
1448
751
|
|
752
|
+
if !triggering_node.nil? and triggering_node.is_a?(MU::Cloud::Server)
|
753
|
+
triggering_node = triggering_node.mu_name
|
754
|
+
end
|
1449
755
|
|
1450
|
-
|
1451
|
-
|
756
|
+
siblings = findLitterMate(type: "server", return_all: true)
|
757
|
+
return if siblings.nil? or siblings.empty?
|
1452
758
|
|
1453
759
|
update_servers = []
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
nodeclasses.each { |nodeclass|
|
1472
|
-
mates = findLitterMate(type: "server", name: nodeclass, return_all: true)
|
1473
|
-
litter.merge!(mates) if mates
|
1474
|
-
}
|
1475
|
-
litter.each_pair { |mu_name, node|
|
1476
|
-
if !triggering_node.nil? and (
|
1477
|
-
(triggering_node.is_a?(MU::Cloud::Server) and mu_name == triggering_node.mu_name) or
|
1478
|
-
(triggering_node.is_a?(String) and mu_name == triggering_node)
|
1479
|
-
)
|
1480
|
-
next
|
1481
|
-
end
|
1482
|
-
|
1483
|
-
if !node.deploydata or !node.deploydata.keys.include?('nodename')
|
1484
|
-
details = node.deploydata ? node.deploydata.keys : nil
|
1485
|
-
MU.log "#{mu_name} deploy data is missing (possibly retired or mid-bootstrap), so not syncing it", MU::WARN, details: details
|
1486
|
-
else
|
1487
|
-
update_servers << node
|
1488
|
-
end
|
1489
|
-
}
|
1490
|
-
end
|
1491
|
-
return if update_servers.size == 0
|
1492
|
-
|
1493
|
-
MU.log "Updating these nodes in #{@deploy_id}", MU::DEBUG, details: update_servers.map { |n| n.mu_name }
|
1494
|
-
|
1495
|
-
update_servers.each { |node|
|
1496
|
-
# Not clear where this pollution comes from, but let's stick a temp
|
1497
|
-
# fix in here.
|
1498
|
-
if node.deploydata['nodename'] != node.mu_name and
|
1499
|
-
!node.deploydata['nodename'].nil? and !node.deploydata['nodename'].emty?
|
1500
|
-
MU.log "Node #{node.mu_name} had wrong or missing nodename (#{node.deploydata['nodename']}), correcting", MU::WARN
|
1501
|
-
node.deploydata['nodename'] = node.mu_name
|
1502
|
-
if @deployment[svrs] and @deployment[svrs][node.config['name']] and
|
1503
|
-
@deployment[svrs][node.config['name']][node.mu_name]
|
1504
|
-
@deployment[svrs][node.config['name']][node.mu_name]['nodename'] = node.mu_name
|
1505
|
-
end
|
1506
|
-
save!
|
1507
|
-
end
|
760
|
+
siblings.each_pair { |mu_name, node|
|
761
|
+
next if mu_name == triggering_node or node.groomer.nil?
|
762
|
+
next if nodeclasses.size > 0 and !nodeclasses.include?(node.config['name'])
|
763
|
+
if !node.deploydata or !node.deploydata['nodename']
|
764
|
+
MU.log "#{mu_name} deploy data is missing (possibly retired or mid-bootstrap), so not syncing it", MU::NOTICE
|
765
|
+
next
|
766
|
+
end
|
767
|
+
|
768
|
+
if @deployment["servers"][node.config['name']][node.mu_name].nil? or
|
769
|
+
@deployment["servers"][node.config['name']][node.mu_name] != node.deploydata
|
770
|
+
@deployment["servers"][node.config['name']][node.mu_name] = node.deploydata
|
771
|
+
elsif !save_only
|
772
|
+
# Don't bother running grooms on nodes that don't need to be updated,
|
773
|
+
# unless we're just going to do a save.
|
774
|
+
next
|
775
|
+
end
|
776
|
+
update_servers << node
|
1508
777
|
}
|
1509
778
|
|
1510
|
-
|
1511
|
-
if !save_only
|
1512
|
-
skip = []
|
1513
|
-
update_servers.each { |node|
|
1514
|
-
if node.mu_name.nil? or node.deploydata.nil? or node.config.nil?
|
1515
|
-
MU.log "Missing mu_name #{node.mu_name}, deploydata, or config from #{node} in syncLitter", MU::ERR, details: node.deploydata
|
1516
|
-
next
|
1517
|
-
end
|
779
|
+
return if update_servers.empty?
|
1518
780
|
|
1519
|
-
|
1520
|
-
@deployment[svrs][node.config['name']][node.mu_name] = node.deploydata
|
1521
|
-
else
|
1522
|
-
skip << node
|
1523
|
-
end
|
1524
|
-
}
|
1525
|
-
update_servers = update_servers - skip
|
1526
|
-
end
|
781
|
+
MU.log "Updating nodes in #{@deploy_id}", MU::DEBUG, details: update_servers.map { |n| n.mu_name }
|
1527
782
|
|
1528
|
-
return if MU.inGem? || update_servers.size < 1
|
1529
783
|
threads = []
|
1530
|
-
parent_thread_id = Thread.current.object_id
|
1531
784
|
update_servers.each { |sibling|
|
1532
785
|
threads << Thread.new {
|
1533
786
|
Thread.abort_on_exception = true
|
1534
|
-
MU.dupGlobals(parent_thread_id)
|
1535
787
|
Thread.current.thread_variable_set("name", "sync-"+sibling.mu_name.downcase)
|
1536
788
|
MU.setVar("syncLitterThread", true)
|
1537
789
|
begin
|
1538
|
-
|
1539
|
-
|
1540
|
-
sibling.groomer.run(purpose: "Synchronizing sibling kittens") if !save_only
|
1541
|
-
end
|
790
|
+
sibling.groomer.saveDeployData
|
791
|
+
sibling.groomer.run(purpose: "Synchronizing sibling kittens") if !save_only
|
1542
792
|
rescue MU::Groomer::RunError => e
|
1543
|
-
MU.log "Sync of #{sibling.mu_name} failed
|
793
|
+
MU.log "Sync of #{sibling.mu_name} failed", MU::WARN, details: e.inspect
|
1544
794
|
end
|
1545
|
-
MU.purgeGlobals
|
1546
795
|
}
|
1547
796
|
}
|
1548
797
|
|