cloud-mu 3.2.0 → 3.5.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/ansible/roles/mu-nat/tasks/main.yml +3 -0
- data/bin/mu-adopt +12 -1
- data/bin/mu-aws-setup +41 -7
- data/bin/mu-azure-setup +34 -0
- data/bin/mu-configure +214 -119
- data/bin/mu-gcp-setup +37 -2
- data/bin/mu-load-config.rb +2 -1
- data/bin/mu-node-manage +3 -0
- data/bin/mu-refresh-ssl +67 -0
- data/bin/mu-run-tests +28 -6
- data/bin/mu-self-update +30 -10
- data/bin/mu-upload-chef-artifacts +30 -26
- data/cloud-mu.gemspec +10 -8
- data/cookbooks/mu-master/attributes/default.rb +5 -1
- data/cookbooks/mu-master/metadata.rb +2 -2
- data/cookbooks/mu-master/recipes/default.rb +81 -26
- data/cookbooks/mu-master/recipes/init.rb +197 -62
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +1 -1
- data/cookbooks/mu-master/recipes/vault.rb +78 -77
- data/cookbooks/mu-master/templates/default/mods/rewrite.conf.erb +1 -0
- data/cookbooks/mu-master/templates/default/nagios.conf.erb +103 -0
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +14 -30
- data/cookbooks/mu-tools/attributes/default.rb +12 -0
- data/cookbooks/mu-tools/files/centos-6/CentOS-Base.repo +47 -0
- data/cookbooks/mu-tools/libraries/helper.rb +98 -4
- data/cookbooks/mu-tools/libraries/monkey.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +31 -9
- data/cookbooks/mu-tools/recipes/aws_api.rb +8 -2
- data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +2 -9
- data/cookbooks/mu-tools/recipes/google_api.rb +7 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
- data/cookbooks/mu-tools/resources/disk.rb +113 -42
- data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
- data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
- data/extras/Gemfile.lock.bootstrap +394 -0
- data/extras/bucketstubs/error.html +0 -0
- data/extras/bucketstubs/index.html +0 -0
- data/extras/clean-stock-amis +11 -3
- data/extras/generate-stock-images +6 -3
- data/extras/git_rpm/build.sh +20 -0
- data/extras/git_rpm/mugit.spec +53 -0
- 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/extras/image-generators/VMWare/centos8.yaml +15 -0
- data/extras/openssl_rpm/build.sh +19 -0
- data/extras/openssl_rpm/mussl.spec +46 -0
- data/extras/python_rpm/muthon.spec +14 -4
- data/extras/ruby_rpm/muby.spec +9 -5
- data/extras/sqlite_rpm/build.sh +19 -0
- data/extras/sqlite_rpm/muqlite.spec +47 -0
- data/install/installer +7 -5
- data/modules/mommacat.ru +2 -2
- data/modules/mu.rb +14 -7
- data/modules/mu/adoption.rb +5 -5
- data/modules/mu/cleanup.rb +47 -25
- data/modules/mu/cloud.rb +29 -1
- data/modules/mu/cloud/dnszone.rb +0 -2
- data/modules/mu/cloud/machine_images.rb +1 -1
- data/modules/mu/cloud/providers.rb +6 -1
- data/modules/mu/cloud/resource_base.rb +16 -7
- data/modules/mu/cloud/ssh_sessions.rb +5 -1
- data/modules/mu/cloud/wrappers.rb +20 -7
- data/modules/mu/config.rb +28 -12
- data/modules/mu/config/bucket.rb +31 -2
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/container_cluster.rb +1 -1
- data/modules/mu/config/database.rb +3 -3
- data/modules/mu/config/dnszone.rb +4 -3
- data/modules/mu/config/endpoint.rb +1 -0
- data/modules/mu/config/firewall_rule.rb +1 -1
- data/modules/mu/config/function.rb +16 -7
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/notifier.rb +7 -18
- data/modules/mu/config/ref.rb +55 -9
- data/modules/mu/config/schema_helpers.rb +12 -3
- data/modules/mu/config/server.rb +11 -5
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/vpc.rb +11 -10
- data/modules/mu/defaults/AWS.yaml +106 -106
- data/modules/mu/deploy.rb +40 -14
- data/modules/mu/groomers/chef.rb +2 -2
- data/modules/mu/master.rb +70 -3
- data/modules/mu/mommacat.rb +28 -9
- data/modules/mu/mommacat/daemon.rb +13 -7
- data/modules/mu/mommacat/naming.rb +2 -2
- data/modules/mu/mommacat/search.rb +16 -5
- data/modules/mu/mommacat/storage.rb +67 -32
- data/modules/mu/providers/aws.rb +298 -85
- data/modules/mu/providers/aws/alarm.rb +5 -5
- data/modules/mu/providers/aws/bucket.rb +284 -50
- data/modules/mu/providers/aws/cache_cluster.rb +26 -26
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/providers/aws/collection.rb +16 -16
- data/modules/mu/providers/aws/container_cluster.rb +84 -64
- data/modules/mu/providers/aws/database.rb +59 -55
- data/modules/mu/providers/aws/dnszone.rb +29 -12
- data/modules/mu/providers/aws/endpoint.rb +535 -50
- data/modules/mu/providers/aws/firewall_rule.rb +32 -26
- data/modules/mu/providers/aws/folder.rb +1 -1
- data/modules/mu/providers/aws/function.rb +300 -134
- data/modules/mu/providers/aws/group.rb +16 -14
- data/modules/mu/providers/aws/habitat.rb +4 -4
- data/modules/mu/providers/aws/job.rb +469 -0
- data/modules/mu/providers/aws/loadbalancer.rb +67 -45
- data/modules/mu/providers/aws/log.rb +17 -17
- data/modules/mu/providers/aws/msg_queue.rb +22 -13
- data/modules/mu/providers/aws/nosqldb.rb +99 -8
- data/modules/mu/providers/aws/notifier.rb +137 -65
- data/modules/mu/providers/aws/role.rb +119 -83
- data/modules/mu/providers/aws/search_domain.rb +166 -30
- data/modules/mu/providers/aws/server.rb +209 -118
- data/modules/mu/providers/aws/server_pool.rb +95 -130
- data/modules/mu/providers/aws/storage_pool.rb +19 -11
- data/modules/mu/providers/aws/user.rb +5 -5
- data/modules/mu/providers/aws/userdata/linux.erb +5 -4
- data/modules/mu/providers/aws/vpc.rb +109 -54
- data/modules/mu/providers/aws/vpc_subnet.rb +43 -39
- data/modules/mu/providers/azure.rb +78 -12
- data/modules/mu/providers/azure/server.rb +20 -4
- data/modules/mu/providers/cloudformation/server.rb +1 -1
- data/modules/mu/providers/google.rb +21 -5
- data/modules/mu/providers/google/bucket.rb +1 -1
- data/modules/mu/providers/google/container_cluster.rb +1 -1
- data/modules/mu/providers/google/database.rb +1 -1
- data/modules/mu/providers/google/firewall_rule.rb +1 -1
- data/modules/mu/providers/google/folder.rb +7 -3
- data/modules/mu/providers/google/function.rb +66 -31
- data/modules/mu/providers/google/group.rb +1 -1
- data/modules/mu/providers/google/habitat.rb +1 -1
- data/modules/mu/providers/google/loadbalancer.rb +1 -1
- data/modules/mu/providers/google/role.rb +6 -3
- data/modules/mu/providers/google/server.rb +1 -1
- data/modules/mu/providers/google/server_pool.rb +1 -1
- data/modules/mu/providers/google/user.rb +1 -1
- data/modules/mu/providers/google/vpc.rb +28 -3
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/aws-servers-with-handrolled-iam.yaml +37 -0
- data/modules/tests/centos6.yaml +4 -0
- data/modules/tests/centos7.yaml +4 -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/k8s.yaml +1 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +5 -5
- data/modules/tests/regrooms/rds.yaml +5 -5
- 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
- metadata +42 -17
@@ -22,9 +22,9 @@ module MU
|
|
22
22
|
# @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
|
23
23
|
def initialize(**args)
|
24
24
|
super
|
25
|
-
if @
|
26
|
-
|
27
|
-
|
25
|
+
describe if @mu_name and !@deploydata
|
26
|
+
@cloud_id ||= @deploydata['domain_name'] if @deploydata
|
27
|
+
|
28
28
|
@mu_name ||= @deploy.getResourceName(@config["name"])
|
29
29
|
end
|
30
30
|
|
@@ -35,7 +35,8 @@ module MU
|
|
35
35
|
params = genParams
|
36
36
|
|
37
37
|
MU.log "Creating ElasticSearch domain #{@config['domain_name']}", details: params
|
38
|
-
|
38
|
+
@cloud_id = @config['domain_name']
|
39
|
+
MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).create_elasticsearch_domain(params).domain_status
|
39
40
|
|
40
41
|
tagDomain
|
41
42
|
|
@@ -44,17 +45,18 @@ module MU
|
|
44
45
|
# Called automatically by {MU::Deploy#createResources}
|
45
46
|
def groom
|
46
47
|
tagDomain
|
47
|
-
@config['domain_name'] ||= @
|
48
|
+
@config['domain_name'] ||= @cloud_id
|
48
49
|
params = genParams(cloud_desc) # get parameters that would change only
|
49
50
|
|
50
51
|
if params.size > 1
|
51
52
|
waitWhileProcessing # wait until the create finishes, if still going
|
52
53
|
|
53
54
|
MU.log "Updating ElasticSearch domain #{@config['domain_name']}", MU::NOTICE, details: params
|
54
|
-
MU::Cloud::AWS.elasticsearch(region: @
|
55
|
+
MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).update_elasticsearch_domain_config(params)
|
55
56
|
end
|
56
57
|
|
57
58
|
waitWhileProcessing # don't return until creation/updating is complete
|
59
|
+
MU.log "Search Domain #{@config['name']}: #{cloud_desc.endpoint}", MU::SUMMARY
|
58
60
|
end
|
59
61
|
|
60
62
|
@cloud_desc_cache = nil
|
@@ -63,31 +65,30 @@ module MU
|
|
63
65
|
# our druthers.
|
64
66
|
def cloud_desc(use_cache: true)
|
65
67
|
return @cloud_desc_cache if @cloud_desc_cache and use_cache
|
66
|
-
@
|
67
|
-
|
68
|
-
|
68
|
+
@cloud_id ||= @config['domain_name']
|
69
|
+
return nil if !@cloud_id
|
70
|
+
MU.retrier([::Aws::ElasticsearchService::Errors::ResourceNotFoundException], wait: 10, max: 12) {
|
71
|
+
@cloud_desc_cache = MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).describe_elasticsearch_domain(
|
72
|
+
domain_name: @cloud_id
|
69
73
|
).domain_status
|
70
|
-
|
71
|
-
|
72
|
-
domain_name: @deploydata['domain_name']
|
73
|
-
).domain_status
|
74
|
-
else
|
75
|
-
raise MuError, "#{@mu_name} can't find its official Elasticsearch domain name!"
|
76
|
-
end
|
74
|
+
}
|
75
|
+
|
77
76
|
@cloud_desc_cache
|
78
77
|
end
|
79
78
|
|
80
79
|
# Canonical Amazon Resource Number for this resource
|
81
80
|
# @return [String]
|
82
81
|
def arn
|
83
|
-
cloud_desc
|
82
|
+
return nil if !cloud_desc
|
83
|
+
cloud_desc.arn.dup
|
84
84
|
end
|
85
85
|
|
86
86
|
# Return the metadata for this SearchDomain rule
|
87
87
|
# @return [Hash]
|
88
88
|
def notify
|
89
|
-
|
90
|
-
|
89
|
+
return nil if !cloud_desc(use_cache: false)
|
90
|
+
deploy_struct = MU.structToHash(cloud_desc, stringify_keys: true)
|
91
|
+
tags = MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).list_tags(arn: arn).tag_list
|
91
92
|
deploy_struct['tags'] = tags.map { |t| { t.key => t.value } }
|
92
93
|
if deploy_struct['endpoint']
|
93
94
|
deploy_struct['kibana'] = deploy_struct['endpoint']+"/_plugin/kibana/"
|
@@ -119,7 +120,7 @@ module MU
|
|
119
120
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
120
121
|
# @param region [String]: The cloud provider region
|
121
122
|
# @return [void]
|
122
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
123
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
123
124
|
MU.log "AWS::SearchDomain.cleanup: need to support flags['known']", MU::DEBUG, details: flags
|
124
125
|
|
125
126
|
list = MU::Cloud::AWS.elasticsearch(region: region, credentials: credentials).list_domain_names
|
@@ -135,7 +136,7 @@ module MU
|
|
135
136
|
deploy_match = false
|
136
137
|
master_match = false
|
137
138
|
tags.tag_list.each { |tag|
|
138
|
-
if tag.key == "MU-ID" and tag.value ==
|
139
|
+
if tag.key == "MU-ID" and tag.value == deploy_id
|
139
140
|
deploy_match = true
|
140
141
|
elsif tag.key == "MU-MASTER-IP" and tag.value == MU.mu_public_ip
|
141
142
|
master_match = true
|
@@ -157,7 +158,7 @@ module MU
|
|
157
158
|
resp = MU::Cloud::AWS.iam(credentials: credentials).list_roles(marker: marker)
|
158
159
|
resp.roles.each{ |role|
|
159
160
|
# XXX Maybe we should have a more generic way to delete IAM profiles and policies. The call itself should be moved from MU::Cloud.resourceClass("AWS", "Server").
|
160
|
-
# MU::Cloud.resourceClass("AWS", "Server").removeIAMProfile(role.role_name) if role.role_name.match(/^#{Regexp.quote(
|
161
|
+
# MU::Cloud.resourceClass("AWS", "Server").removeIAMProfile(role.role_name) if role.role_name.match(/^#{Regexp.quote(deploy_id)}/)
|
161
162
|
}
|
162
163
|
marker = resp.marker
|
163
164
|
end while resp.is_truncated
|
@@ -191,6 +192,96 @@ module MU
|
|
191
192
|
found
|
192
193
|
end
|
193
194
|
|
195
|
+
# Reverse-map our cloud description into a runnable config hash.
|
196
|
+
# We assume that any values we have in +@config+ are placeholders, and
|
197
|
+
# calculate our own accordingly based on what's live in the cloud.
|
198
|
+
def toKitten(**_args)
|
199
|
+
bok = {
|
200
|
+
"cloud" => "AWS",
|
201
|
+
"credentials" => @credentials,
|
202
|
+
"cloud_id" => @cloud_id,
|
203
|
+
"region" => @region
|
204
|
+
}
|
205
|
+
|
206
|
+
if !cloud_desc
|
207
|
+
MU.log "toKitten failed to load a cloud_desc from #{@cloud_id}", MU::ERR, details: @config
|
208
|
+
return nil
|
209
|
+
end
|
210
|
+
|
211
|
+
bok['name'] = cloud_desc.domain_name
|
212
|
+
bok['elasticsearch_version'] = cloud_desc.elasticsearch_version
|
213
|
+
bok['instance_count'] = cloud_desc.elasticsearch_cluster_config.instance_count
|
214
|
+
bok['instance_type'] = cloud_desc.elasticsearch_cluster_config.instance_type
|
215
|
+
bok['zone_aware'] = cloud_desc.elasticsearch_cluster_config.zone_awareness_enabled
|
216
|
+
|
217
|
+
if cloud_desc.elasticsearch_cluster_config.dedicated_master_enabled
|
218
|
+
bok['dedicated_masters'] = cloud_desc.elasticsearch_cluster_config.dedicated_master_count
|
219
|
+
bok['master_instance_type'] = cloud_desc.elasticsearch_cluster_config.dedicated_master_type
|
220
|
+
end
|
221
|
+
|
222
|
+
if cloud_desc.access_policies and !cloud_desc.access_policies.empty?
|
223
|
+
bok['access_policies'] = JSON.parse(cloud_desc.access_policies)
|
224
|
+
end
|
225
|
+
|
226
|
+
if cloud_desc.advanced_options and !cloud_desc.advanced_options.empty?
|
227
|
+
bok['advanced_options'] = cloud_desc.advanced_options
|
228
|
+
end
|
229
|
+
|
230
|
+
bok['ebs_size'] = cloud_desc.ebs_options.volume_size
|
231
|
+
bok['ebs_type'] = cloud_desc.ebs_options.volume_type
|
232
|
+
bok['ebs_iops'] = cloud_desc.ebs_options.iops if cloud_desc.ebs_options.iops
|
233
|
+
|
234
|
+
if cloud_desc.snapshot_options and cloud_desc.snapshot_options.automated_snapshot_start_hour
|
235
|
+
bok['snapshot_hour'] = cloud_desc.snapshot_options.automated_snapshot_start_hour
|
236
|
+
end
|
237
|
+
|
238
|
+
if cloud_desc.cognito_options.user_pool_id and
|
239
|
+
cloud_desc.cognito_options.identity_pool_id
|
240
|
+
bok['user_pool_id'] = cloud_desc.cognito_options.user_pool_id
|
241
|
+
bok['identity_pool_id'] = cloud_desc.cognito_options.identity_pool_id
|
242
|
+
end
|
243
|
+
|
244
|
+
tags = MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).list_tags(arn: cloud_desc.arn).tag_list
|
245
|
+
if tags and !tags.empty?
|
246
|
+
bok['tags'] = MU.structToHash(tags)
|
247
|
+
end
|
248
|
+
|
249
|
+
if cloud_desc.vpc_options
|
250
|
+
bok['vpc'] = MU::Config::Ref.get(
|
251
|
+
id: cloud_desc.vpc_options.vpc_id,
|
252
|
+
cloud: "AWS",
|
253
|
+
credentials: @credentials,
|
254
|
+
type: "vpcs",
|
255
|
+
region: @region,
|
256
|
+
subnets: cloud_desc.vpc_options.subnet_ids.map { |s| { "subnet_id" => s } }
|
257
|
+
)
|
258
|
+
if cloud_desc.vpc_options.security_group_ids and
|
259
|
+
!cloud_desc.vpc_options.security_group_ids.empty?
|
260
|
+
bok['add_firewall_rules'] = cloud_desc.vpc_options.security_group_ids.map { |sg|
|
261
|
+
MU::Config::Ref.get(
|
262
|
+
id: sg,
|
263
|
+
cloud: "AWS",
|
264
|
+
credentials: @credentials,
|
265
|
+
region: @region,
|
266
|
+
type: "firewall_rules",
|
267
|
+
)
|
268
|
+
}
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
if cloud_desc.log_publishing_options
|
273
|
+
# XXX this is primitive... there are multiple other log types now,
|
274
|
+
# and this should be a Ref blob, not a flat string
|
275
|
+
cloud_desc.log_publishing_options.each_pair { |type, whither|
|
276
|
+
if type == "SEARCH_SLOW_LOGS"
|
277
|
+
bok['slow_logs'] = whither.cloud_watch_logs_log_group_arn
|
278
|
+
end
|
279
|
+
}
|
280
|
+
end
|
281
|
+
|
282
|
+
bok
|
283
|
+
end
|
284
|
+
|
194
285
|
# Cloud-specific configuration properties.
|
195
286
|
# @param _config [MU::Config]: The calling MU::Config object
|
196
287
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
@@ -200,7 +291,7 @@ module MU
|
|
200
291
|
versions = begin
|
201
292
|
MU::Cloud::AWS.elasticsearch.list_elasticsearch_versions.elasticsearch_versions
|
202
293
|
rescue MuError
|
203
|
-
["7.1", "6.8", "6.7", "6.5", "6.4", "6.3", "6.2", "6.0", "5.6"]
|
294
|
+
["7.4", "7.1", "6.8", "6.7", "6.5", "6.4", "6.3", "6.2", "6.0", "5.6"]
|
204
295
|
end
|
205
296
|
instance_types = begin
|
206
297
|
MU::Cloud::AWS.elasticsearch.list_elasticsearch_instance_types(
|
@@ -215,6 +306,8 @@ module MU
|
|
215
306
|
).elasticsearch_instance_types
|
216
307
|
end
|
217
308
|
|
309
|
+
polschema = MU::Config::Role.schema["properties"]["policies"]
|
310
|
+
polschema.deep_merge!(MU::Cloud.resourceClass("AWS", "Role").condition_schema)
|
218
311
|
|
219
312
|
schema = {
|
220
313
|
"name" => {
|
@@ -236,9 +329,10 @@ module MU
|
|
236
329
|
"default" => 0,
|
237
330
|
"description" => "Separate, dedicated master node(s), over and above the search instances specified in instance_count."
|
238
331
|
},
|
332
|
+
"policies" => polschema,
|
239
333
|
"access_policies" => {
|
240
334
|
"type" => "object",
|
241
|
-
"description" => "An IAM policy document for access to ElasticSearch. Our parser expects this to be defined inline like the rest of your YAML/JSON Basket of Kittens, not as raw JSON. For guidance on ElasticSearch IAM capabilities, see: https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-ac.html"
|
335
|
+
"description" => "An IAM policy document for access to ElasticSearch (see {policies} for setting complex access policies with runtime dependencies). Our parser expects this to be defined inline like the rest of your YAML/JSON Basket of Kittens, not as raw JSON. For guidance on ElasticSearch IAM capabilities, see: https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-ac.html"
|
242
336
|
},
|
243
337
|
"master_instance_type" => {
|
244
338
|
"type" => "string",
|
@@ -246,7 +340,7 @@ module MU
|
|
246
340
|
},
|
247
341
|
"ebs_type" => {
|
248
342
|
"type" => "string",
|
249
|
-
"default" => "
|
343
|
+
"default" => "gp2",
|
250
344
|
"description" => "Type of EBS storage to use for cluster nodes. If 'none' is specified, EBS storage will not be used, but this is only valid for certain instance types.",
|
251
345
|
"enum" => ["standard", "gp2", "io1", "none"]
|
252
346
|
},
|
@@ -509,9 +603,51 @@ module MU
|
|
509
603
|
params[:snapshot_options][:automated_snapshot_start_hour] = @config['snapshot_hour']
|
510
604
|
end
|
511
605
|
|
512
|
-
if
|
513
|
-
#
|
514
|
-
|
606
|
+
if ext
|
607
|
+
# Despite being called access_policies, this parameter actually
|
608
|
+
# only accepts one policy. So, we'll munge everything we have
|
609
|
+
# together into one policy with multiple Statements.
|
610
|
+
policy = nil
|
611
|
+
# TODO check against ext.access_policy.options
|
612
|
+
|
613
|
+
if @config['access_policies']
|
614
|
+
policy = @config['access_policies']
|
615
|
+
# ensure the "Statement" key is cased in a predictable way
|
616
|
+
statement_key = nil
|
617
|
+
policy.each_pair { |k, v|
|
618
|
+
if k.downcase == "statement" and k != "Statement"
|
619
|
+
statement_key = k
|
620
|
+
break
|
621
|
+
end
|
622
|
+
}
|
623
|
+
if statement_key
|
624
|
+
policy["Statement"] = policy.delete(statement_key)
|
625
|
+
end
|
626
|
+
if !policy["Statement"].is_a?(Array)
|
627
|
+
policy["Statement"] = [policy["Statement"]]
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
if @config['policies']
|
632
|
+
@config['policies'].each { |p|
|
633
|
+
p['targets'].each { |t|
|
634
|
+
if t['path']
|
635
|
+
t['path'].gsub!(/#SELF/, @mu_name.downcase)
|
636
|
+
end
|
637
|
+
}
|
638
|
+
parsed = MU::Cloud.resourceClass("AWS", "Role").genPolicyDocument([p], deploy_obj: @deploy, bucket_style: true).first.values.first
|
639
|
+
|
640
|
+
if policy and policy["Statement"]
|
641
|
+
policy["Statement"].concat(parsed["Statement"])
|
642
|
+
else
|
643
|
+
policy = parsed
|
644
|
+
end
|
645
|
+
}
|
646
|
+
end
|
647
|
+
|
648
|
+
if policy
|
649
|
+
params[:access_policies] = JSON.generate(policy)
|
650
|
+
end
|
515
651
|
end
|
516
652
|
|
517
653
|
if @config['slow_logs']
|
@@ -547,7 +683,7 @@ module MU
|
|
547
683
|
params[:log_publishing_options]["SEARCH_SLOW_LOGS"] = {}
|
548
684
|
params[:log_publishing_options]["SEARCH_SLOW_LOGS"][:enabled] = true
|
549
685
|
params[:log_publishing_options]["SEARCH_SLOW_LOGS"][:cloud_watch_logs_log_group_arn] = arn
|
550
|
-
MU::Cloud.resourceClass("AWS", "Log").allowService("es.amazonaws.com", arn, @
|
686
|
+
MU::Cloud.resourceClass("AWS", "Log").allowService("es.amazonaws.com", arn, @region)
|
551
687
|
end
|
552
688
|
end
|
553
689
|
|
@@ -677,7 +813,7 @@ module MU
|
|
677
813
|
raise MU::MuError, "Can't tag ElasticSearch domain, cloud descriptor came back without an ARN"
|
678
814
|
end
|
679
815
|
|
680
|
-
MU::Cloud::AWS.elasticsearch(region: @
|
816
|
+
MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).add_tags(
|
681
817
|
arn: domain.arn,
|
682
818
|
tag_list: tags
|
683
819
|
)
|
@@ -85,11 +85,11 @@ module MU
|
|
85
85
|
MU::Cloud.fetchUserdata(
|
86
86
|
platform: @config["platform"],
|
87
87
|
cloud: "AWS",
|
88
|
-
credentials: @
|
88
|
+
credentials: @credentials,
|
89
89
|
template_variables: {
|
90
90
|
"deployKey" => Base64.urlsafe_encode64(@deploy.public_key),
|
91
91
|
"deploySSHKey" => @deploy.ssh_public_key,
|
92
|
-
"muID" =>
|
92
|
+
"muID" => @deploy.deploy_id,
|
93
93
|
"muUser" => MU.mu_user,
|
94
94
|
"publicIP" => MU.mu_public_ip,
|
95
95
|
"mommaCatPort" => MU.mommaCatPort,
|
@@ -242,8 +242,8 @@ module MU
|
|
242
242
|
else
|
243
243
|
MU::Cloud::AWS.createStandardTags(
|
244
244
|
instance.instance_id,
|
245
|
-
region: @
|
246
|
-
credentials: @
|
245
|
+
region: @region,
|
246
|
+
credentials: @credentials,
|
247
247
|
optional: @config['optional_tags'],
|
248
248
|
nametag: @mu_name,
|
249
249
|
othertags: @config['tags']
|
@@ -258,7 +258,7 @@ module MU
|
|
258
258
|
parent_thread_id = Thread.current.object_id
|
259
259
|
Thread.new {
|
260
260
|
MU.dupGlobals(parent_thread_id)
|
261
|
-
MU::Cloud::AWS::Server.cleanup(noop: false, ignoremaster: false, region: @
|
261
|
+
MU::Cloud::AWS::Server.cleanup(noop: false, ignoremaster: false, region: @region, credentials: @credentials, flags: { "skipsnapshots" => true } )
|
262
262
|
}
|
263
263
|
end
|
264
264
|
end
|
@@ -307,9 +307,9 @@ module MU
|
|
307
307
|
instance_descriptor[:user_data] = Base64.encode64(@userdata)
|
308
308
|
end
|
309
309
|
|
310
|
-
MU::Cloud::AWS::Server.waitForAMI(@config["image_id"], region: @
|
310
|
+
MU::Cloud::AWS::Server.waitForAMI(@config["image_id"], region: @region, credentials: @credentials)
|
311
311
|
|
312
|
-
instance_descriptor[:block_device_mappings] = MU::Cloud::AWS::Server.configureBlockDevices(image_id: @config["image_id"], storage: @config['storage'], region: @
|
312
|
+
instance_descriptor[:block_device_mappings] = MU::Cloud::AWS::Server.configureBlockDevices(image_id: @config["image_id"], storage: @config['storage'], region: @region, credentials: @credentials)
|
313
313
|
|
314
314
|
instance_descriptor[:monitoring] = {enabled: @config['monitoring']}
|
315
315
|
|
@@ -330,10 +330,26 @@ module MU
|
|
330
330
|
resp.nil? or resp.instances.nil? or instance.nil?
|
331
331
|
}
|
332
332
|
|
333
|
+
bad_subnets = []
|
334
|
+
mysubnet_ids = if mySubnets
|
335
|
+
mySubnets.map { |s| s.cloud_id }
|
336
|
+
end
|
333
337
|
begin
|
334
338
|
MU.retrier([Aws::EC2::Errors::InvalidGroupNotFound, Aws::EC2::Errors::InvalidSubnetIDNotFound, Aws::EC2::Errors::InvalidParameterValue], loop_if: loop_if, loop_msg: "Waiting for run_instances to return #{@mu_name}") {
|
335
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
339
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).run_instances(instance_descriptor)
|
336
340
|
}
|
341
|
+
rescue Aws::EC2::Errors::Unsupported => e
|
342
|
+
bad_subnets << instance_descriptor[:subnet_id]
|
343
|
+
better_subnet = (mysubnet_ids - bad_subnets).sample
|
344
|
+
if e.message !~ /is not supported in your requested Availability Zone/ and
|
345
|
+
(mysubnet_ids.nil? or mysubnet_ids.empty? or
|
346
|
+
mysubnet_ids.size == bad_subnets.size or
|
347
|
+
better_subnet.nil? or better_subnet == "")
|
348
|
+
raise MuError.new e.message, details: mysubnet_ids
|
349
|
+
end
|
350
|
+
instance_descriptor[:subnet_id] = (mysubnet_ids - bad_subnets).sample
|
351
|
+
MU.log "One or more subnets does not support this instance type, attempting with #{instance_descriptor[:subnet_id]} instead", MU::WARN, details: bad_subnets
|
352
|
+
retry
|
337
353
|
rescue Aws::EC2::Errors::InvalidRequest => e
|
338
354
|
MU.log e.message, MU::ERR, details: instance_descriptor
|
339
355
|
raise e
|
@@ -351,12 +367,12 @@ module MU
|
|
351
367
|
if hard
|
352
368
|
groupname = nil
|
353
369
|
if !@config['basis'].nil?
|
354
|
-
resp = MU::Cloud::AWS.autoscale(region: @
|
370
|
+
resp = MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).describe_auto_scaling_instances(
|
355
371
|
instance_ids: [@cloud_id]
|
356
372
|
)
|
357
373
|
groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
|
358
374
|
MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
|
359
|
-
MU::Cloud::AWS.autoscale(region: @
|
375
|
+
MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).suspend_processes(
|
360
376
|
auto_scaling_group_name: groupname,
|
361
377
|
scaling_processes: [
|
362
378
|
"Terminate",
|
@@ -365,22 +381,22 @@ module MU
|
|
365
381
|
end
|
366
382
|
begin
|
367
383
|
MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
|
368
|
-
MU::Cloud::AWS.ec2(region: @
|
384
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).stop_instances(
|
369
385
|
instance_ids: [@cloud_id]
|
370
386
|
)
|
371
|
-
MU::Cloud::AWS.ec2(region: @
|
387
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
|
372
388
|
waiter.before_attempt do
|
373
389
|
MU.log "Waiting for #{@mu_name} to stop for hard reboot"
|
374
390
|
end
|
375
391
|
end
|
376
392
|
MU.log "Starting #{@mu_name} (#{@cloud_id})"
|
377
|
-
MU::Cloud::AWS.ec2(region: @
|
393
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).start_instances(
|
378
394
|
instance_ids: [@cloud_id]
|
379
395
|
)
|
380
396
|
ensure
|
381
397
|
if !groupname.nil?
|
382
398
|
MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
|
383
|
-
MU::Cloud::AWS.autoscale(region: @
|
399
|
+
MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).resume_processes(
|
384
400
|
auto_scaling_group_name: groupname,
|
385
401
|
scaling_processes: [
|
386
402
|
"Terminate",
|
@@ -390,7 +406,7 @@ module MU
|
|
390
406
|
end
|
391
407
|
else
|
392
408
|
MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
|
393
|
-
MU::Cloud::AWS.ec2(region: @
|
409
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).reboot_instances(
|
394
410
|
instance_ids: [@cloud_id]
|
395
411
|
)
|
396
412
|
end
|
@@ -405,7 +421,7 @@ module MU
|
|
405
421
|
return nil if @config.nil? or @deploy.nil?
|
406
422
|
|
407
423
|
nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
|
408
|
-
if !@config["vpc"].nil? and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @
|
424
|
+
if !@config["vpc"].nil? and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @region, credentials: @credentials)
|
409
425
|
if !@nat.nil?
|
410
426
|
if @nat.is_a?(Struct) && @nat.nat_gateway_id && @nat.nat_gateway_id.start_with?("nat-")
|
411
427
|
raise MuError, "Configured to use NAT Gateway, but I have no route to instance. Either use Bastion, or configure VPC peering"
|
@@ -449,6 +465,9 @@ module MU
|
|
449
465
|
raise MuError, "Couldn't find instance #{@mu_name} (#{@cloud_id})" if !cloud_desc
|
450
466
|
return false if !MU::MommaCat.lock(@cloud_id+"-orchestrate", true)
|
451
467
|
return false if !MU::MommaCat.lock(@cloud_id+"-groom", true)
|
468
|
+
|
469
|
+
getIAMProfile
|
470
|
+
|
452
471
|
finish = Proc.new { |status|
|
453
472
|
MU::MommaCat.unlock(@cloud_id+"-orchestrate")
|
454
473
|
MU::MommaCat.unlock(@cloud_id+"-groom")
|
@@ -457,8 +476,8 @@ module MU
|
|
457
476
|
|
458
477
|
MU::Cloud::AWS.createStandardTags(
|
459
478
|
@cloud_id,
|
460
|
-
region: @
|
461
|
-
credentials: @
|
479
|
+
region: @region,
|
480
|
+
credentials: @credentials,
|
462
481
|
optional: @config['optional_tags'],
|
463
482
|
nametag: @mu_name,
|
464
483
|
othertags: @config['tags']
|
@@ -474,7 +493,15 @@ module MU
|
|
474
493
|
}
|
475
494
|
MU.retrier([Aws::EC2::Errors::ServiceError], max: 30, wait: 40, loop_if: loop_if) { |retries, _wait|
|
476
495
|
if cloud_desc and cloud_desc.state.name == "terminated"
|
477
|
-
|
496
|
+
logs = if !@config['basis'].nil?
|
497
|
+
pool = @deploy.findLitterMate(type: "server_pools", name: @config["name"])
|
498
|
+
if pool
|
499
|
+
MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).describe_scaling_activities(auto_scaling_group_name: pool.cloud_id).activities
|
500
|
+
else
|
501
|
+
nil
|
502
|
+
end
|
503
|
+
end
|
504
|
+
raise MuError.new, "#{@cloud_id} appears to have been terminated mid-bootstrap!", details: logs
|
478
505
|
end
|
479
506
|
if retries % 3 == 0
|
480
507
|
MU.log "Waiting for EC2 instance #{@mu_name} (#{@cloud_id}) to be ready...", MU::NOTICE
|
@@ -495,7 +522,7 @@ module MU
|
|
495
522
|
|
496
523
|
if !@config['src_dst_check'] and !@config["vpc"].nil?
|
497
524
|
MU.log "Disabling source_dest_check #{@mu_name} (making it NAT-worthy)"
|
498
|
-
MU::Cloud::AWS.ec2(region: @
|
525
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_instance_attribute(
|
499
526
|
instance_id: @cloud_id,
|
500
527
|
source_dest_check: { value: false }
|
501
528
|
)
|
@@ -503,7 +530,7 @@ module MU
|
|
503
530
|
|
504
531
|
# Set console termination protection. Autoscale nodes won't set this
|
505
532
|
# by default.
|
506
|
-
MU::Cloud::AWS.ec2(region: @
|
533
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_instance_attribute(
|
507
534
|
instance_id: @cloud_id,
|
508
535
|
disable_api_termination: { value: true}
|
509
536
|
)
|
@@ -516,7 +543,6 @@ module MU
|
|
516
543
|
notify
|
517
544
|
end
|
518
545
|
|
519
|
-
getIAMProfile
|
520
546
|
finish.call(false) if !bootstrapGroomer
|
521
547
|
|
522
548
|
# Make sure we got our name written everywhere applicable
|
@@ -574,7 +600,7 @@ module MU
|
|
574
600
|
regions.each { |r|
|
575
601
|
searches.each { |search|
|
576
602
|
search_threads << Thread.new(search) { |params|
|
577
|
-
MU.retrier([
|
603
|
+
MU.retrier([], wait: 5, max: 5, ignoreme: [Aws::EC2::Errors::InvalidInstanceIDNotFound]) {
|
578
604
|
MU::Cloud::AWS.ec2(region: r, credentials: args[:credentials]).describe_instances(params).reservations.each { |resp|
|
579
605
|
next if resp.nil? or resp.instances.nil?
|
580
606
|
resp.instances.each { |i|
|
@@ -604,9 +630,9 @@ module MU
|
|
604
630
|
def toKitten(**_args)
|
605
631
|
bok = {
|
606
632
|
"cloud" => "AWS",
|
607
|
-
"credentials" => @
|
633
|
+
"credentials" => @credentials,
|
608
634
|
"cloud_id" => @cloud_id,
|
609
|
-
"region" => @
|
635
|
+
"region" => @region
|
610
636
|
}
|
611
637
|
|
612
638
|
if !cloud_desc
|
@@ -616,7 +642,7 @@ module MU
|
|
616
642
|
|
617
643
|
asgs = MU::Cloud.resourceClass("AWS", "ServerPool").find(
|
618
644
|
instance_id: @cloud_id,
|
619
|
-
region: @
|
645
|
+
region: @region,
|
620
646
|
credentials: @credentials
|
621
647
|
)
|
622
648
|
if asgs.size > 0
|
@@ -651,7 +677,7 @@ module MU
|
|
651
677
|
|
652
678
|
bok['image_id'] = cloud_desc.image_id
|
653
679
|
|
654
|
-
ami = MU::Cloud::AWS.ec2(region: @
|
680
|
+
ami = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_images(image_ids: [bok['image_id']]).images.first
|
655
681
|
|
656
682
|
if ami.nil? or ami.empty?
|
657
683
|
MU.log "#{@mu_name} source image #{bok['image_id']} no longer exists", MU::WARN
|
@@ -660,7 +686,7 @@ module MU
|
|
660
686
|
|
661
687
|
if cloud_desc.block_device_mappings and !cloud_desc.block_device_mappings.empty?
|
662
688
|
vol_map = {}
|
663
|
-
MU::Cloud::AWS.ec2(region: @
|
689
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(
|
664
690
|
volume_ids: cloud_desc.block_device_mappings.map { |d| d.ebs.volume_id if d.ebs }
|
665
691
|
).volumes.each { |vol|
|
666
692
|
vol_map[vol.volume_id] = vol
|
@@ -696,7 +722,7 @@ module MU
|
|
696
722
|
id: int.vpc_id,
|
697
723
|
cloud: "AWS",
|
698
724
|
credentials: @credentials,
|
699
|
-
region: @
|
725
|
+
region: @region,
|
700
726
|
subnet_id: int.subnet_id,
|
701
727
|
habitat: MU::Config::Ref.get(
|
702
728
|
id: int.owner_id,
|
@@ -725,11 +751,11 @@ module MU
|
|
725
751
|
if int.groups.size > 0
|
726
752
|
|
727
753
|
require 'mu/providers/aws/firewall_rule'
|
728
|
-
ifaces = MU::Cloud.resourceClass("AWS", "FirewallRule").getAssociatedInterfaces(int.groups.map { |sg| sg.group_id }, credentials: @credentials, region: @
|
754
|
+
ifaces = MU::Cloud.resourceClass("AWS", "FirewallRule").getAssociatedInterfaces(int.groups.map { |sg| sg.group_id }, credentials: @credentials, region: @region)
|
729
755
|
done_local_rules = false
|
730
756
|
int.groups.each { |sg|
|
731
757
|
if !done_local_rules and ifaces[sg.group_id].size == 1
|
732
|
-
sg_desc = MU::Cloud.resourceClass("AWS", "FirewallRule").find(cloud_id: sg.group_id, credentials: @credentials, region: @
|
758
|
+
sg_desc = MU::Cloud.resourceClass("AWS", "FirewallRule").find(cloud_id: sg.group_id, credentials: @credentials, region: @region).values.first
|
733
759
|
if sg_desc
|
734
760
|
bok["ingress_rules"] = MU::Cloud.resourceClass("AWS", "FirewallRule").rulesToBoK(sg_desc.ip_permissions)
|
735
761
|
bok["ingress_rules"].concat(MU::Cloud.resourceClass("AWS", "FirewallRule").rulesToBoK(sg_desc.ip_permissions_egress, egress: true))
|
@@ -743,7 +769,7 @@ module MU
|
|
743
769
|
cloud: "AWS",
|
744
770
|
credentials: @credentials,
|
745
771
|
type: "firewall_rules",
|
746
|
-
region: @
|
772
|
+
region: @region
|
747
773
|
)
|
748
774
|
}
|
749
775
|
end
|
@@ -799,7 +825,7 @@ module MU
|
|
799
825
|
if !@config['chef_data'].nil?
|
800
826
|
deploydata.merge!(@config['chef_data'])
|
801
827
|
end
|
802
|
-
deploydata["region"] = @
|
828
|
+
deploydata["region"] = @region if !@region.nil?
|
803
829
|
if !@named
|
804
830
|
MU::MommaCat.nameKitten(self, no_dns: true)
|
805
831
|
@named = true
|
@@ -883,7 +909,7 @@ module MU
|
|
883
909
|
# Canonical Amazon Resource Number for this resource
|
884
910
|
# @return [String]
|
885
911
|
def arn
|
886
|
-
"arn:"+(MU::Cloud::AWS.isGovCloud?(@
|
912
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@region) ? "aws-us-gov" : "aws")+":ec2:"+@region+":"+MU::Cloud::AWS.credToAcct(@credentials)+":instance/"+@cloud_id
|
887
913
|
end
|
888
914
|
|
889
915
|
@cloud_desc_cache = nil
|
@@ -891,11 +917,12 @@ module MU
|
|
891
917
|
# @return [Openstruct]
|
892
918
|
def cloud_desc(use_cache: true)
|
893
919
|
return @cloud_desc_cache if @cloud_desc_cache and use_cache
|
920
|
+
return nil if !@cloud_id
|
894
921
|
max_retries = 5
|
895
922
|
retries = 0
|
896
923
|
if !@cloud_id.nil?
|
897
924
|
begin
|
898
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
925
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_instances(instance_ids: [@cloud_id])
|
899
926
|
if resp and resp.reservations and resp.reservations.first and
|
900
927
|
resp.reservations.first.instances and
|
901
928
|
resp.reservations.first.instances.first
|
@@ -942,7 +969,7 @@ module MU
|
|
942
969
|
# Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
|
943
970
|
# which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
|
944
971
|
# The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
|
945
|
-
if MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @
|
972
|
+
if MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @region, credentials: @credentials) or @deploydata["public_ip_address"].nil?
|
946
973
|
@config['canonical_ip'] = cloud_desc.private_ip_address
|
947
974
|
@deploydata["private_ip_address"] = cloud_desc.private_ip_address
|
948
975
|
return cloud_desc.private_ip_address
|
@@ -1169,7 +1196,7 @@ module MU
|
|
1169
1196
|
retries = 0
|
1170
1197
|
MU.log "Waiting for Windows instance password to be set by Amazon and flagged as available from the API. Note- if you're using a source AMI that already has its password set, this may fail. You'll want to set use_cloud_provider_windows_password to false if this is the case.", MU::NOTICE
|
1171
1198
|
begin
|
1172
|
-
MU::Cloud::AWS.ec2(region: @
|
1199
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).wait_until(:password_data_available, instance_id: @cloud_id) do |waiter|
|
1173
1200
|
waiter.max_attempts = 60
|
1174
1201
|
waiter.before_attempt do |attempts|
|
1175
1202
|
MU.log "Waiting for Windows password data to be available for node #{@mu_name}", MU::NOTICE if attempts % 5 == 0
|
@@ -1181,15 +1208,15 @@ module MU
|
|
1181
1208
|
rescue Aws::Waiters::Errors::TooManyAttemptsError => e
|
1182
1209
|
if retries < 2
|
1183
1210
|
retries = retries + 1
|
1184
|
-
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@
|
1211
|
+
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@region} never got a good response, retrying (#{retries}/2)", MU::WARN, details: e.inspect
|
1185
1212
|
retry
|
1186
1213
|
else
|
1187
|
-
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@
|
1214
|
+
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@region} never returned- this image may not be configured to have its password set by AWS.", MU::ERR
|
1188
1215
|
return nil
|
1189
1216
|
end
|
1190
1217
|
end
|
1191
1218
|
|
1192
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
1219
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).get_password_data(instance_id: @cloud_id)
|
1193
1220
|
encrypted_password = resp.password_data
|
1194
1221
|
|
1195
1222
|
# Note: This is already implemented in the decrypt_windows_password API call
|
@@ -1208,7 +1235,7 @@ module MU
|
|
1208
1235
|
# instead of VPC.
|
1209
1236
|
# @param ip [String]: Request a specific IP address.
|
1210
1237
|
# @param region [String]: The cloud provider region
|
1211
|
-
def self.findFreeElasticIp(classic: false, ip: nil, region: MU.curRegion)
|
1238
|
+
def self.findFreeElasticIp(classic: false, ip: nil, region: MU.curRegion, credentials: nil)
|
1212
1239
|
filters = Array.new
|
1213
1240
|
if !classic
|
1214
1241
|
filters << {name: "domain", values: ["vpc"]}
|
@@ -1218,25 +1245,22 @@ module MU
|
|
1218
1245
|
filters << {name: "public-ip", values: [ip]} if ip != nil
|
1219
1246
|
|
1220
1247
|
if filters.size > 0
|
1221
|
-
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(filters: filters)
|
1248
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_addresses(filters: filters)
|
1222
1249
|
else
|
1223
|
-
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses
|
1250
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_addresses
|
1224
1251
|
end
|
1225
1252
|
resp.addresses.each { |address|
|
1226
|
-
return address if (address.network_interface_id.nil?
|
1253
|
+
return address if (address.network_interface_id.nil? or address.network_interface_id.empty?) or !@eips_used.include?(address.public_ip)
|
1227
1254
|
}
|
1228
|
-
if ip
|
1229
|
-
|
1230
|
-
|
1231
|
-
else
|
1232
|
-
raise MuError, "Requested EIP #{ip}, but no such IP exists or is available in EC2 Classic"
|
1233
|
-
end
|
1255
|
+
if !ip.nil?
|
1256
|
+
mode = classic ? "EC2 Classic" : "VPC"
|
1257
|
+
raise MuError.new "Requested EIP #{ip}, but no such IP exists or is available in #{mode} mode#{credentials ? " with credentials #{credentials}" : ""}", details: { "describe_address filters" => filters, "describe_address response" => resp }
|
1234
1258
|
end
|
1235
1259
|
if !classic
|
1236
|
-
resp = MU::Cloud::AWS.ec2(region: region).allocate_address(domain: "vpc")
|
1260
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).allocate_address(domain: "vpc")
|
1237
1261
|
new_ip = resp.public_ip
|
1238
1262
|
else
|
1239
|
-
new_ip = MU::Cloud::AWS.ec2(region: region).allocate_address().public_ip
|
1263
|
+
new_ip = MU::Cloud::AWS.ec2(region: region, credentials: credentials).allocate_address().public_ip
|
1240
1264
|
end
|
1241
1265
|
filters = [{name: "public-ip", values: [new_ip]}]
|
1242
1266
|
if resp.domain
|
@@ -1252,8 +1276,8 @@ module MU
|
|
1252
1276
|
begin
|
1253
1277
|
begin
|
1254
1278
|
sleep 5
|
1255
|
-
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(
|
1256
|
-
|
1279
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_addresses(
|
1280
|
+
filters: filters
|
1257
1281
|
)
|
1258
1282
|
addr = resp.addresses.first
|
1259
1283
|
end while resp.addresses.size < 1 or addr.public_ip.nil?
|
@@ -1274,19 +1298,19 @@ module MU
|
|
1274
1298
|
def addVolume(dev, size, type: "gp2", delete_on_termination: false)
|
1275
1299
|
|
1276
1300
|
if setDeleteOntermination(dev, delete_on_termination)
|
1277
|
-
MU.log "A volume #{
|
1301
|
+
MU.log "A volume #{dev} already attached to #{self}, skipping", MU::NOTICE
|
1278
1302
|
return
|
1279
1303
|
end
|
1280
1304
|
|
1281
1305
|
MU.log "Creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1282
|
-
creation = MU::Cloud::AWS.ec2(region: @
|
1306
|
+
creation = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_volume(
|
1283
1307
|
availability_zone: cloud_desc.placement.availability_zone,
|
1284
1308
|
size: size,
|
1285
1309
|
volume_type: type
|
1286
1310
|
)
|
1287
1311
|
|
1288
1312
|
MU.retrier(wait: 3, loop_if: Proc.new {
|
1289
|
-
creation = MU::Cloud::AWS.ec2(region: @
|
1313
|
+
creation = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(volume_ids: [creation.volume_id]).volumes.first
|
1290
1314
|
if !["creating", "available"].include?(creation.state)
|
1291
1315
|
raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1292
1316
|
end
|
@@ -1297,27 +1321,35 @@ module MU
|
|
1297
1321
|
if @deploy
|
1298
1322
|
MU::Cloud::AWS.createStandardTags(
|
1299
1323
|
creation.volume_id,
|
1300
|
-
region: @
|
1301
|
-
credentials: @
|
1324
|
+
region: @region,
|
1325
|
+
credentials: @credentials,
|
1302
1326
|
optional: @config['optional_tags'],
|
1303
1327
|
nametag: @mu_name+"-"+dev.upcase,
|
1304
1328
|
othertags: @config['tags']
|
1305
1329
|
)
|
1306
1330
|
end
|
1307
1331
|
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1332
|
+
MU.log "Attaching #{creation.volume_id} as #{dev} to #{@cloud_id} in #{@region} (credentials #{@credentials})"
|
1333
|
+
attachment = nil
|
1334
|
+
MU.retrier([Aws::EC2::Errors::IncorrectState], wait: 15, max: 4) {
|
1335
|
+
attachment = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).attach_volume(
|
1336
|
+
device: dev,
|
1337
|
+
instance_id: @cloud_id,
|
1338
|
+
volume_id: creation.volume_id
|
1339
|
+
)
|
1340
|
+
}
|
1313
1341
|
|
1314
1342
|
begin
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1343
|
+
att_resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(volume_ids: [attachment.volume_id])
|
1344
|
+
if att_resp and att_resp.volumes and !att_resp.volumes.empty? and
|
1345
|
+
att_resp.volumes.first.attachments and
|
1346
|
+
!att_resp.volumes.first.attachments.empty?
|
1347
|
+
attachment = att_resp.volumes.first.attachments.first
|
1348
|
+
if !attachment.nil? and !["attaching", "attached"].include?(attachment.state)
|
1349
|
+
raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1350
|
+
end
|
1319
1351
|
end
|
1320
|
-
end while attachment.state != "attached"
|
1352
|
+
end while attachment.nil? or attachment.state != "attached"
|
1321
1353
|
|
1322
1354
|
# Set delete_on_termination, which for some reason is an instance
|
1323
1355
|
# attribute and not on the attachment
|
@@ -1333,7 +1365,7 @@ module MU
|
|
1333
1365
|
return true
|
1334
1366
|
end
|
1335
1367
|
begin
|
1336
|
-
MU::Cloud::AWS.ec2(region: @
|
1368
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_instances(
|
1337
1369
|
instance_ids: [@cloud_id]
|
1338
1370
|
).reservations.each { |resp|
|
1339
1371
|
if !resp.nil? and !resp.instances.nil?
|
@@ -1384,7 +1416,7 @@ module MU
|
|
1384
1416
|
}
|
1385
1417
|
end
|
1386
1418
|
end
|
1387
|
-
elastic_ip = findFreeElasticIp(classic: classic, ip: ip)
|
1419
|
+
elastic_ip = findFreeElasticIp(classic: classic, ip: ip, credentials: credentials)
|
1388
1420
|
if !ip.nil? and (elastic_ip.nil? or ip != elastic_ip.public_ip)
|
1389
1421
|
raise MuError, "Requested EIP #{ip}, but this IP does not exist or is not available"
|
1390
1422
|
end
|
@@ -1454,11 +1486,11 @@ module MU
|
|
1454
1486
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
1455
1487
|
# @param region [String]: The cloud provider region
|
1456
1488
|
# @return [void]
|
1457
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
1489
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
1458
1490
|
onlycloud = flags["onlycloud"]
|
1459
1491
|
skipsnapshots = flags["skipsnapshots"]
|
1460
1492
|
tagfilters = [
|
1461
|
-
{name: "tag:MU-ID", values: [
|
1493
|
+
{name: "tag:MU-ID", values: [deploy_id]}
|
1462
1494
|
]
|
1463
1495
|
if !ignoremaster
|
1464
1496
|
tagfilters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
|
@@ -1492,7 +1524,7 @@ module MU
|
|
1492
1524
|
threads << Thread.new(instance) { |myinstance|
|
1493
1525
|
MU.dupGlobals(parent_thread_id)
|
1494
1526
|
Thread.abort_on_exception = true
|
1495
|
-
MU::Cloud::AWS::Server.terminateInstance(id: myinstance.instance_id, noop: noop, onlycloud: onlycloud, region: region, deploy_id:
|
1527
|
+
MU::Cloud::AWS::Server.terminateInstance(id: myinstance.instance_id, noop: noop, onlycloud: onlycloud, region: region, deploy_id: deploy_id, credentials: credentials)
|
1496
1528
|
}
|
1497
1529
|
}
|
1498
1530
|
|
@@ -1503,7 +1535,7 @@ module MU
|
|
1503
1535
|
threads << Thread.new(volume) { |myvolume|
|
1504
1536
|
MU.dupGlobals(parent_thread_id)
|
1505
1537
|
Thread.abort_on_exception = true
|
1506
|
-
delete_volume(myvolume, noop, skipsnapshots, credentials: credentials)
|
1538
|
+
delete_volume(myvolume, noop, skipsnapshots, credentials: credentials, deploy_id: deploy_id)
|
1507
1539
|
}
|
1508
1540
|
}
|
1509
1541
|
|
@@ -1736,6 +1768,7 @@ module MU
|
|
1736
1768
|
return size
|
1737
1769
|
end
|
1738
1770
|
|
1771
|
+
|
1739
1772
|
return size if types.has_key?(size)
|
1740
1773
|
|
1741
1774
|
if size.nil? or !types.has_key?(size)
|
@@ -1781,7 +1814,8 @@ module MU
|
|
1781
1814
|
def self.generateStandardRole(server, configurator)
|
1782
1815
|
role = {
|
1783
1816
|
"name" => server["name"],
|
1784
|
-
"
|
1817
|
+
"bare_policies" => !server['generate_iam_role'],
|
1818
|
+
"strip_path" => server["role_strip_path"],
|
1785
1819
|
"can_assume" => [
|
1786
1820
|
{
|
1787
1821
|
"entity_id" => "ec2.amazonaws.com",
|
@@ -1800,6 +1834,7 @@ module MU
|
|
1800
1834
|
}
|
1801
1835
|
]
|
1802
1836
|
}
|
1837
|
+
role["credentials"] = server["credentials"] if server["credentials"]
|
1803
1838
|
if server['iam_policies']
|
1804
1839
|
role['iam_policies'] = server['iam_policies'].dup
|
1805
1840
|
end
|
@@ -1833,9 +1868,10 @@ module MU
|
|
1833
1868
|
MU.log "Cannot mix iam_policies with generate_iam_role set to false", MU::ERR
|
1834
1869
|
ok = false
|
1835
1870
|
end
|
1836
|
-
else
|
1837
|
-
generateStandardRole(server, configurator)
|
1838
1871
|
end
|
1872
|
+
|
1873
|
+
generateStandardRole(server, configurator)
|
1874
|
+
|
1839
1875
|
if !server['create_image'].nil?
|
1840
1876
|
if server['create_image'].has_key?('copy_to_regions') and
|
1841
1877
|
(server['create_image']['copy_to_regions'].nil? or
|
@@ -1889,7 +1925,7 @@ module MU
|
|
1889
1925
|
# @param volume [OpenStruct]: The cloud provider's description of the volume.
|
1890
1926
|
# @param region [String]: The cloud provider region
|
1891
1927
|
# @return [void]
|
1892
|
-
def self.delete_volume(volume, noop, skipsnapshots, region: MU.curRegion, credentials: nil)
|
1928
|
+
def self.delete_volume(volume, noop, skipsnapshots, region: MU.curRegion, credentials: nil, deploy_id: MU.deploy_id)
|
1893
1929
|
if !volume.nil?
|
1894
1930
|
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_volumes(volume_ids: [volume.volume_id])
|
1895
1931
|
volume = resp.data.volumes.first
|
@@ -1904,9 +1940,9 @@ module MU
|
|
1904
1940
|
if !noop
|
1905
1941
|
if !skipsnapshots
|
1906
1942
|
if !name.nil? and !name.empty?
|
1907
|
-
desc = "#{
|
1943
|
+
desc = "#{deploy_id}-MUfinal (#{name})"
|
1908
1944
|
else
|
1909
|
-
desc = "#{
|
1945
|
+
desc = "#{deploy_id}-MUfinal"
|
1910
1946
|
end
|
1911
1947
|
|
1912
1948
|
begin
|
@@ -2084,7 +2120,7 @@ module MU
|
|
2084
2120
|
def haveElasticIP?
|
2085
2121
|
if !cloud_desc.public_ip_address.nil?
|
2086
2122
|
begin
|
2087
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
2123
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_addresses(public_ips: [cloud_desc.public_ip_address])
|
2088
2124
|
if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
|
2089
2125
|
return true
|
2090
2126
|
end
|
@@ -2099,9 +2135,9 @@ module MU
|
|
2099
2135
|
def configureNetworking
|
2100
2136
|
if !@config['static_ip'].nil?
|
2101
2137
|
if !@config['static_ip']['ip'].nil?
|
2102
|
-
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil?, ip: @config['static_ip']['ip'])
|
2138
|
+
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil?, ip: @config['static_ip']['ip'], credentials: @credentials)
|
2103
2139
|
elsif !haveElasticIP?
|
2104
|
-
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil
|
2140
|
+
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil?, credentials: @credentials)
|
2105
2141
|
end
|
2106
2142
|
end
|
2107
2143
|
|
@@ -2109,7 +2145,7 @@ module MU
|
|
2109
2145
|
subnet = @vpc.getSubnet(cloud_id: cloud_desc.subnet_id)
|
2110
2146
|
|
2111
2147
|
_nat_ssh_key, _nat_ssh_user, nat_ssh_host, _canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
|
2112
|
-
if subnet.private? and !nat_ssh_host and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @
|
2148
|
+
if subnet.private? and !nat_ssh_host and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @region, credentials: @credentials)
|
2113
2149
|
raise MuError, "#{@mu_name} is in a private subnet (#{subnet}), but has no bastion host configured, and I have no other route to it"
|
2114
2150
|
end
|
2115
2151
|
|
@@ -2126,17 +2162,17 @@ module MU
|
|
2126
2162
|
next
|
2127
2163
|
end
|
2128
2164
|
MU.log "Adding network interface on subnet #{s.cloud_id} for #{@mu_name}"
|
2129
|
-
iface = MU::Cloud::AWS.ec2(region: @
|
2165
|
+
iface = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_network_interface(subnet_id: s.cloud_id).network_interface
|
2130
2166
|
MU::Cloud::AWS.createStandardTags(
|
2131
2167
|
iface.network_interface_id,
|
2132
|
-
region: @
|
2133
|
-
credentials: @
|
2168
|
+
region: @region,
|
2169
|
+
credentials: @credentials,
|
2134
2170
|
optional: @config['optional_tags'],
|
2135
2171
|
nametag: @mu_name+"-ETH"+device_index.to_s,
|
2136
2172
|
othertags: @config['tags']
|
2137
2173
|
)
|
2138
2174
|
|
2139
|
-
MU::Cloud::AWS.ec2(region: @
|
2175
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).attach_network_interface(
|
2140
2176
|
network_interface_id: iface.network_interface_id,
|
2141
2177
|
instance_id: cloud_desc.instance_id,
|
2142
2178
|
device_index: device_index
|
@@ -2155,7 +2191,7 @@ module MU
|
|
2155
2191
|
cloud_desc.network_interfaces.each { |int|
|
2156
2192
|
if int.private_ip_address == cloud_desc.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
|
2157
2193
|
MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{cloud_desc.instance_id}"
|
2158
|
-
MU::Cloud::AWS.ec2(region: @
|
2194
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).assign_private_ip_addresses(
|
2159
2195
|
network_interface_id: int.network_interface_id,
|
2160
2196
|
secondary_private_ip_address_count: @config['add_private_ips'],
|
2161
2197
|
allow_reassignment: false
|
@@ -2166,14 +2202,14 @@ module MU
|
|
2166
2202
|
end
|
2167
2203
|
|
2168
2204
|
def tagVolumes
|
2169
|
-
volumes = MU::Cloud::AWS.ec2(region: @
|
2205
|
+
volumes = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(filters: [name: "attachment.instance-id", values: [@cloud_id]])
|
2170
2206
|
volumes.each { |vol|
|
2171
2207
|
vol.volumes.each { |volume|
|
2172
2208
|
volume.attachments.each { |attachment|
|
2173
2209
|
MU::Cloud::AWS.createStandardTags(
|
2174
2210
|
attachment.volume_id,
|
2175
|
-
region: @
|
2176
|
-
credentials: @
|
2211
|
+
region: @region,
|
2212
|
+
credentials: @credentials,
|
2177
2213
|
optional: @config['optional_tags'],
|
2178
2214
|
nametag: ["/dev/sda", "/dev/sda1"].include?(attachment.device) ? "ROOT-"+@mu_name : @mu_name+"-"+attachment.device.upcase,
|
2179
2215
|
othertags: @config['tags']
|
@@ -2194,15 +2230,17 @@ module MU
|
|
2194
2230
|
alarm_obj = MU::MommaCat.findStray(
|
2195
2231
|
"AWS",
|
2196
2232
|
"alarms",
|
2197
|
-
region: @
|
2233
|
+
region: @region,
|
2198
2234
|
deploy_id: @deploy.deploy_id,
|
2199
2235
|
name: alarm['name']
|
2200
2236
|
).first
|
2201
2237
|
alarm["dimensions"] = [{:name => "InstanceId", :value => @cloud_id}]
|
2202
2238
|
|
2203
2239
|
if alarm["enable_notifications"]
|
2204
|
-
|
2205
|
-
|
2240
|
+
# XXX vile, this should be a sibling resource generated by the
|
2241
|
+
# parser
|
2242
|
+
topic_arn = MU::Cloud.resourceClass("AWS", "Notification").createTopic(alarm["notification_group"], region: @region, credentials: @credentials)
|
2243
|
+
MU::Cloud.resourceClass("AWS", "Notification").subscribe(topic_arn, alarm["notification_endpoint"], alarm["notification_type"], region: @region, credentials: @credentials)
|
2206
2244
|
alarm["alarm_actions"] = [topic_arn]
|
2207
2245
|
alarm["ok_actions"] = [topic_arn]
|
2208
2246
|
end
|
@@ -2223,36 +2261,88 @@ module MU
|
|
2223
2261
|
evaluation_periods: alarm["evaluation_periods"],
|
2224
2262
|
threshold: alarm["threshold"],
|
2225
2263
|
comparison_operator: alarm["comparison_operator"],
|
2226
|
-
region: @
|
2227
|
-
credentials: @
|
2264
|
+
region: @region,
|
2265
|
+
credentials: @credentials
|
2228
2266
|
)
|
2229
2267
|
}
|
2230
2268
|
end
|
2231
2269
|
end
|
2232
2270
|
|
2233
|
-
# We have issues sometimes where our dns_records are pointing at the wrong node name and IP address.
|
2234
|
-
|
2235
2271
|
def getIAMProfile
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2272
|
+
self.class.getIAMProfile(
|
2273
|
+
@config['name'],
|
2274
|
+
@deploy,
|
2275
|
+
generated: @config['generate_iam_role'],
|
2276
|
+
role_name: @config['iam_role'],
|
2277
|
+
region: @region,
|
2278
|
+
credentials: @credentials,
|
2279
|
+
want_arn: true
|
2280
|
+
)
|
2281
|
+
end
|
2282
|
+
|
2283
|
+
# XXX move to public section
|
2284
|
+
def self.getIAMProfile(myname, deploy, generated: true, role_name: nil, region: nil, credentials: nil, want_arn: false)
|
2285
|
+
|
2286
|
+
arn = if generated
|
2287
|
+
role = deploy.findLitterMate(name: myname, type: "roles", debug: true)
|
2288
|
+
if !role
|
2289
|
+
raise MuError, "Failed to find a role matching #{myname}"
|
2290
|
+
end
|
2291
|
+
s3_objs = ["#{deploy.deploy_id}-secret", "#{role.mu_name}.pfx", "#{role.mu_name}.crt", "#{role.mu_name}.key", "#{role.mu_name}-winrm.crt", "#{role.mu_name}-winrm.key"].map { |file|
|
2292
|
+
'arn:'+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+':s3:::'+MU::Cloud::AWS.adminBucketName(credentials)+'/'+file
|
2240
2293
|
}
|
2241
|
-
MU.log "Adding S3 read permissions to #{
|
2294
|
+
MU.log "Adding S3 read permissions to #{myname}'s IAM profile", MU::NOTICE, details: s3_objs
|
2242
2295
|
role.cloudobj.injectPolicyTargets("MuSecrets", s3_objs)
|
2243
2296
|
|
2244
|
-
|
2297
|
+
role_name = role.mu_name
|
2245
2298
|
role.cloudobj.createInstanceProfile
|
2246
2299
|
|
2247
|
-
elsif
|
2248
|
-
raise MuError, "#{
|
2300
|
+
elsif role_name.nil?
|
2301
|
+
raise MuError, "#{myname} has generate_iam_role set to false, but no iam_role assigned."
|
2302
|
+
else
|
2303
|
+
begin
|
2304
|
+
ext_prof = MU::Cloud::AWS.iam(credentials: credentials).get_instance_profile(instance_profile_name: role_name)
|
2305
|
+
role_name = ext_prof.instance_profile.instance_profile_name
|
2306
|
+
ext_prof.instance_profile.arn
|
2307
|
+
rescue Aws::IAM::Errors::NoSuchEntity
|
2308
|
+
role = MU::MommaCat.findStray("AWS", "role", cloud_id: role_name, dummy_ok: true, credentials: credentials).first
|
2309
|
+
if !role
|
2310
|
+
raise MuError, "#{myname} specified iam_role '#{role_name}', but I can't find a role with that name to use when creating an instance profile"
|
2311
|
+
end
|
2312
|
+
role.cloudobj.createInstanceProfile
|
2313
|
+
end
|
2249
2314
|
end
|
2250
2315
|
|
2251
|
-
|
2252
|
-
|
2316
|
+
role_or_policy = deploy.findLitterMate(name: myname, type: "roles")
|
2317
|
+
|
2318
|
+
# Make sure our permissions to read our identity secrets are set
|
2319
|
+
s3_objs = [
|
2320
|
+
"#{deploy.deploy_id}-secret",
|
2321
|
+
"#{role_or_policy.mu_name}.pfx",
|
2322
|
+
"#{role_or_policy.mu_name}.crt",
|
2323
|
+
"#{role_or_policy.mu_name}.key",
|
2324
|
+
"#{role_or_policy.mu_name}-winrm.crt",
|
2325
|
+
"#{role_or_policy.mu_name}-winrm.key"].map { |file|
|
2326
|
+
'arn:'+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+':s3:::'+MU::Cloud::AWS.adminBucketName(credentials)+'/'+file
|
2327
|
+
}
|
2328
|
+
if generated
|
2329
|
+
role_or_policy.injectPolicyTargets("MuSecrets", s3_objs)
|
2330
|
+
elsif role_name
|
2331
|
+
realrole = MU::MommaCat.findStray("AWS", "role", cloud_id: role_name, dummy_ok: true, credentials: credentials).first
|
2332
|
+
if !role_or_policy
|
2333
|
+
raise MuError, "I should have a bare policy littermate named #{name} but I can't find it"
|
2334
|
+
end
|
2335
|
+
if realrole
|
2336
|
+
role_or_policy.bindTo("role", realrole.cloud_id)
|
2337
|
+
realrole.injectPolicyTargets(role_or_policy.mu_name+"-MUSECRETS", s3_objs)
|
2338
|
+
end
|
2339
|
+
end
|
2340
|
+
|
2341
|
+
if !role_name.nil?
|
2342
|
+
if arn and want_arn
|
2253
2343
|
return {arn: arn}
|
2254
2344
|
else
|
2255
|
-
return {name:
|
2345
|
+
return {name: role_name}
|
2256
2346
|
end
|
2257
2347
|
end
|
2258
2348
|
|
@@ -2269,8 +2359,8 @@ module MU
|
|
2269
2359
|
if vol[:device_name] == device
|
2270
2360
|
if vol[:ebs][:delete_on_termination] != delete_on_termination
|
2271
2361
|
vol[:ebs][:delete_on_termination] = delete_on_termination
|
2272
|
-
MU.log "Setting delete_on_termination flag to #{delete_on_termination.to_s} on #{@mu_name}'s #{
|
2273
|
-
MU::Cloud::AWS.ec2(region: @
|
2362
|
+
MU.log "Setting delete_on_termination flag to #{delete_on_termination.to_s} on #{@mu_name}'s #{device}"
|
2363
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_instance_attribute(
|
2274
2364
|
instance_id: @cloud_id,
|
2275
2365
|
block_device_mappings: mappings
|
2276
2366
|
)
|
@@ -2314,16 +2404,17 @@ module MU
|
|
2314
2404
|
exclude_storage: img_cfg['image_exclude_storage'],
|
2315
2405
|
copy_to_regions: img_cfg['copy_to_regions'],
|
2316
2406
|
make_public: img_cfg['public'],
|
2317
|
-
region: @
|
2407
|
+
region: @region,
|
2318
2408
|
tags: @config['tags'],
|
2319
|
-
credentials: @
|
2409
|
+
credentials: @credentials
|
2320
2410
|
)
|
2411
|
+
|
2321
2412
|
@deploy.notify("images", @config['name'], ami_ids)
|
2322
2413
|
@config['image_created'] = true
|
2323
2414
|
if img_cfg['image_then_destroy']
|
2324
|
-
MU::Cloud::AWS::Server.waitForAMI(ami_ids[@
|
2325
|
-
MU.log "AMI #{ami_ids[@
|
2326
|
-
MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @
|
2415
|
+
MU::Cloud::AWS::Server.waitForAMI(ami_ids[@region], region: @region, credentials: @credentials)
|
2416
|
+
MU.log "AMI #{ami_ids[@region]} ready, removing source node #{@mu_name}"
|
2417
|
+
MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @region, deploy_id: @deploy.deploy_id, mu_name: @mu_name, credentials: @credentials)
|
2327
2418
|
destroy
|
2328
2419
|
end
|
2329
2420
|
end
|