cloud-mu 3.1.3 → 3.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +10 -2
- data/bin/mu-adopt +5 -1
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-run-tests +112 -27
- data/cloud-mu.gemspec +20 -20
- data/cookbooks/mu-tools/libraries/helper.rb +2 -1
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +5 -15
- data/modules/mu.rb +10 -14
- data/modules/mu/adoption.rb +20 -14
- data/modules/mu/cleanup.rb +13 -9
- data/modules/mu/cloud.rb +26 -26
- data/modules/mu/clouds/aws.rb +100 -59
- data/modules/mu/clouds/aws/alarm.rb +4 -2
- data/modules/mu/clouds/aws/bucket.rb +25 -21
- data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
- data/modules/mu/clouds/aws/collection.rb +21 -20
- data/modules/mu/clouds/aws/container_cluster.rb +47 -26
- data/modules/mu/clouds/aws/database.rb +57 -68
- data/modules/mu/clouds/aws/dnszone.rb +14 -14
- data/modules/mu/clouds/aws/endpoint.rb +20 -16
- data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
- data/modules/mu/clouds/aws/folder.rb +7 -7
- data/modules/mu/clouds/aws/function.rb +15 -12
- data/modules/mu/clouds/aws/group.rb +14 -10
- data/modules/mu/clouds/aws/habitat.rb +16 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
- data/modules/mu/clouds/aws/log.rb +13 -10
- data/modules/mu/clouds/aws/msg_queue.rb +15 -8
- data/modules/mu/clouds/aws/nosqldb.rb +18 -11
- data/modules/mu/clouds/aws/notifier.rb +11 -6
- data/modules/mu/clouds/aws/role.rb +87 -70
- data/modules/mu/clouds/aws/search_domain.rb +30 -19
- data/modules/mu/clouds/aws/server.rb +102 -72
- data/modules/mu/clouds/aws/server_pool.rb +47 -28
- data/modules/mu/clouds/aws/storage_pool.rb +5 -6
- data/modules/mu/clouds/aws/user.rb +13 -10
- data/modules/mu/clouds/aws/vpc.rb +135 -121
- data/modules/mu/clouds/azure.rb +16 -9
- data/modules/mu/clouds/azure/container_cluster.rb +2 -3
- data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
- data/modules/mu/clouds/azure/habitat.rb +8 -6
- data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
- data/modules/mu/clouds/azure/role.rb +8 -10
- data/modules/mu/clouds/azure/server.rb +65 -25
- data/modules/mu/clouds/azure/user.rb +5 -7
- data/modules/mu/clouds/azure/vpc.rb +12 -15
- data/modules/mu/clouds/cloudformation.rb +8 -7
- data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
- data/modules/mu/clouds/google.rb +39 -24
- data/modules/mu/clouds/google/bucket.rb +9 -11
- data/modules/mu/clouds/google/container_cluster.rb +27 -42
- data/modules/mu/clouds/google/database.rb +6 -9
- data/modules/mu/clouds/google/firewall_rule.rb +11 -10
- data/modules/mu/clouds/google/folder.rb +16 -9
- data/modules/mu/clouds/google/function.rb +127 -161
- data/modules/mu/clouds/google/group.rb +21 -18
- data/modules/mu/clouds/google/habitat.rb +18 -15
- data/modules/mu/clouds/google/loadbalancer.rb +14 -16
- data/modules/mu/clouds/google/role.rb +48 -31
- data/modules/mu/clouds/google/server.rb +105 -105
- data/modules/mu/clouds/google/server_pool.rb +12 -31
- data/modules/mu/clouds/google/user.rb +67 -13
- data/modules/mu/clouds/google/vpc.rb +58 -65
- data/modules/mu/config.rb +89 -1738
- data/modules/mu/config/bucket.rb +3 -3
- data/modules/mu/config/collection.rb +3 -3
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/dnszone.rb +5 -5
- data/modules/mu/config/doc_helpers.rb +517 -0
- data/modules/mu/config/endpoint.rb +3 -3
- data/modules/mu/config/firewall_rule.rb +118 -3
- data/modules/mu/config/folder.rb +3 -3
- data/modules/mu/config/function.rb +2 -2
- data/modules/mu/config/group.rb +3 -3
- data/modules/mu/config/habitat.rb +3 -3
- data/modules/mu/config/loadbalancer.rb +3 -3
- data/modules/mu/config/log.rb +3 -3
- data/modules/mu/config/msg_queue.rb +3 -3
- data/modules/mu/config/nosqldb.rb +3 -3
- data/modules/mu/config/notifier.rb +2 -2
- data/modules/mu/config/ref.rb +333 -0
- data/modules/mu/config/role.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +508 -0
- data/modules/mu/config/search_domain.rb +3 -3
- data/modules/mu/config/server.rb +86 -58
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/tail.rb +189 -0
- data/modules/mu/config/user.rb +3 -3
- data/modules/mu/config/vpc.rb +44 -4
- data/modules/mu/defaults/Google.yaml +2 -2
- data/modules/mu/deploy.rb +13 -10
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -24
- data/modules/mu/groomers/chef.rb +52 -44
- data/modules/mu/logger.rb +17 -14
- data/modules/mu/master.rb +317 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -2
- data/modules/mu/mommacat.rb +85 -1766
- data/modules/mu/mommacat/daemon.rb +394 -0
- data/modules/mu/mommacat/naming.rb +366 -0
- data/modules/mu/mommacat/storage.rb +689 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- metadata +112 -102
data/modules/mu.rb
CHANGED
@@ -121,22 +121,18 @@ class Hash
|
|
121
121
|
# custom objects which we might find in here so that we can get away with
|
122
122
|
# sorting arrays full of weird, non-primitive types.
|
123
123
|
done = []
|
124
|
-
# before_a = on.dup
|
125
|
-
# after_a = on.dup.sort
|
126
|
-
# before_b = with.dup
|
127
|
-
# after_b = with.dup.sort
|
128
124
|
on.sort.each { |elt|
|
129
125
|
if elt.is_a?(Hash) and elt['name'] or elt['entity']# or elt['cloud_id']
|
130
126
|
with.sort.each { |other_elt|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
)
|
127
|
+
# Figure out what convention this thing is using for resource identification
|
128
|
+
compare_a, compare_b = if elt['name'].nil? and elt["id"].nil? and !elt["entity"].nil? and !other_elt["entity"].nil?
|
129
|
+
[elt["entity"], other_elt["entity"]]
|
130
|
+
else
|
131
|
+
[elt, other_elt]
|
132
|
+
end
|
133
|
+
|
134
|
+
if (compare_a['name'] and compare_b['name'] == compare_a['name']) or
|
135
|
+
(compare_a['name'].nil? and !compare_a["id"].nil? and compare_a["id"] == compare_b["id"])
|
140
136
|
break if elt == other_elt
|
141
137
|
done << elt
|
142
138
|
done << other_elt
|
@@ -649,7 +645,7 @@ module MU
|
|
649
645
|
!$MU_CFG['public_address'].empty? and @@my_public_ip != $MU_CFG['public_address']
|
650
646
|
@@mu_public_addr = $MU_CFG['public_address']
|
651
647
|
if !@@mu_public_addr.match(/^\d+\.\d+\.\d+\.\d+$/)
|
652
|
-
hostname = IO.readlines("/etc/hostname")[0].gsub
|
648
|
+
hostname = IO.readlines("/etc/hostname")[0].gsub(/\n/, '')
|
653
649
|
|
654
650
|
hostlines = File.open('/etc/hosts').grep(/.*#{hostname}.*/)
|
655
651
|
if hostlines and !hostlines.empty?
|
data/modules/mu/adoption.rb
CHANGED
@@ -123,6 +123,8 @@ module MU
|
|
123
123
|
MU.log "Failed to locate a folder that resembles #{@parent}", MU::ERR
|
124
124
|
end
|
125
125
|
MU.log "Scraping complete"
|
126
|
+
|
127
|
+
@scraped
|
126
128
|
end
|
127
129
|
|
128
130
|
# Given a list of BoK style tags, try to reverse-engineer the correct
|
@@ -130,8 +132,9 @@ module MU
|
|
130
132
|
# this infers from Mu-style tagging, but we'll add a couple cases for
|
131
133
|
# special cloud provider cases.
|
132
134
|
# @param tags [Array<Hash>]
|
135
|
+
# @param basename [String]
|
133
136
|
# return [String]
|
134
|
-
def self.tagsToName(tags = [])
|
137
|
+
def self.tagsToName(tags = [], basename: nil)
|
135
138
|
tags.each { |tag|
|
136
139
|
if tag['key'] == "aws:cloudformation:logical-id"
|
137
140
|
return tag['value']
|
@@ -144,6 +147,7 @@ module MU
|
|
144
147
|
break
|
145
148
|
end
|
146
149
|
}
|
150
|
+
|
147
151
|
tags.each { |tag|
|
148
152
|
if tag['key'] == "Name"
|
149
153
|
if muid and tag['value'].match(/^#{Regexp.quote(muid)}-(.*)/)
|
@@ -153,6 +157,11 @@ module MU
|
|
153
157
|
end
|
154
158
|
end
|
155
159
|
}
|
160
|
+
|
161
|
+
if basename and muid and basename.match(/^#{Regexp.quote(muid)}-(.*)/)
|
162
|
+
return Regexp.last_match[1].downcase
|
163
|
+
end
|
164
|
+
|
156
165
|
nil
|
157
166
|
end
|
158
167
|
|
@@ -206,7 +215,7 @@ module MU
|
|
206
215
|
@scraped.each_pair { |type, resources|
|
207
216
|
res_class = begin
|
208
217
|
MU::Cloud.loadCloudType(cloud, type)
|
209
|
-
rescue MU::Cloud::MuCloudResourceNotImplemented
|
218
|
+
rescue MU::Cloud::MuCloudResourceNotImplemented
|
210
219
|
# XXX I don't think this can actually happen
|
211
220
|
next
|
212
221
|
end
|
@@ -217,8 +226,8 @@ module MU
|
|
217
226
|
class_semaphore = Mutex.new
|
218
227
|
|
219
228
|
Thread.abort_on_exception = true
|
220
|
-
resources.
|
221
|
-
threads << Thread.new(
|
229
|
+
resources.values.each { |obj_thr|
|
230
|
+
threads << Thread.new(obj_thr) { |obj|
|
222
231
|
|
223
232
|
kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats)
|
224
233
|
if kitten_cfg
|
@@ -307,14 +316,14 @@ module MU
|
|
307
316
|
|
308
317
|
private
|
309
318
|
|
310
|
-
def scrubSchemaDefaults(conf_chunk, schema_chunk, depth = 0,
|
319
|
+
def scrubSchemaDefaults(conf_chunk, schema_chunk, depth = 0, type: nil)
|
311
320
|
return if schema_chunk.nil?
|
312
321
|
|
313
322
|
if !conf_chunk.nil? and schema_chunk["properties"].kind_of?(Hash) and conf_chunk.is_a?(Hash)
|
314
323
|
deletia = []
|
315
324
|
schema_chunk["properties"].each_pair { |key, subschema|
|
316
325
|
next if !conf_chunk[key]
|
317
|
-
shortclass,
|
326
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key)
|
318
327
|
|
319
328
|
if subschema["default_if"]
|
320
329
|
subschema["default_if"].each { |cond|
|
@@ -328,7 +337,7 @@ module MU
|
|
328
337
|
if subschema["default"] and conf_chunk[key] == subschema["default"]
|
329
338
|
deletia << key
|
330
339
|
elsif ["array", "object"].include?(subschema["type"])
|
331
|
-
scrubSchemaDefaults(conf_chunk[key], subschema, depth+1,
|
340
|
+
scrubSchemaDefaults(conf_chunk[key], subschema, depth+1, type: shortclass)
|
332
341
|
end
|
333
342
|
}
|
334
343
|
deletia.each { |key| conf_chunk.delete(key) }
|
@@ -339,7 +348,7 @@ module MU
|
|
339
348
|
realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"] and MU::Cloud.supportedClouds.include?(item['cloud'])
|
340
349
|
|
341
350
|
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(item["cloud"]).const_get(type)
|
342
|
-
|
351
|
+
_toplevel_required, cloudschema = cloudclass.schema(self)
|
343
352
|
|
344
353
|
newschema = schema_chunk["items"].dup
|
345
354
|
newschema["properties"].merge!(cloudschema)
|
@@ -349,7 +358,7 @@ module MU
|
|
349
358
|
end
|
350
359
|
next if ["array", "object"].include?(realschema["type"])
|
351
360
|
|
352
|
-
scrubSchemaDefaults(item, realschema, depth+1,
|
361
|
+
scrubSchemaDefaults(item, realschema, depth+1, type: type)
|
353
362
|
}
|
354
363
|
end
|
355
364
|
|
@@ -373,10 +382,7 @@ module MU
|
|
373
382
|
'billing_acct' => {},
|
374
383
|
'us_only' => {},
|
375
384
|
}
|
376
|
-
|
377
|
-
credentials = {}
|
378
|
-
regions = {}
|
379
|
-
MU::Cloud.resource_types.each_pair { |typename, attrs|
|
385
|
+
MU::Cloud.resource_types.values.each { |attrs|
|
380
386
|
if bok[attrs[:cfg_plural]]
|
381
387
|
processed = []
|
382
388
|
bok[attrs[:cfg_plural]].each { |resource|
|
@@ -434,7 +440,7 @@ module MU
|
|
434
440
|
next if counts.size != 1
|
435
441
|
bok[field] = counts.keys.first
|
436
442
|
MU.log "Setting global default #{field} to #{bok[field]} (#{deploy.deploy_id})", MU::DEBUG
|
437
|
-
MU::Cloud.resource_types.
|
443
|
+
MU::Cloud.resource_types.values.each { |attrs|
|
438
444
|
if bok[attrs[:cfg_plural]]
|
439
445
|
new_resources = []
|
440
446
|
bok[attrs[:cfg_plural]].each { |resource|
|
data/modules/mu/cleanup.rb
CHANGED
@@ -25,8 +25,6 @@ module MU
|
|
25
25
|
# Routines for removing cloud resources.
|
26
26
|
class Cleanup
|
27
27
|
|
28
|
-
home = Etc.getpwuid(Process.uid).dir
|
29
|
-
|
30
28
|
@deploy_id = nil
|
31
29
|
@noop = false
|
32
30
|
@onlycloud = false
|
@@ -81,7 +79,7 @@ module MU
|
|
81
79
|
MU.log "Searching for remnants of #{deploy_id}, though this may be an invalid MU-ID.", MU::WARN
|
82
80
|
end
|
83
81
|
@mommacat = MU::MommaCat.new(deploy_id, mu_user: MU.mu_user, delay_descriptor_load: true)
|
84
|
-
rescue
|
82
|
+
rescue StandardError => e
|
85
83
|
MU.log "Can't load a deploy record for #{deploy_id} (#{e.inspect}), cleaning up resources by guesswork", MU::WARN, details: e.backtrace
|
86
84
|
MU.setVar("deploy_id", deploy_id)
|
87
85
|
|
@@ -90,6 +88,7 @@ module MU
|
|
90
88
|
|
91
89
|
regionsused = @mommacat.regionsUsed if @mommacat
|
92
90
|
credsused = @mommacat.credsUsed if @mommacat
|
91
|
+
habitatsused = @mommacat.habitatsUsed if @mommacat
|
93
92
|
|
94
93
|
if !@skipcloud
|
95
94
|
creds = {}
|
@@ -112,7 +111,6 @@ module MU
|
|
112
111
|
}
|
113
112
|
|
114
113
|
parent_thread_id = Thread.current.object_id
|
115
|
-
deleted_nodes = 0
|
116
114
|
cloudthreads = []
|
117
115
|
keyname = "deploy-#{MU.deploy_id}"
|
118
116
|
had_failures = false
|
@@ -127,7 +125,6 @@ module MU
|
|
127
125
|
next if credsused and !credsused.include?(credset)
|
128
126
|
global_vs_region_semaphore = Mutex.new
|
129
127
|
global_done = {}
|
130
|
-
habitats_done = {}
|
131
128
|
regionthreads = []
|
132
129
|
acct_regions.each { |r|
|
133
130
|
if regionsused
|
@@ -172,10 +169,13 @@ module MU
|
|
172
169
|
# CloudFormation sometimes fails internally.
|
173
170
|
projectthreads = []
|
174
171
|
projects.each { |project|
|
175
|
-
next if !habitatclass.isLive?(project, credset)
|
176
172
|
if habitats and !habitats.empty? and project != ""
|
177
173
|
next if !habitats.include?(project)
|
178
174
|
end
|
175
|
+
if habitatsused and !habitatsused.empty? and project != ""
|
176
|
+
next if !habitatsused.include?(project)
|
177
|
+
end
|
178
|
+
next if !habitatclass.isLive?(project, credset)
|
179
179
|
|
180
180
|
projectthreads << Thread.new {
|
181
181
|
MU.dupGlobals(parent_thread_id)
|
@@ -192,7 +192,6 @@ module MU
|
|
192
192
|
"skipsnapshots" => @skipsnapshots,
|
193
193
|
}
|
194
194
|
types_in_order.each { |t|
|
195
|
-
shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(t)
|
196
195
|
begin
|
197
196
|
skipme = false
|
198
197
|
global_vs_region_semaphore.synchronize {
|
@@ -424,8 +423,12 @@ module MU
|
|
424
423
|
|
425
424
|
end
|
426
425
|
|
427
|
-
|
428
|
-
|
426
|
+
# Wrapper for dynamically invoking resource type cleanup methods.
|
427
|
+
# @param type [String]:
|
428
|
+
# @param credset [String]:
|
429
|
+
# @param provider [String]:
|
430
|
+
# @param flags [Hash]:
|
431
|
+
# @param region [String]:
|
429
432
|
def self.call_cleanup(type, credset, provider, flags, region)
|
430
433
|
if @mommacat.nil? or @mommacat.numKittens(types: [type]) > 0
|
431
434
|
if @mommacat
|
@@ -458,6 +461,7 @@ module MU
|
|
458
461
|
else
|
459
462
|
true
|
460
463
|
end
|
464
|
+
|
461
465
|
end
|
462
466
|
end #class
|
463
467
|
end #module
|
data/modules/mu/cloud.rb
CHANGED
@@ -479,7 +479,7 @@ module MU
|
|
479
479
|
@@platform_cache = MU::Cloud.supportedClouds.map { |cloud|
|
480
480
|
begin
|
481
481
|
loadCloudType(cloud, :Server)
|
482
|
-
rescue MU::Cloud::MuCloudResourceNotImplemented, MU::MuError
|
482
|
+
rescue MU::Cloud::MuCloudResourceNotImplemented, MU::MuError
|
483
483
|
next
|
484
484
|
end
|
485
485
|
|
@@ -529,7 +529,7 @@ module MU
|
|
529
529
|
images.deep_merge!(YAML.load(response))
|
530
530
|
break
|
531
531
|
end
|
532
|
-
rescue
|
532
|
+
rescue StandardError
|
533
533
|
if fail_hard
|
534
534
|
raise MuError, "Failed to fetch stock images from #{base_url}/#{cloud}.yaml (#{e.message})"
|
535
535
|
else
|
@@ -624,7 +624,7 @@ module MU
|
|
624
624
|
end
|
625
625
|
else
|
626
626
|
if region
|
627
|
-
images.
|
627
|
+
images.values.each { |regions|
|
628
628
|
# Filter to match our requested region, but for all the platforms,
|
629
629
|
# since we didn't specify one.
|
630
630
|
if regions.is_a?(Hash)
|
@@ -652,7 +652,6 @@ module MU
|
|
652
652
|
cloudclass[:cfg_name] == type or
|
653
653
|
cloudclass[:cfg_plural] == type or
|
654
654
|
Object.const_get("MU").const_get("Cloud").const_get(name) == type
|
655
|
-
cfg_name = cloudclass[:cfg_name]
|
656
655
|
type = name
|
657
656
|
return [type.to_sym, cloudclass[:cfg_name], cloudclass[:cfg_plural], Object.const_get("MU").const_get("Cloud").const_get(name), cloudclass]
|
658
657
|
end
|
@@ -802,7 +801,7 @@ module MU
|
|
802
801
|
# @return [Class]: The cloud-specific class implementing this resource
|
803
802
|
def self.loadCloudType(cloud, type)
|
804
803
|
raise MuError, "cloud argument to MU::Cloud.loadCloudType cannot be nil" if cloud.nil?
|
805
|
-
shortclass, cfg_name,
|
804
|
+
shortclass, cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(type)
|
806
805
|
if @cloud_class_cache.has_key?(cloud) and @cloud_class_cache[cloud].has_key?(type)
|
807
806
|
if @cloud_class_cache[cloud][type].nil?
|
808
807
|
raise MuError, "The '#{type}' resource is not supported in cloud #{cloud} (tried MU::#{cloud}::#{type})", caller
|
@@ -864,7 +863,7 @@ module MU
|
|
864
863
|
}
|
865
864
|
}
|
866
865
|
|
867
|
-
@@resource_types.
|
866
|
+
@@resource_types.keys.each { |name|
|
868
867
|
Object.const_get("MU").const_get("Cloud").const_get(name).class_eval {
|
869
868
|
attr_reader :cloudclass
|
870
869
|
attr_reader :cloudobj
|
@@ -1145,19 +1144,19 @@ module MU
|
|
1145
1144
|
if self.class.cfg_name == "server"
|
1146
1145
|
begin
|
1147
1146
|
ip = canonicalIP
|
1148
|
-
MU::
|
1147
|
+
MU::Master.removeIPFromSSHKnownHosts(ip) if ip
|
1149
1148
|
if @deploy and @deploy.deployment and
|
1150
|
-
@deploy.deployment['servers'] and @config['name']
|
1149
|
+
@deploy.deployment['servers'] and @config['name']
|
1151
1150
|
me = @deploy.deployment['servers'][@config['name']][@mu_name]
|
1152
1151
|
if me
|
1153
1152
|
["private_ip_address", "public_ip_address"].each { |field|
|
1154
1153
|
if me[field]
|
1155
|
-
MU::
|
1154
|
+
MU::Master.removeIPFromSSHKnownHosts(me[field])
|
1156
1155
|
end
|
1157
1156
|
}
|
1158
1157
|
if me["private_ip_list"]
|
1159
|
-
me["private_ip_list"].each { |
|
1160
|
-
MU::
|
1158
|
+
me["private_ip_list"].each { |private_ip|
|
1159
|
+
MU::Master.removeIPFromSSHKnownHosts(private_ip)
|
1161
1160
|
}
|
1162
1161
|
end
|
1163
1162
|
end
|
@@ -1286,7 +1285,7 @@ module MU
|
|
1286
1285
|
if !@cloud_desc_cache
|
1287
1286
|
MU.log "cloud_desc via #{self.class.name}.find() failed to locate a live object.\nWas called by #{caller[0]}", MU::WARN, details: args
|
1288
1287
|
end
|
1289
|
-
rescue
|
1288
|
+
rescue StandardError => e
|
1290
1289
|
MU.log "Got #{e.inspect} trying to find cloud handle for #{self.class.shortname} #{@mu_name} (#{@cloud_id})", MU::WARN
|
1291
1290
|
raise e
|
1292
1291
|
end
|
@@ -1297,9 +1296,8 @@ module MU
|
|
1297
1296
|
|
1298
1297
|
# Retrieve all of the known metadata for this resource.
|
1299
1298
|
# @param cloud_id [String]: The cloud platform's identifier for the resource we're describing. Makes lookups more efficient.
|
1300
|
-
# @param update_cache [Boolean]: Ignore cached data if we have any, instead reconsituting from original sources.
|
1301
1299
|
# @return [Array<Hash>]: mu_name, config, deploydata
|
1302
|
-
def describe(cloud_id: nil
|
1300
|
+
def describe(cloud_id: nil)
|
1303
1301
|
if cloud_id.nil? and !@cloudobj.nil?
|
1304
1302
|
@cloud_id ||= @cloudobj.cloud_id
|
1305
1303
|
end
|
@@ -1614,7 +1612,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1614
1612
|
end
|
1615
1613
|
begin
|
1616
1614
|
cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
|
1617
|
-
rescue MU::MuError
|
1615
|
+
rescue MU::MuError
|
1618
1616
|
next
|
1619
1617
|
end
|
1620
1618
|
|
@@ -1778,17 +1776,14 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1778
1776
|
MU.log "Failed at installing Cygwin", MU::ERR, details: resp
|
1779
1777
|
end
|
1780
1778
|
|
1781
|
-
set_hostname = true
|
1782
1779
|
hostname = nil
|
1783
1780
|
if !@config['active_directory'].nil?
|
1784
1781
|
if @config['active_directory']['node_type'] == "domain_controller" && @config['active_directory']['domain_controller_hostname']
|
1785
1782
|
hostname = @config['active_directory']['domain_controller_hostname']
|
1786
1783
|
@mu_windows_name = hostname
|
1787
|
-
set_hostname = true
|
1788
1784
|
else
|
1789
1785
|
# Do we have an AD specific hostname?
|
1790
1786
|
hostname = @mu_windows_name
|
1791
|
-
set_hostname = true
|
1792
1787
|
end
|
1793
1788
|
else
|
1794
1789
|
hostname = @mu_windows_name
|
@@ -1859,7 +1854,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1859
1854
|
end
|
1860
1855
|
if windows?
|
1861
1856
|
output = ssh.exec!(win_env_fix)
|
1862
|
-
output
|
1857
|
+
output += ssh.exec!(win_installer_check)
|
1863
1858
|
raise MU::Cloud::BootstrapTempFail, "Got nil output from ssh session, waiting and retrying" if output.nil?
|
1864
1859
|
if output.match(/InProgress/)
|
1865
1860
|
raise MU::Cloud::BootstrapTempFail, "Windows Installer service is still doing something, need to wait"
|
@@ -1906,14 +1901,13 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1906
1901
|
# @param winrm_retries [Integer]:
|
1907
1902
|
# @param reboot_on_problems [Boolean]:
|
1908
1903
|
def getWinRMSession(max_retries = 40, retry_interval = 60, timeout: 30, winrm_retries: 5, reboot_on_problems: false)
|
1909
|
-
|
1904
|
+
_nat_ssh_key, _nat_ssh_user, _nat_ssh_host, canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
|
1910
1905
|
@mu_name ||= @config['mu_name']
|
1911
1906
|
|
1912
|
-
conn = nil
|
1913
1907
|
shell = nil
|
1914
1908
|
opts = nil
|
1915
1909
|
# and now, a thing I really don't want to do
|
1916
|
-
MU::
|
1910
|
+
MU::Master.addInstanceToEtcHosts(canonical_ip, @mu_name)
|
1917
1911
|
|
1918
1912
|
# catch exceptions that circumvent our regular call stack
|
1919
1913
|
Thread.abort_on_exception = false
|
@@ -1949,7 +1943,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1949
1943
|
retries, rebootable_fails = handleWindowsFail(e, retries, rebootable_fails, max_retries: max_retries, reboot_on_problems: reboot_on_problems, retry_interval: retry_interval)
|
1950
1944
|
retry
|
1951
1945
|
ensure
|
1952
|
-
MU::
|
1946
|
+
MU::Master.removeInstanceFromEtcHosts(@mu_name)
|
1953
1947
|
end
|
1954
1948
|
|
1955
1949
|
shell
|
@@ -1960,7 +1954,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
1960
1954
|
# @return [Net::SSH::Connection::Session]
|
1961
1955
|
def getSSHSession(max_retries = 12, retry_interval = 30)
|
1962
1956
|
ssh_keydir = Etc.getpwnam(@deploy.mu_user).dir+"/.ssh"
|
1963
|
-
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user,
|
1957
|
+
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, _ssh_key_name = getSSHConfig
|
1964
1958
|
session = nil
|
1965
1959
|
retries = 0
|
1966
1960
|
|
@@ -2011,7 +2005,8 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
2011
2005
|
e.remember_host!
|
2012
2006
|
session.close
|
2013
2007
|
retry
|
2014
|
-
rescue SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, MU::Cloud::NetSSHFail => e
|
2008
|
+
# rescue SystemCallError, Timeout::Error, Errno::ECONNRESET, Errno::EHOSTUNREACH, Net::SSH::Proxy::ConnectError, SocketError, Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, IOError, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, MU::Cloud::NetSSHFail => e
|
2009
|
+
rescue SystemExit, Timeout::Error, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::ConnectionTimeout, Net::SSH::Proxy::ConnectError, Net::SSH::Exception, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE, SocketError, IOError => e
|
2015
2010
|
begin
|
2016
2011
|
session.close if !session.nil?
|
2017
2012
|
rescue Net::SSH::Disconnect, IOError => e
|
@@ -2059,12 +2054,17 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
|
|
2059
2054
|
clouds.each { |cloud|
|
2060
2055
|
begin
|
2061
2056
|
cloudclass = MU::Cloud.loadCloudType(cloud, shortname)
|
2057
|
+
|
2058
|
+
if cloudclass.isGlobal?
|
2059
|
+
params.delete(:region)
|
2060
|
+
end
|
2061
|
+
|
2062
2062
|
raise MuCloudResourceNotImplemented if !cloudclass.respond_to?(:cleanup) or cloudclass.method(:cleanup).owner.to_s != "#<Class:#{cloudclass}>"
|
2063
2063
|
MU.log "Invoking #{cloudclass}.cleanup from #{shortname}", MU::DEBUG, details: flags
|
2064
2064
|
cloudclass.cleanup(params)
|
2065
2065
|
rescue MuCloudResourceNotImplemented
|
2066
2066
|
MU.log "No #{cloud} implementation of #{shortname}.cleanup, skipping", MU::DEBUG, details: flags
|
2067
|
-
rescue
|
2067
|
+
rescue StandardError => e
|
2068
2068
|
in_msg = cloud
|
2069
2069
|
if params and params[:region]
|
2070
2070
|
in_msg += " "+params[:region]
|
data/modules/mu/clouds/aws.rb
CHANGED
@@ -38,8 +38,8 @@ module MU
|
|
38
38
|
# repetitive setup tasks (like resolving +:resource_group+ for Azure
|
39
39
|
# resources) have always been done.
|
40
40
|
# @param cloudobj [MU::Cloud]
|
41
|
-
# @param
|
42
|
-
def self.resourceInitHook(cloudobj,
|
41
|
+
# @param _deploy [MU::MommaCat]
|
42
|
+
def self.resourceInitHook(cloudobj, _deploy)
|
43
43
|
class << self
|
44
44
|
attr_reader :cloudformation_data
|
45
45
|
end
|
@@ -63,7 +63,6 @@ module MU
|
|
63
63
|
return nil
|
64
64
|
end
|
65
65
|
|
66
|
-
loaded = false
|
67
66
|
cred_obj = nil
|
68
67
|
if cred_cfg['access_key'] and cred_cfg['access_secret'] and
|
69
68
|
# access key and secret just sitting in mu.yaml
|
@@ -137,11 +136,22 @@ module MU
|
|
137
136
|
# assume we've got an IAM profile and hope for the best
|
138
137
|
ENV.delete('AWS_ACCESS_KEY_ID')
|
139
138
|
ENV.delete('AWS_SECRET_ACCESS_KEY')
|
140
|
-
|
139
|
+
retries = 0
|
140
|
+
begin
|
141
|
+
cred_obj = Aws::InstanceProfileCredentials.new
|
142
|
+
if cred_obj.nil?
|
143
|
+
retries += 1
|
144
|
+
MU.log "Failed to fetch AWS instance profile credentials, attempt #{retries.to_s}/10", MU::WARN
|
145
|
+
sleep 3
|
146
|
+
end
|
147
|
+
end while cred_obj.nil? and retries < 10
|
141
148
|
# if name.nil?
|
142
149
|
# Aws.config = {region: ENV['EC2_REGION']}
|
143
150
|
# end
|
144
151
|
end
|
152
|
+
if cred_obj.nil?
|
153
|
+
MU.log "cred_obj is nil and hosted? says #{hosted?.to_s}", MU::WARN, details: name
|
154
|
+
end
|
145
155
|
|
146
156
|
if name.nil?
|
147
157
|
@@creds_loaded["#default"] = cred_obj
|
@@ -283,52 +293,13 @@ module MU
|
|
283
293
|
)
|
284
294
|
end
|
285
295
|
|
286
|
-
# Tag EC2 resources.
|
287
|
-
#
|
288
|
-
# @param resources [Array<String>]: The cloud provider identifier of the resource to tag
|
289
|
-
# @param key [String]: The name of the tag to create
|
290
|
-
# @param value [String]: The value of the tag
|
291
|
-
# @param region [String]: The cloud provider region
|
292
|
-
# @return [void,<Hash>]
|
293
|
-
def self.createTag(key, value, resources = [], region: myRegion, credentials: nil)
|
294
|
-
|
295
|
-
if !MU::Cloud::CloudFormation.emitCloudFormation
|
296
|
-
begin
|
297
|
-
MU::Cloud::AWS.ec2(region: region, credentials: credentials).create_tags(
|
298
|
-
resources: resources,
|
299
|
-
tags: [
|
300
|
-
{
|
301
|
-
key: key,
|
302
|
-
value: value
|
303
|
-
}
|
304
|
-
]
|
305
|
-
)
|
306
|
-
rescue Aws::EC2::Errors::ServiceError => e
|
307
|
-
MU.log "Got #{e.inspect} tagging #{resources.size.to_s} resources with #{key}=#{value}", MU::WARN, details: resources if attempts > 1
|
308
|
-
if attempts < 5
|
309
|
-
attempts = attempts + 1
|
310
|
-
sleep 15
|
311
|
-
retry
|
312
|
-
else
|
313
|
-
raise e
|
314
|
-
end
|
315
|
-
end
|
316
|
-
MU.log "Created tag #{key} with value #{value}", MU::DEBUG, details: resources
|
317
|
-
else
|
318
|
-
return {
|
319
|
-
"Key" => key,
|
320
|
-
"Value" => value
|
321
|
-
}
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
296
|
@@azs = {}
|
326
297
|
# List the Availability Zones associated with a given Amazon Web Services
|
327
298
|
# region. If no region is given, search the one in which this MU master
|
328
299
|
# server resides.
|
329
300
|
# @param region [String]: The region to search.
|
330
301
|
# @return [Array<String>]: The Availability Zones in this region.
|
331
|
-
def self.listAZs(region: MU.curRegion,
|
302
|
+
def self.listAZs(region: MU.curRegion, credentials: nil)
|
332
303
|
cfg = credConfig(credentials)
|
333
304
|
return [] if !cfg
|
334
305
|
if !region.nil? and @@azs[region]
|
@@ -491,7 +462,32 @@ module MU
|
|
491
462
|
# @param cloudobj [MU::Cloud::AWS]: The resource from which to extract the habitat id
|
492
463
|
# @return [String,nil]
|
493
464
|
def self.habitat(cloudobj, nolookup: false, deploy: nil)
|
494
|
-
|
465
|
+
@@habmap ||= {}
|
466
|
+
# XXX whaddabout config['habitat'] HNNNGH
|
467
|
+
|
468
|
+
if cloudobj.respond_to?(:account_number) and cloudobj.account_number and
|
469
|
+
!cloudobj.account_number.empty?
|
470
|
+
return cloudobj.account_number
|
471
|
+
elsif cloudobj.config and cloudobj.config['account']
|
472
|
+
if nolookup
|
473
|
+
return cloudobj.config['account']
|
474
|
+
end
|
475
|
+
if @@habmap[cloudobj.config['account']]
|
476
|
+
return @@habmap[cloudobj.config['account']]
|
477
|
+
end
|
478
|
+
deploy ||= cloudobj.deploy if cloudobj.respond_to?(:deploy)
|
479
|
+
|
480
|
+
MU.log "Incomplete implementation: MU::Cloud::AWS.habitat", MU::DEBUG, details: deploy
|
481
|
+
|
482
|
+
# accountobj = accountLookup(cloudobj.config['account'], deploy, raise_on_fail: false)
|
483
|
+
|
484
|
+
# if accountobj
|
485
|
+
# @@habmap[cloudobj.config['account']] = accountobj.cloud_id
|
486
|
+
# return accountobj.cloud_id
|
487
|
+
# end
|
488
|
+
end
|
489
|
+
|
490
|
+
nil
|
495
491
|
end
|
496
492
|
|
497
493
|
|
@@ -506,7 +502,6 @@ module MU
|
|
506
502
|
|
507
503
|
return creds['account_number'] if creds['account_number']
|
508
504
|
|
509
|
-
user_list = MU::Cloud::AWS.iam(credentials: name).list_users.users
|
510
505
|
acct_num = MU::Cloud::AWS.iam(credentials: name).list_users.users.first.arn.split(/:/)[4]
|
511
506
|
acct_num.to_s
|
512
507
|
end
|
@@ -543,8 +538,8 @@ module MU
|
|
543
538
|
if !found
|
544
539
|
MU.log "Attempting to create log bucket #{cfg['log_bucket_name']} for credentials #{credentials}", MU::WARN
|
545
540
|
begin
|
546
|
-
|
547
|
-
rescue Aws::S3::Errors::BucketAlreadyExists
|
541
|
+
MU::Cloud::AWS.s3(credentials: credentials).create_bucket(bucket: cfg['log_bucket_name'], acl: "private")
|
542
|
+
rescue Aws::S3::Errors::BucketAlreadyExists
|
548
543
|
raise MuError, "AWS credentials #{credentials} need a log bucket, and the name #{cfg['log_bucket_name']} is unavailable. Use mu-configure to edit credentials '#{credentials}' or 'hostname'"
|
549
544
|
end
|
550
545
|
end
|
@@ -620,9 +615,9 @@ module MU
|
|
620
615
|
# Check each credential sets' resident account, then
|
621
616
|
$MU_CFG['aws'].each_pair { |acctname, cfg|
|
622
617
|
begin
|
623
|
-
|
618
|
+
MU::Cloud::AWS.iam(credentials: acctname).list_users.users
|
624
619
|
# rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
|
625
|
-
rescue
|
620
|
+
rescue StandardError => e
|
626
621
|
MU.log e.inspect, MU::WARN, details: cfg
|
627
622
|
next
|
628
623
|
end
|
@@ -653,7 +648,7 @@ module MU
|
|
653
648
|
# begin
|
654
649
|
# user_list = MU::Cloud::AWS.iam(region: credConfig['region']).list_users.users
|
655
650
|
## rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
|
656
|
-
# rescue
|
651
|
+
# rescue StandardError => e
|
657
652
|
# MU.log "Got #{e.inspect} while trying to figure out our account number", MU::WARN, details: caller
|
658
653
|
# end
|
659
654
|
# if user_list.nil? or user_list.size == 0
|
@@ -682,7 +677,6 @@ module MU
|
|
682
677
|
if @@regions.size == 0
|
683
678
|
return [] if credConfig.nil?
|
684
679
|
result = MU::Cloud::AWS.ec2(region: myRegion, credentials: credentials).describe_regions.regions
|
685
|
-
regions = []
|
686
680
|
@@regions_semaphore.synchronize {
|
687
681
|
begin
|
688
682
|
result.each { |r|
|
@@ -1154,6 +1148,55 @@ module MU
|
|
1154
1148
|
end
|
1155
1149
|
end
|
1156
1150
|
|
1151
|
+
# Tag a resource. Defaults to applying our MU deployment identifier, if no
|
1152
|
+
# arguments other than the resource identifier are given.
|
1153
|
+
# XXX this belongs in the cloud layer(s)
|
1154
|
+
#
|
1155
|
+
# @param resource [String]: The cloud provider identifier of the resource to tag
|
1156
|
+
# @param tag_name [String]: The name of the tag to create
|
1157
|
+
# @param tag_value [String]: The value of the tag
|
1158
|
+
# @param region [String]: The cloud provider region
|
1159
|
+
# @return [void]
|
1160
|
+
def self.createTag(resource = nil,
|
1161
|
+
tag_name="MU-ID",
|
1162
|
+
tag_value=MU.deploy_id,
|
1163
|
+
region: MU.curRegion,
|
1164
|
+
credentials: nil)
|
1165
|
+
attempts = 0
|
1166
|
+
|
1167
|
+
return nil if resource.nil?
|
1168
|
+
resource = [resource] if resource.is_a?(String)
|
1169
|
+
|
1170
|
+
if !MU::Cloud::CloudFormation.emitCloudFormation
|
1171
|
+
begin
|
1172
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).create_tags(
|
1173
|
+
resources: resource,
|
1174
|
+
tags: [
|
1175
|
+
{
|
1176
|
+
key: tag_name,
|
1177
|
+
value: tag_value
|
1178
|
+
}
|
1179
|
+
]
|
1180
|
+
)
|
1181
|
+
rescue Aws::EC2::Errors::ServiceError => e
|
1182
|
+
MU.log "Got #{e.inspect} tagging #{resource} with #{tag_name}=#{tag_value}", MU::WARN if attempts > 1
|
1183
|
+
if attempts < 5
|
1184
|
+
attempts = attempts + 1
|
1185
|
+
sleep 15
|
1186
|
+
retry
|
1187
|
+
else
|
1188
|
+
raise e
|
1189
|
+
end
|
1190
|
+
end
|
1191
|
+
MU.log "Created tag #{tag_name} with value #{tag_value} for resource #{resource}", MU::DEBUG
|
1192
|
+
else
|
1193
|
+
return {
|
1194
|
+
"Key" => tag_name,
|
1195
|
+
"Value" => tag_value
|
1196
|
+
}
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
|
1157
1200
|
@syslog_port_semaphore = Mutex.new
|
1158
1201
|
# Punch AWS security group holes for client nodes to talk back to us, the
|
1159
1202
|
# Mu Master, if we're in AWS.
|
@@ -1205,8 +1248,8 @@ module MU
|
|
1205
1248
|
)
|
1206
1249
|
sg_id = group.group_id
|
1207
1250
|
my_sgs << sg_id
|
1208
|
-
MU::
|
1209
|
-
MU::
|
1251
|
+
MU::Cloud::AWS.createTag sg_id, "Name", my_client_sg_name
|
1252
|
+
MU::Cloud::AWS.createTag sg_id, "MU-MASTER-IP", MU.mu_public_ip
|
1210
1253
|
MU::Cloud::AWS.ec2.modify_instance_attribute(
|
1211
1254
|
instance_id: my_instance_id,
|
1212
1255
|
groups: my_sgs
|
@@ -1237,7 +1280,7 @@ module MU
|
|
1237
1280
|
end
|
1238
1281
|
|
1239
1282
|
allow_ips = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
1240
|
-
MU::MommaCat.listAllNodes.
|
1283
|
+
MU::MommaCat.listAllNodes.values.each { |data|
|
1241
1284
|
next if data.nil? or !data.is_a?(Hash)
|
1242
1285
|
["public_ip_address"].each { |key|
|
1243
1286
|
if data.has_key?(key) and !data[key].nil? and !data[key].empty?
|
@@ -1266,7 +1309,7 @@ module MU
|
|
1266
1309
|
}
|
1267
1310
|
]
|
1268
1311
|
)
|
1269
|
-
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
1312
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
1270
1313
|
MU.log "Permission disappeared from #{sg_id} (port #{port.to_s}) before I could remove it", MU::WARN, details: MU.structToHash(rule.ip_ranges)
|
1271
1314
|
end
|
1272
1315
|
end
|
@@ -1300,8 +1343,6 @@ module MU
|
|
1300
1343
|
}
|
1301
1344
|
end
|
1302
1345
|
|
1303
|
-
private
|
1304
|
-
|
1305
1346
|
# XXX we shouldn't have to do this, but AWS does not provide a way to look
|
1306
1347
|
# it up, and the pricing API only returns the human-readable strings.
|
1307
1348
|
@@regionLookup = {
|
@@ -1397,7 +1438,7 @@ module MU
|
|
1397
1438
|
MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}, waiting #{interval.to_s}s and retrying. Args were: #{arguments}", debuglevel, details: caller
|
1398
1439
|
sleep interval
|
1399
1440
|
retry
|
1400
|
-
rescue
|
1441
|
+
rescue StandardError => e
|
1401
1442
|
MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}", MU::DEBUG, details: arguments
|
1402
1443
|
raise e
|
1403
1444
|
end
|