cloud-mu 3.2.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +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
|