cloud-mu 3.1.6 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/bin/mu-adopt +15 -12
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +37 -1
- 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-run-tests +37 -12
- data/cloud-mu.gemspec +4 -4
- data/cookbooks/mu-tools/attributes/default.rb +7 -0
- data/cookbooks/mu-tools/libraries/helper.rb +87 -3
- data/cookbooks/mu-tools/recipes/apply_security.rb +39 -23
- data/cookbooks/mu-tools/recipes/aws_api.rb +13 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +4 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
- data/cookbooks/mu-tools/resources/disk.rb +33 -12
- data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
- data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
- data/extras/clean-stock-amis +10 -2
- data/extras/generate-stock-images +7 -3
- data/extras/image-generators/AWS/centos7.yaml +19 -16
- data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
- data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
- data/modules/mommacat.ru +2 -2
- data/modules/mu.rb +84 -97
- data/modules/mu/adoption.rb +359 -59
- data/modules/mu/cleanup.rb +67 -44
- data/modules/mu/cloud.rb +108 -1754
- 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 +929 -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 +178 -0
- data/modules/mu/config.rb +122 -80
- 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 +2 -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 +4 -5
- 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 +81 -9
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/schema_helpers.rb +30 -34
- data/modules/mu/config/search_domain.rb +1 -1
- data/modules/mu/config/server.rb +5 -13
- data/modules/mu/config/server_pool.rb +3 -7
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +10 -0
- data/modules/mu/config/user.rb +1 -1
- data/modules/mu/config/vpc.rb +13 -17
- data/modules/mu/defaults/AWS.yaml +106 -106
- 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 +15 -0
- data/modules/mu/groomers/chef.rb +3 -0
- data/modules/mu/logger.rb +120 -144
- data/modules/mu/master.rb +22 -1
- data/modules/mu/mommacat.rb +71 -26
- data/modules/mu/mommacat/daemon.rb +23 -14
- data/modules/mu/mommacat/naming.rb +82 -3
- data/modules/mu/mommacat/search.rb +59 -16
- data/modules/mu/mommacat/storage.rb +119 -48
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +248 -62
- 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 +65 -63
- data/modules/mu/providers/aws/database.rb +1747 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
- data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/function.rb +291 -133
- 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 +469 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
- 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 +112 -78
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
- data/modules/mu/{clouds → providers}/aws/server.rb +120 -145
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
- 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 +0 -0
- data/modules/mu/{clouds → providers}/aws/vpc.rb +141 -73
- data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
- data/modules/mu/{clouds → providers}/azure.rb +4 -1
- 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 +1 -1
- 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 +15 -6
- data/modules/mu/{clouds → providers}/google/bucket.rb +2 -2
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +29 -14
- data/modules/mu/{clouds → providers}/google/database.rb +2 -9
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
- data/modules/mu/{clouds → providers}/google/function.rb +4 -4
- 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 +2 -2
- data/modules/mu/{clouds → providers}/google/role.rb +46 -35
- data/modules/mu/{clouds → providers}/google/server.rb +26 -11
- data/modules/mu/{clouds → providers}/google/server_pool.rb +11 -11
- data/modules/mu/{clouds → providers}/google/user.rb +32 -22
- 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 +38 -3
- 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 +2 -2
- 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/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 +1 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +2 -2
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +126 -98
- data/modules/mu/clouds/aws/database.rb +0 -1974
- data/modules/mu/clouds/aws/endpoint.rb +0 -596
@@ -33,7 +33,7 @@ module MU
|
|
33
33
|
my_key = OpenSSL::PKey::RSA.new(@private_key)
|
34
34
|
|
35
35
|
begin
|
36
|
-
if my_key.private_decrypt(ciphertext).force_encoding("UTF-8") == @deploy_secret.force_encoding("UTF-8")
|
36
|
+
if my_key.private_decrypt(ciphertext).force_encoding("UTF-8").chomp == @deploy_secret.force_encoding("UTF-8").chomp
|
37
37
|
MU.log "Matched ciphertext for #{MU.deploy_id}", MU::INFO
|
38
38
|
return true
|
39
39
|
else
|
@@ -165,11 +165,11 @@ module MU
|
|
165
165
|
if e.class.name != "MU::Cloud::AWS::Server::BootstrapTempFail" and !File.exist?(deploy_dir+"/.cleanup."+cloud_id) and !File.exist?(deploy_dir+"/.cleanup")
|
166
166
|
MU.log "Grooming FAILED for #{kitten.mu_name} (#{e.inspect})", MU::ERR, details: e.backtrace
|
167
167
|
sendAdminSlack("Grooming FAILED for `#{kitten.mu_name}` with `#{e.message}` :crying_cat_face:", msg: e.backtrace.join("\n"))
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
168
|
+
sendAdminMail("Grooming FAILED for #{kitten.mu_name} on #{MU.appname} \"#{MU.handle}\" (#{MU.deploy_id})",
|
169
|
+
msg: e.inspect,
|
170
|
+
data: e.backtrace,
|
171
|
+
debug: true
|
172
|
+
)
|
173
173
|
raise e if reraise_fail
|
174
174
|
else
|
175
175
|
MU.log "Grooming of #{kitten.mu_name} interrupted by cleanup or planned reboot"
|
@@ -288,8 +288,8 @@ module MU
|
|
288
288
|
|
289
289
|
# Path to the PID file used by the Momma Cat daemon
|
290
290
|
# @return [String]
|
291
|
-
def self.daemonPidFile
|
292
|
-
base = (Process.uid == 0 and !MU.localOnly) ? "/var" : MU.dataDir
|
291
|
+
def self.daemonPidFile(root = false)
|
292
|
+
base = ((Process.uid == 0 or root) and !MU.localOnly) ? "/var" : MU.dataDir
|
293
293
|
"#{base}/run/mommacat.pid"
|
294
294
|
end
|
295
295
|
|
@@ -306,8 +306,14 @@ module MU
|
|
306
306
|
Dir.mkdir(dir)
|
307
307
|
end
|
308
308
|
}
|
309
|
-
|
309
|
+
if (Process.uid != 0 and
|
310
|
+
(!$MU_CFG['overridden_keys'] or !$MU_CFG['overridden_keys'].include?("mommacat_port")) and
|
311
|
+
status(true)
|
312
|
+
) or status
|
313
|
+
return 0
|
314
|
+
end
|
310
315
|
|
316
|
+
File.unlink(daemonPidFile) if File.exists?(daemonPidFile)
|
311
317
|
MU.log "Starting Momma Cat on port #{MU.mommaCatPort}, logging to #{daemonLogFile}, PID file #{daemonPidFile}"
|
312
318
|
origdir = Dir.getwd
|
313
319
|
Dir.chdir(MU.myRoot+"/modules")
|
@@ -342,22 +348,25 @@ module MU
|
|
342
348
|
return $?.exitstatus
|
343
349
|
end
|
344
350
|
|
351
|
+
@@notified_on_pid = {}
|
352
|
+
|
345
353
|
# Return true if the Momma Cat daemon appears to be running
|
346
354
|
# @return [Boolean]
|
347
|
-
def self.status
|
355
|
+
def self.status(root = false)
|
348
356
|
if MU.inGem? and MU.muCfg['disable_mommacat']
|
349
357
|
return true
|
350
358
|
end
|
351
|
-
if File.exist?(daemonPidFile)
|
352
|
-
pid = File.read(daemonPidFile).chomp.to_i
|
359
|
+
if File.exist?(daemonPidFile(root))
|
360
|
+
pid = File.read(daemonPidFile(root)).chomp.to_i
|
353
361
|
begin
|
354
362
|
Process.getpgid(pid)
|
355
|
-
MU.log "Momma Cat running with pid #{pid.to_s}"
|
363
|
+
MU.log "Momma Cat running with pid #{pid.to_s}", (@@notified_on_pid[pid] ? MU::DEBUG : MU::INFO) # shush
|
364
|
+
@@notified_on_pid[pid] = true
|
356
365
|
return true
|
357
366
|
rescue Errno::ESRCH
|
358
367
|
end
|
359
368
|
end
|
360
|
-
MU.log "Momma Cat daemon not running", MU::NOTICE, details: daemonPidFile
|
369
|
+
MU.log "Momma Cat daemon not running", MU::NOTICE, details: daemonPidFile(root)
|
361
370
|
false
|
362
371
|
end
|
363
372
|
|
@@ -19,6 +19,16 @@ module MU
|
|
19
19
|
# the normal synchronous deploy sequence invoked by *mu-deploy*.
|
20
20
|
class MommaCat
|
21
21
|
|
22
|
+
# Lookup table to translate the word "habitat" back to its
|
23
|
+
# provider-specific jargon
|
24
|
+
HABITAT_SYNONYMS = {
|
25
|
+
"AWS" => "account",
|
26
|
+
"CloudFormation" => "account",
|
27
|
+
"Google" => "project",
|
28
|
+
"Azure" => "subscription",
|
29
|
+
"VMWare" => "sddc"
|
30
|
+
}
|
31
|
+
|
22
32
|
# Given a cloud provider's native descriptor for a resource, make some
|
23
33
|
# reasonable guesses about what the thing's name should be.
|
24
34
|
def self.guessName(desc, resourceclass, cloud_id: nil, tag_value: nil)
|
@@ -47,6 +57,74 @@ module MU
|
|
47
57
|
|
48
58
|
end
|
49
59
|
|
60
|
+
# Given a piece of a BoK resource descriptor Hash, come up with shorthand
|
61
|
+
# strings to give it a name for human readers. If nothing reasonable can be
|
62
|
+
# extracted, returns nil.
|
63
|
+
# @param obj [Hash]
|
64
|
+
# @param array_of [String]
|
65
|
+
# @param habitat_translate [String]
|
66
|
+
# @return [Array<String,nil>]
|
67
|
+
def self.getChunkName(obj, array_of = nil, habitat_translate: nil)
|
68
|
+
return [nil, nil] if obj.nil?
|
69
|
+
if [String, Integer, Boolean].include?(obj.class)
|
70
|
+
return [obj, nil]
|
71
|
+
end
|
72
|
+
obj_type = array_of || obj['type']
|
73
|
+
obj_name = obj['name'] || obj['id'] || obj['mu_name'] || obj['cloud_id']
|
74
|
+
|
75
|
+
name_string = if obj_name
|
76
|
+
if obj_type
|
77
|
+
"#{obj_type}[#{obj_name}]"
|
78
|
+
else
|
79
|
+
obj_name.dup
|
80
|
+
end
|
81
|
+
else
|
82
|
+
found_it = nil
|
83
|
+
using = nil
|
84
|
+
["entity", "role"].each { |subtype|
|
85
|
+
if obj[subtype] and obj[subtype].is_a?(Hash)
|
86
|
+
found_it = if obj[subtype]["id"]
|
87
|
+
obj[subtype]['id'].dup
|
88
|
+
elsif obj[subtype]["type"] and obj[subtype]["name"]
|
89
|
+
"#{obj[subtype]['type']}[#{obj[subtype]['name']}]"
|
90
|
+
end
|
91
|
+
break
|
92
|
+
end
|
93
|
+
}
|
94
|
+
found_it
|
95
|
+
end
|
96
|
+
if name_string
|
97
|
+
name_string.gsub!(/\[.+?\](\[.+?\]$)/, '\1')
|
98
|
+
if habitat_translate and HABITAT_SYNONYMS[habitat_translate]
|
99
|
+
name_string.sub!(/^habitats?\[(.+?)\]/i, HABITAT_SYNONYMS[habitat_translate]+'[\1]')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
location_list = []
|
104
|
+
|
105
|
+
location = if obj['project']
|
106
|
+
obj['project']
|
107
|
+
elsif obj['habitat'] and (obj['habitat']['id'] or obj['habitat']['name'])
|
108
|
+
obj['habitat']['name'] || obj['habitat']['id']
|
109
|
+
else
|
110
|
+
hab_str = nil
|
111
|
+
['projects', 'habitats'].each { |key|
|
112
|
+
|
113
|
+
if obj[key] and obj[key].is_a?(Array)
|
114
|
+
location_list = obj[key].sort.map { |p|
|
115
|
+
(p["name"] || p["id"]).gsub(/^.*?[^\/]+\/([^\/]+)$/, '\1')
|
116
|
+
}
|
117
|
+
hab_str = location_list.join(", ")
|
118
|
+
name_string.gsub!(/^.*?[^\/]+\/([^\/]+)$/, '\1') if name_string
|
119
|
+
break
|
120
|
+
end
|
121
|
+
}
|
122
|
+
hab_str
|
123
|
+
end
|
124
|
+
|
125
|
+
[name_string, location, location_list]
|
126
|
+
end
|
127
|
+
|
50
128
|
# Generate a three-character string which can be used to unique-ify the
|
51
129
|
# names of resources which might potentially collide, e.g. Windows local
|
52
130
|
# hostnames, Amazon Elastic Load Balancers, or server pool instances.
|
@@ -218,17 +296,18 @@ module MU
|
|
218
296
|
# SSH config entries, etc.
|
219
297
|
# @param server [MU::Cloud::Server]: The {MU::Cloud::Server} we'll be setting up.
|
220
298
|
# @param sync_wait [Boolean]: Whether to wait for DNS to fully synchronize before returning.
|
221
|
-
def self.nameKitten(server, sync_wait: false)
|
299
|
+
def self.nameKitten(server, sync_wait: false, no_dns: false)
|
222
300
|
node, config, _deploydata = server.describe
|
223
301
|
|
224
302
|
mu_zone = nil
|
225
303
|
# XXX GCP!
|
226
|
-
if MU::Cloud::AWS.hosted? and !MU::Cloud::AWS.isGovCloud?
|
304
|
+
if !no_dns and MU::Cloud::AWS.hosted? and !MU::Cloud::AWS.isGovCloud?
|
227
305
|
zones = MU::Cloud::DNSZone.find(cloud_id: "platform-mu")
|
228
306
|
mu_zone = zones.values.first if !zones.nil?
|
229
307
|
end
|
308
|
+
|
230
309
|
if !mu_zone.nil?
|
231
|
-
MU::Cloud::DNSZone.genericMuDNSEntry(name: node, target: server.canonicalIP, cloudclass: MU::Cloud::Server, sync_wait: sync_wait)
|
310
|
+
MU::Cloud::DNSZone.genericMuDNSEntry(name: node.gsub(/[^a-z0-9!"\#$%&'\(\)\*\+,\-\/:;<=>\?@\[\]\^_`{\|}~\.]/, '-').gsub(/--|^-/, ''), target: server.canonicalIP, cloudclass: MU::Cloud::Server, sync_wait: sync_wait)
|
232
311
|
else
|
233
312
|
MU::Master.addInstanceToEtcHosts(server.canonicalIP, node)
|
234
313
|
end
|
@@ -60,7 +60,7 @@ module MU
|
|
60
60
|
)
|
61
61
|
_shortclass, _cfg_name, type, _classname, _attrs = MU::Cloud.getResourceNames(type, true)
|
62
62
|
|
63
|
-
cloudclass = MU::Cloud.
|
63
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
64
64
|
return nil if cloudclass.virtual?
|
65
65
|
|
66
66
|
if (tag_key and !tag_value) or (!tag_key and tag_value)
|
@@ -107,7 +107,17 @@ module MU
|
|
107
107
|
matches = []
|
108
108
|
|
109
109
|
credlist.each { |creds|
|
110
|
-
|
110
|
+
cur_habitats = []
|
111
|
+
|
112
|
+
if habitats and !habitats.empty? and habitats != [nil]
|
113
|
+
valid_habitats = cloudclass.listHabitats(creds)
|
114
|
+
cur_habitats = (habitats & valid_habitats)
|
115
|
+
next if cur_habitats.empty?
|
116
|
+
else
|
117
|
+
cur_habitats = cloudclass.listHabitats(creds)
|
118
|
+
end
|
119
|
+
|
120
|
+
cloud_descs = search_cloud_provider(type, cloud, cur_habitats, region, cloud_id: cloud_id, tag_key: tag_key, tag_value: tag_value, credentials: creds, flags: flags)
|
111
121
|
|
112
122
|
cloud_descs.each_pair.each { |p, regions|
|
113
123
|
regions.each_pair.each { |r, results|
|
@@ -127,6 +137,8 @@ module MU
|
|
127
137
|
matches
|
128
138
|
end
|
129
139
|
|
140
|
+
@object_load_fails = false
|
141
|
+
|
130
142
|
# Return the resource object of another member of this deployment
|
131
143
|
# @param type [String,Symbol]: The type of resource
|
132
144
|
# @param name [String]: The name of the resource as defined in its 'name' Basket of Kittens field
|
@@ -135,7 +147,7 @@ module MU
|
|
135
147
|
# @param created_only [Boolean]: Only return the littermate if its cloud_id method returns a value
|
136
148
|
# @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
149
|
# @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)
|
150
|
+
def findLitterMate(type: nil, name: nil, mu_name: nil, cloud_id: nil, created_only: false, return_all: false, credentials: nil, habitat: nil, ignore_missing: false, debug: false, **flags)
|
139
151
|
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
|
140
152
|
|
141
153
|
# If we specified a habitat, which we may also have done by its shorthand
|
@@ -159,17 +171,35 @@ module MU
|
|
159
171
|
}
|
160
172
|
|
161
173
|
@kitten_semaphore.synchronize {
|
162
|
-
return nil if !@kittens.has_key?(type)
|
163
|
-
matches = []
|
164
174
|
|
175
|
+
if !@kittens.has_key?(type)
|
176
|
+
return nil if !@original_config or @original_config[type].nil? or @original_config[type].empty?
|
177
|
+
begin
|
178
|
+
loadObjects(false)
|
179
|
+
rescue ThreadError => e
|
180
|
+
if e.message !~ /deadlock/
|
181
|
+
raise e
|
182
|
+
end
|
183
|
+
end
|
184
|
+
if @object_load_fails or !@kittens[type]
|
185
|
+
if !ignore_missing
|
186
|
+
MU.log "#{@deploy_id}'s original config has #{@original_config[type].size == 1 ? "a" : @original_config[type].size.to_s} #{type}, but loadObjects could not populate anything from deployment metadata", MU::ERR if !@object_load_fails
|
187
|
+
@object_load_fails = true
|
188
|
+
end
|
189
|
+
return nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
matches = {}
|
165
193
|
@kittens[type].each { |habitat_group, sib_classes|
|
166
194
|
next if habitat and habitat_group and habitat_group != habitat
|
167
195
|
sib_classes.each_pair { |sib_class, cloud_objs|
|
196
|
+
|
168
197
|
if attrs[:has_multiples]
|
169
198
|
next if !name.nil? and name != sib_class or cloud_objs.empty?
|
170
199
|
if !name.nil?
|
171
200
|
if return_all
|
172
|
-
|
201
|
+
matches.merge!(cloud_objs.clone)
|
202
|
+
next
|
173
203
|
elsif cloud_objs.size == 1 and does_match.call(cloud_objs.values.first)
|
174
204
|
return cloud_objs.values.first
|
175
205
|
end
|
@@ -177,19 +207,24 @@ module MU
|
|
177
207
|
|
178
208
|
cloud_objs.each_value { |obj|
|
179
209
|
if does_match.call(obj)
|
180
|
-
|
210
|
+
if return_all
|
211
|
+
matches.merge!(cloud_objs.clone)
|
212
|
+
else
|
213
|
+
return obj.clone
|
214
|
+
end
|
181
215
|
end
|
182
216
|
}
|
183
|
-
# has_multiples is false
|
217
|
+
# has_multiples is false, "cloud_objs" is actually a singular object
|
184
218
|
elsif (name.nil? and does_match.call(cloud_objs)) or [sib_class, cloud_objs.virtual_name(name)].include?(name.to_s)
|
185
|
-
matches
|
219
|
+
matches[cloud_objs.config['name']] = cloud_objs.clone
|
186
220
|
end
|
187
221
|
}
|
188
222
|
}
|
189
223
|
|
190
|
-
return matches
|
224
|
+
return matches if return_all and matches.size >= 1
|
225
|
+
|
226
|
+
return matches.values.first if matches.size == 1
|
191
227
|
|
192
|
-
return matches if return_all and matches.size > 1
|
193
228
|
}
|
194
229
|
|
195
230
|
return nil
|
@@ -213,7 +248,7 @@ module MU
|
|
213
248
|
end
|
214
249
|
|
215
250
|
def self.generate_dummy_object(type, cloud, name, mu_name, cloud_id, desc, region, habitat, tag_value, calling_deploy, credentials)
|
216
|
-
resourceclass = MU::Cloud.
|
251
|
+
resourceclass = MU::Cloud.resourceClass(cloud, type)
|
217
252
|
|
218
253
|
use_name = if (name.nil? or name.empty?)
|
219
254
|
if !mu_name.nil?
|
@@ -269,15 +304,23 @@ module MU
|
|
269
304
|
private_class_method :generate_dummy_object
|
270
305
|
|
271
306
|
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.
|
273
|
-
resourceclass = MU::Cloud.
|
307
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
308
|
+
resourceclass = MU::Cloud.resourceClass(cloud, type)
|
274
309
|
|
275
310
|
# Decide what regions we'll search, if applicable for this resource
|
276
311
|
# type.
|
277
312
|
regions = if resourceclass.isGlobal?
|
278
313
|
[nil]
|
279
314
|
else
|
280
|
-
|
315
|
+
if region
|
316
|
+
if region.is_a?(Array) and !region.empty?
|
317
|
+
region
|
318
|
+
else
|
319
|
+
[region]
|
320
|
+
end
|
321
|
+
else
|
322
|
+
cloudclass.listRegions(credentials: credentials)
|
323
|
+
end
|
281
324
|
end
|
282
325
|
|
283
326
|
# Decide what habitats (accounts/projects/subscriptions) we'll
|
@@ -288,7 +331,7 @@ module MU
|
|
288
331
|
habitats << nil
|
289
332
|
end
|
290
333
|
if resourceclass.canLiveIn.include?(:Habitat)
|
291
|
-
habitats.concat(cloudclass.listHabitats(credentials))
|
334
|
+
habitats.concat(cloudclass.listHabitats(credentials, use_cache: false))
|
292
335
|
end
|
293
336
|
end
|
294
337
|
habitats << nil if habitats.empty?
|
@@ -88,16 +88,28 @@ module MU
|
|
88
88
|
}
|
89
89
|
end
|
90
90
|
|
91
|
+
|
91
92
|
# Overwrite this deployment's configuration with a new version. Save the
|
92
93
|
# previous version as well.
|
93
94
|
# @param new_conf [Hash]: A new configuration, fully resolved by {MU::Config}
|
94
|
-
def updateBasketofKittens(new_conf)
|
95
|
+
def updateBasketofKittens(new_conf, skip_validation: false, new_metadata: nil, save_now: false)
|
95
96
|
loadDeploy
|
96
97
|
if new_conf == @original_config
|
97
|
-
MU.log "#{@deploy_id}", MU::WARN
|
98
98
|
return
|
99
99
|
end
|
100
100
|
|
101
|
+
scrub_with = nil
|
102
|
+
|
103
|
+
# Make sure the new config that we were just handed resolves and makes
|
104
|
+
# sense
|
105
|
+
if !skip_validation
|
106
|
+
f = Tempfile.new(@deploy_id)
|
107
|
+
f.write JSON.parse(JSON.generate(new_conf)).to_yaml
|
108
|
+
conf_engine = MU::Config.new(f.path) # will throw an exception if it's bad, adoption should catch this and cope reasonably
|
109
|
+
scrub_with = conf_engine.config
|
110
|
+
f.close
|
111
|
+
end
|
112
|
+
|
101
113
|
backup = "#{deploy_dir}/basket_of_kittens.json.#{Time.now.to_i.to_s}"
|
102
114
|
MU.log "Saving previous config of #{@deploy_id} to #{backup}"
|
103
115
|
config = File.new(backup, File::CREAT|File::TRUNC|File::RDWR, 0600)
|
@@ -106,9 +118,27 @@ module MU
|
|
106
118
|
config.flock(File::LOCK_UN)
|
107
119
|
config.close
|
108
120
|
|
109
|
-
@original_config = new_conf
|
110
|
-
|
111
|
-
MU.
|
121
|
+
@original_config = new_conf.clone
|
122
|
+
|
123
|
+
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
124
|
+
next if !@deployment.has_key?(attrs[:cfg_plural])
|
125
|
+
deletia = []
|
126
|
+
# existing_deploys
|
127
|
+
@deployment[attrs[:cfg_plural]].each_pair { |res_name, data|
|
128
|
+
orig_cfg = findResourceConfig(attrs[:cfg_plural], res_name, (scrub_with || @original_config))
|
129
|
+
|
130
|
+
if orig_cfg.nil? and (!data['mu_name'] or data['mu_name'] =~ /^#{Regexp.quote(@deploy_id)}/)
|
131
|
+
MU.log "#{res_type} #{res_name} no longer configured, will remove deployment metadata", MU::NOTICE, details: data
|
132
|
+
deletia << res_name
|
133
|
+
end
|
134
|
+
}
|
135
|
+
@deployment[attrs[:cfg_plural]].reject! { |k, v| deletia.include?(k) }
|
136
|
+
}
|
137
|
+
|
138
|
+
if save_now
|
139
|
+
save!
|
140
|
+
MU.log "New config saved to #{deploy_dir}/basket_of_kittens.json"
|
141
|
+
end
|
112
142
|
end
|
113
143
|
|
114
144
|
@lock_semaphore = Mutex.new
|
@@ -147,11 +177,11 @@ module MU
|
|
147
177
|
# @param id [String]: The lock identifier to release.
|
148
178
|
# @param nonblock [Boolean]: Whether to block while waiting for the lock. In non-blocking mode, we simply return false if the lock is not available.
|
149
179
|
# return [false, nil]
|
150
|
-
def self.lock(id, nonblock = false, global = false)
|
180
|
+
def self.lock(id, nonblock = false, global = false, retries: 0, deploy_id: MU.deploy_id)
|
151
181
|
raise MuError, "Can't pass a nil id to MU::MommaCat.lock" if id.nil?
|
152
182
|
|
153
183
|
if !global
|
154
|
-
lockdir = "#{deploy_dir(
|
184
|
+
lockdir = "#{deploy_dir(deploy_id)}/locks"
|
155
185
|
else
|
156
186
|
lockdir = File.expand_path(MU.dataDir+"/locks")
|
157
187
|
end
|
@@ -160,6 +190,7 @@ module MU
|
|
160
190
|
MU.log "Creating #{lockdir}", MU::DEBUG
|
161
191
|
Dir.mkdir(lockdir, 0700)
|
162
192
|
end
|
193
|
+
nonblock = true if retries > 0
|
163
194
|
|
164
195
|
@lock_semaphore.synchronize {
|
165
196
|
if @locks[Thread.current.object_id].nil?
|
@@ -168,11 +199,38 @@ module MU
|
|
168
199
|
|
169
200
|
@locks[Thread.current.object_id][id] = File.open("#{lockdir}/#{id}.lock", File::CREAT|File::RDWR, 0600)
|
170
201
|
}
|
171
|
-
|
202
|
+
|
203
|
+
MU.log "Getting a lock on #{lockdir}/#{id}.lock (thread #{Thread.current.object_id})...", MU::DEBUG, details: caller
|
204
|
+
show_relevant = Proc.new {
|
205
|
+
@lock_semaphore.synchronize {
|
206
|
+
@locks.each_pair { |thread_id, lock|
|
207
|
+
lock.each_pair { |lockid, lockpath|
|
208
|
+
if lockid == id
|
209
|
+
thread = Thread.list.select { |t| t.object_id == thread_id }.first
|
210
|
+
if thread.object_id != Thread.current.object_id
|
211
|
+
MU.log "#{thread_id} sitting on #{id}", MU::WARN, thread.backtrace
|
212
|
+
end
|
213
|
+
end
|
214
|
+
}
|
215
|
+
}
|
216
|
+
}
|
217
|
+
}
|
172
218
|
begin
|
173
219
|
if nonblock
|
174
220
|
if !@locks[Thread.current.object_id][id].flock(File::LOCK_EX|File::LOCK_NB)
|
175
|
-
|
221
|
+
if retries > 0
|
222
|
+
success = false
|
223
|
+
MU.retrier([], loop_if: Proc.new { !success }, loop_msg: "Waiting for lock on #{lockdir}/#{id}.lock...", max: retries) { |cur_retries, _wait|
|
224
|
+
success = @locks[Thread.current.object_id][id].flock(File::LOCK_EX|File::LOCK_NB)
|
225
|
+
if !success and cur_retries > 0 and (cur_retries % 3) == 0
|
226
|
+
show_relevant.call(cur_retries)
|
227
|
+
end
|
228
|
+
}
|
229
|
+
show_relevant.call(cur_retries) if !success
|
230
|
+
return success
|
231
|
+
else
|
232
|
+
return false
|
233
|
+
end
|
176
234
|
end
|
177
235
|
else
|
178
236
|
@locks[Thread.current.object_id][id].flock(File::LOCK_EX)
|
@@ -186,11 +244,11 @@ module MU
|
|
186
244
|
|
187
245
|
# Release a flock() lock.
|
188
246
|
# @param id [String]: The lock identifier to release.
|
189
|
-
def self.unlock(id, global = false)
|
247
|
+
def self.unlock(id, global = false, deploy_id: MU.deploy_id)
|
190
248
|
raise MuError, "Can't pass a nil id to MU::MommaCat.unlock" if id.nil?
|
191
249
|
lockdir = nil
|
192
250
|
if !global
|
193
|
-
lockdir = "#{deploy_dir(
|
251
|
+
lockdir = "#{deploy_dir(deploy_id)}/locks"
|
194
252
|
else
|
195
253
|
lockdir = File.expand_path(MU.dataDir+"/locks")
|
196
254
|
end
|
@@ -361,6 +419,7 @@ module MU
|
|
361
419
|
deploy.flock(File::LOCK_UN)
|
362
420
|
deploy.close
|
363
421
|
@need_deploy_flush = false
|
422
|
+
@last_modified = nil
|
364
423
|
MU::MommaCat.updateLitter(@deploy_id, self)
|
365
424
|
end
|
366
425
|
|
@@ -512,48 +571,30 @@ module MU
|
|
512
571
|
if !@original_config['scrub_mu_isms'] and !@no_artifacts
|
513
572
|
credsets.each_pair { |cloud, creds|
|
514
573
|
creds.uniq!
|
515
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(cloud)
|
516
574
|
creds.each { |credentials|
|
517
|
-
|
575
|
+
MU::Cloud.cloudClass(cloud).writeDeploySecret(@deploy_id, @deploy_secret, credentials: credentials)
|
518
576
|
}
|
519
577
|
}
|
520
578
|
end
|
521
579
|
end
|
522
580
|
|
523
581
|
def loadObjects(delay_descriptor_load)
|
582
|
+
# Load up MU::Cloud objects for all our kittens in this deploy
|
583
|
+
|
524
584
|
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
525
585
|
type = attrs[:cfg_plural]
|
526
586
|
next if !@deployment.has_key?(type)
|
527
587
|
|
588
|
+
deletia = {}
|
528
589
|
@deployment[type].each_pair { |res_name, data|
|
529
|
-
orig_cfg =
|
530
|
-
if @original_config.has_key?(type)
|
531
|
-
@original_config[type].each { |resource|
|
532
|
-
if resource["name"] == res_name
|
533
|
-
orig_cfg = resource
|
534
|
-
break
|
535
|
-
end
|
536
|
-
}
|
537
|
-
end
|
538
|
-
|
539
|
-
# Some Server objects originated from ServerPools, get their
|
540
|
-
# configs from there
|
541
|
-
if type == "servers" and orig_cfg.nil? and
|
542
|
-
@original_config.has_key?("server_pools")
|
543
|
-
@original_config["server_pools"].each { |resource|
|
544
|
-
if resource["name"] == res_name
|
545
|
-
orig_cfg = resource
|
546
|
-
break
|
547
|
-
end
|
548
|
-
}
|
549
|
-
end
|
590
|
+
orig_cfg = findResourceConfig(type, res_name)
|
550
591
|
|
551
592
|
if orig_cfg.nil?
|
552
593
|
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
|
553
594
|
next
|
554
595
|
end
|
555
596
|
|
556
|
-
if orig_cfg['vpc']
|
597
|
+
if orig_cfg['vpc']
|
557
598
|
ref = if orig_cfg['vpc']['id'] and orig_cfg['vpc']['id'].is_a?(Hash)
|
558
599
|
orig_cfg['vpc']['id']['mommacat'] = self
|
559
600
|
MU::Config::Ref.get(orig_cfg['vpc']['id'])
|
@@ -566,18 +607,12 @@ module MU
|
|
566
607
|
end
|
567
608
|
|
568
609
|
begin
|
569
|
-
# Load up MU::Cloud objects for all our kittens in this deploy
|
570
|
-
orig_cfg['environment'] = @environment # not always set in old deploys
|
571
610
|
if attrs[:has_multiples]
|
572
611
|
data.keys.each { |mu_name|
|
573
|
-
attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: mu_name, delay_descriptor_load: delay_descriptor_load)
|
612
|
+
addKitten(type, res_name, attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: mu_name, delay_descriptor_load: delay_descriptor_load))
|
574
613
|
}
|
575
614
|
else
|
576
|
-
|
577
|
-
if data['mu_name'].nil?
|
578
|
-
raise MuError, "Unable to find or guess a Mu name for #{res_type}: #{res_name} in #{@deploy_id}"
|
579
|
-
end
|
580
|
-
attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: data['mu_name'], cloud_id: data['cloud_id'])
|
615
|
+
addKitten(type, res_name, attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: data['mu_name'], cloud_id: data['cloud_id']))
|
581
616
|
end
|
582
617
|
rescue StandardError => e
|
583
618
|
if e.class != MU::Cloud::MuCloudResourceNotImplemented
|
@@ -585,6 +620,7 @@ module MU
|
|
585
620
|
end
|
586
621
|
end
|
587
622
|
}
|
623
|
+
|
588
624
|
}
|
589
625
|
end
|
590
626
|
|
@@ -612,6 +648,14 @@ module MU
|
|
612
648
|
def loadDeployFromCache(set_context_to_me = true)
|
613
649
|
return false if !File.size?(deploy_dir+"/deployment.json")
|
614
650
|
|
651
|
+
lastmod = File.mtime("#{deploy_dir}/deployment.json")
|
652
|
+
if @last_modified and lastmod < @last_modified
|
653
|
+
MU.log "#{deploy_dir}/deployment.json last written at #{lastmod}, live meta at #{@last_modified}, not loading", MU::WARN if @last_modified
|
654
|
+
# this is a weird place for this
|
655
|
+
setThreadContextToMe if set_context_to_me
|
656
|
+
return true
|
657
|
+
end
|
658
|
+
|
615
659
|
deploy = File.open("#{deploy_dir}/deployment.json", File::RDONLY)
|
616
660
|
MU.log "Getting lock to read #{deploy_dir}/deployment.json", MU::DEBUG
|
617
661
|
# deploy.flock(File::LOCK_EX)
|
@@ -623,6 +667,7 @@ module MU
|
|
623
667
|
|
624
668
|
begin
|
625
669
|
@deployment = JSON.parse(File.read("#{deploy_dir}/deployment.json"))
|
670
|
+
# XXX is it worthwhile to merge fuckery?
|
626
671
|
rescue JSON::ParserError => e
|
627
672
|
MU.log "JSON parse failed on #{deploy_dir}/deployment.json", MU::ERR, details: e.message
|
628
673
|
end
|
@@ -632,20 +677,21 @@ module MU
|
|
632
677
|
|
633
678
|
setThreadContextToMe if set_context_to_me
|
634
679
|
|
635
|
-
@timestamp = @deployment['timestamp']
|
636
|
-
@seed = @deployment['seed']
|
637
|
-
@appname = @deployment['appname']
|
638
|
-
@handle = @deployment['handle']
|
639
|
-
|
640
680
|
true
|
641
681
|
end
|
642
682
|
|
683
|
+
|
643
684
|
###########################################################################
|
644
685
|
###########################################################################
|
645
686
|
def loadDeploy(deployment_json_only = false, set_context_to_me: true)
|
646
687
|
MU::MommaCat.deploy_struct_semaphore.synchronize {
|
647
688
|
success = loadDeployFromCache(set_context_to_me)
|
648
689
|
|
690
|
+
@timestamp ||= @deployment['timestamp']
|
691
|
+
@seed ||= @deployment['seed']
|
692
|
+
@appname ||= @deployment['appname']
|
693
|
+
@handle ||= @deployment['handle']
|
694
|
+
|
649
695
|
return if deployment_json_only and success
|
650
696
|
|
651
697
|
if File.exist?(deploy_dir+"/private_key")
|
@@ -687,5 +733,30 @@ module MU
|
|
687
733
|
}
|
688
734
|
end
|
689
735
|
|
736
|
+
def findResourceConfig(type, name, config = @original_config)
|
737
|
+
orig_cfg = nil
|
738
|
+
if config.has_key?(type)
|
739
|
+
config[type].each { |resource|
|
740
|
+
if resource["name"] == name
|
741
|
+
orig_cfg = resource
|
742
|
+
break
|
743
|
+
end
|
744
|
+
}
|
745
|
+
end
|
746
|
+
|
747
|
+
# Some Server objects originated from ServerPools, get their
|
748
|
+
# configs from there
|
749
|
+
if type == "servers" and orig_cfg.nil? and config.has_key?("server_pools")
|
750
|
+
config["server_pools"].each { |resource|
|
751
|
+
if resource["name"] == name
|
752
|
+
orig_cfg = resource
|
753
|
+
break
|
754
|
+
end
|
755
|
+
}
|
756
|
+
end
|
757
|
+
|
758
|
+
orig_cfg
|
759
|
+
end
|
760
|
+
|
690
761
|
end #class
|
691
762
|
end #module
|