cloud-mu 3.1.3 → 3.3.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 +15 -3
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -0
- data/ansible/roles/mu-windows/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +36 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/bin/mu-adopt +21 -13
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +52 -0
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-load-config.rb +4 -4
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +147 -37
- data/cloud-mu.gemspec +22 -20
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/libraries/helper.rb +3 -2
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +18 -13
- data/extras/image-generators/AWS/win2k16.yaml +18 -13
- data/extras/image-generators/AWS/win2k19.yaml +21 -0
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +6 -16
- data/modules/mu.rb +158 -111
- data/modules/mu/adoption.rb +404 -71
- data/modules/mu/cleanup.rb +221 -306
- data/modules/mu/cloud.rb +129 -1633
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +44 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +926 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +169 -0
- data/modules/mu/config.rb +171 -1767
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +32 -3
- data/modules/mu/config/cache_cluster.rb +2 -2
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/collection.rb +4 -4
- data/modules/mu/config/container_cluster.rb +9 -4
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +10 -9
- data/modules/mu/config/doc_helpers.rb +516 -0
- data/modules/mu/config/endpoint.rb +5 -4
- data/modules/mu/config/firewall_rule.rb +103 -4
- data/modules/mu/config/folder.rb +4 -4
- data/modules/mu/config/function.rb +19 -10
- data/modules/mu/config/group.rb +4 -4
- data/modules/mu/config/habitat.rb +4 -4
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +60 -14
- data/modules/mu/config/log.rb +4 -4
- data/modules/mu/config/msg_queue.rb +4 -4
- data/modules/mu/config/nosqldb.rb +4 -4
- data/modules/mu/config/notifier.rb +10 -21
- data/modules/mu/config/ref.rb +411 -0
- data/modules/mu/config/role.rb +4 -4
- data/modules/mu/config/schema_helpers.rb +509 -0
- data/modules/mu/config/search_domain.rb +4 -4
- data/modules/mu/config/server.rb +98 -71
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/config/server_pool.rb +5 -9
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +200 -0
- data/modules/mu/config/user.rb +4 -4
- data/modules/mu/config/vpc.rb +71 -27
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +91 -68
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +3 -2
- data/modules/mu/deploy.rb +43 -26
- data/modules/mu/groomer.rb +17 -2
- data/modules/mu/groomers/ansible.rb +188 -41
- data/modules/mu/groomers/chef.rb +116 -55
- data/modules/mu/logger.rb +127 -148
- data/modules/mu/master.rb +410 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -3
- data/modules/mu/mommacat.rb +218 -2612
- data/modules/mu/mommacat/daemon.rb +403 -0
- data/modules/mu/mommacat/naming.rb +473 -0
- data/modules/mu/mommacat/search.rb +495 -0
- data/modules/mu/mommacat/storage.rb +722 -0
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +380 -122
- data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
- data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
- data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
- data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
- data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
- data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
- data/modules/mu/providers/aws/job.rb +466 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
- data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
- data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
- data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
- data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
- data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
- data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
- data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
- data/modules/mu/{clouds → providers}/azure.rb +29 -9
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
- data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
- data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
- data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
- data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +68 -30
- data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
- data/modules/mu/{clouds → providers}/google/database.rb +11 -21
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
- data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
- data/modules/mu/{clouds → providers}/google/function.rb +140 -168
- data/modules/mu/{clouds → providers}/google/group.rb +29 -34
- data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
- data/modules/mu/{clouds → providers}/google/role.rb +94 -58
- data/modules/mu/{clouds → providers}/google/server.rb +243 -156
- data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
- data/modules/mu/{clouds → providers}/google/user.rb +95 -31
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/centos6.yaml +15 -0
- data/modules/tests/centos7.yaml +15 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +23 -0
- 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/includes-and-params.yaml +2 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +2 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +3 -5
- data/modules/tests/win2k12.yaml +17 -5
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +240 -154
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/mu/clouds/aws/database.rb +0 -1985
- data/modules/mu/clouds/aws/endpoint.rb +0 -592
|
@@ -89,7 +89,7 @@ Looking elsewhere in `cloud.rb` let's see what all we have to do:
|
|
|
89
89
|
generic_instance_methods = [:create, :notify, :mu_name, :cloud_id, :config]
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Just the basics, for now. Here's what that will look like in the AWS layer, in the file `modules/mu/
|
|
92
|
+
Just the basics, for now. Here's what that will look like in the AWS layer, in the file `modules/mu/providers/aws/function.rb`:
|
|
93
93
|
|
|
94
94
|
```
|
|
95
95
|
module MU
|
|
@@ -33,13 +33,25 @@ module MU
|
|
|
33
33
|
module AdditionalResourceMethods
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Is this a "real" cloud provider, or a stub like CloudFormation?
|
|
37
|
+
def self.virtual?
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# List all AWS projects available to our credentials
|
|
42
|
+
def self.listHabitats(credentials = nil, use_cache: true)
|
|
43
|
+
cfg = credConfig(credentials)
|
|
44
|
+
return [] if !cfg or !cfg['account_number']
|
|
45
|
+
[cfg['account_number']]
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
# A hook that is always called just before any of the instance method of
|
|
37
49
|
# our resource implementations gets invoked, so that we can ensure that
|
|
38
50
|
# repetitive setup tasks (like resolving +:resource_group+ for Azure
|
|
39
51
|
# resources) have always been done.
|
|
40
52
|
# @param cloudobj [MU::Cloud]
|
|
41
|
-
# @param
|
|
42
|
-
def self.resourceInitHook(cloudobj,
|
|
53
|
+
# @param _deploy [MU::MommaCat]
|
|
54
|
+
def self.resourceInitHook(cloudobj, _deploy)
|
|
43
55
|
class << self
|
|
44
56
|
attr_reader :cloudformation_data
|
|
45
57
|
end
|
|
@@ -63,7 +75,6 @@ module MU
|
|
|
63
75
|
return nil
|
|
64
76
|
end
|
|
65
77
|
|
|
66
|
-
loaded = false
|
|
67
78
|
cred_obj = nil
|
|
68
79
|
if cred_cfg['access_key'] and cred_cfg['access_secret'] and
|
|
69
80
|
# access key and secret just sitting in mu.yaml
|
|
@@ -137,11 +148,22 @@ module MU
|
|
|
137
148
|
# assume we've got an IAM profile and hope for the best
|
|
138
149
|
ENV.delete('AWS_ACCESS_KEY_ID')
|
|
139
150
|
ENV.delete('AWS_SECRET_ACCESS_KEY')
|
|
140
|
-
|
|
151
|
+
retries = 0
|
|
152
|
+
begin
|
|
153
|
+
cred_obj = Aws::InstanceProfileCredentials.new
|
|
154
|
+
if cred_obj.nil?
|
|
155
|
+
retries += 1
|
|
156
|
+
MU.log "Failed to fetch AWS instance profile credentials, attempt #{retries.to_s}/10", MU::WARN
|
|
157
|
+
sleep 3
|
|
158
|
+
end
|
|
159
|
+
end while cred_obj.nil? and retries < 10
|
|
141
160
|
# if name.nil?
|
|
142
161
|
# Aws.config = {region: ENV['EC2_REGION']}
|
|
143
162
|
# end
|
|
144
163
|
end
|
|
164
|
+
if cred_obj.nil?
|
|
165
|
+
MU.log "cred_obj is nil and hosted? says #{hosted?.to_s}", MU::WARN, details: name
|
|
166
|
+
end
|
|
145
167
|
|
|
146
168
|
if name.nil?
|
|
147
169
|
@@creds_loaded["#default"] = cred_obj
|
|
@@ -172,18 +194,34 @@ module MU
|
|
|
172
194
|
end
|
|
173
195
|
end
|
|
174
196
|
|
|
175
|
-
# Tag
|
|
197
|
+
# Tag an EC2 resource
|
|
176
198
|
#
|
|
177
199
|
# @param resource [String]: The cloud provider identifier of the resource to tag
|
|
178
200
|
# @param region [String]: The cloud provider region
|
|
201
|
+
# @param credentials [String]: Credentials to authorize API requests
|
|
202
|
+
# @param optional [Boolean]: Whether to apply our optional generic tags
|
|
203
|
+
# @param nametag [String]: A +Name+ tag to apply
|
|
204
|
+
# @param othertags [Array<Hash>]: Miscellaneous custom tags, in Basket of Kittens style
|
|
179
205
|
# @return [void]
|
|
180
|
-
def self.createStandardTags(resource = nil, region: MU.curRegion, credentials: nil)
|
|
206
|
+
def self.createStandardTags(resource = nil, region: MU.curRegion, credentials: nil, optional: true, nametag: nil, othertags: nil)
|
|
181
207
|
tags = []
|
|
182
208
|
MU::MommaCat.listStandardTags.each_pair { |name, value|
|
|
183
|
-
if !value.nil?
|
|
184
|
-
tags << {key: name, value: value}
|
|
185
|
-
end
|
|
209
|
+
tags << {key: name, value: value} if !value.nil?
|
|
186
210
|
}
|
|
211
|
+
if optional
|
|
212
|
+
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
213
|
+
tags << {key: name, value: value} if !value.nil?
|
|
214
|
+
}
|
|
215
|
+
end
|
|
216
|
+
if nametag
|
|
217
|
+
tags << { key: "Name", value: nametag }
|
|
218
|
+
end
|
|
219
|
+
if othertags
|
|
220
|
+
othertags.each { |tag|
|
|
221
|
+
tags << { key: tag['key'], value: tag['value'] }
|
|
222
|
+
}
|
|
223
|
+
end
|
|
224
|
+
|
|
187
225
|
if MU::Cloud::CloudFormation.emitCloudFormation
|
|
188
226
|
return tags
|
|
189
227
|
end
|
|
@@ -205,6 +243,7 @@ module MU
|
|
|
205
243
|
end
|
|
206
244
|
end
|
|
207
245
|
MU.log "Created standard tags for resource #{resource}", MU::DEBUG, details: caller
|
|
246
|
+
|
|
208
247
|
end
|
|
209
248
|
|
|
210
249
|
@@myVPCObj = nil
|
|
@@ -283,52 +322,13 @@ module MU
|
|
|
283
322
|
)
|
|
284
323
|
end
|
|
285
324
|
|
|
286
|
-
# Tag EC2 resources.
|
|
287
|
-
#
|
|
288
|
-
# @param resources [Array<String>]: The cloud provider identifier of the resource to tag
|
|
289
|
-
# @param key [String]: The name of the tag to create
|
|
290
|
-
# @param value [String]: The value of the tag
|
|
291
|
-
# @param region [String]: The cloud provider region
|
|
292
|
-
# @return [void,<Hash>]
|
|
293
|
-
def self.createTag(key, value, resources = [], region: myRegion, credentials: nil)
|
|
294
|
-
|
|
295
|
-
if !MU::Cloud::CloudFormation.emitCloudFormation
|
|
296
|
-
begin
|
|
297
|
-
MU::Cloud::AWS.ec2(region: region, credentials: credentials).create_tags(
|
|
298
|
-
resources: resources,
|
|
299
|
-
tags: [
|
|
300
|
-
{
|
|
301
|
-
key: key,
|
|
302
|
-
value: value
|
|
303
|
-
}
|
|
304
|
-
]
|
|
305
|
-
)
|
|
306
|
-
rescue Aws::EC2::Errors::ServiceError => e
|
|
307
|
-
MU.log "Got #{e.inspect} tagging #{resources.size.to_s} resources with #{key}=#{value}", MU::WARN, details: resources if attempts > 1
|
|
308
|
-
if attempts < 5
|
|
309
|
-
attempts = attempts + 1
|
|
310
|
-
sleep 15
|
|
311
|
-
retry
|
|
312
|
-
else
|
|
313
|
-
raise e
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
MU.log "Created tag #{key} with value #{value}", MU::DEBUG, details: resources
|
|
317
|
-
else
|
|
318
|
-
return {
|
|
319
|
-
"Key" => key,
|
|
320
|
-
"Value" => value
|
|
321
|
-
}
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
|
|
325
325
|
@@azs = {}
|
|
326
326
|
# List the Availability Zones associated with a given Amazon Web Services
|
|
327
327
|
# region. If no region is given, search the one in which this MU master
|
|
328
328
|
# server resides.
|
|
329
329
|
# @param region [String]: The region to search.
|
|
330
330
|
# @return [Array<String>]: The Availability Zones in this region.
|
|
331
|
-
def self.listAZs(region: MU.curRegion,
|
|
331
|
+
def self.listAZs(region: MU.curRegion, credentials: nil)
|
|
332
332
|
cfg = credConfig(credentials)
|
|
333
333
|
return [] if !cfg
|
|
334
334
|
if !region.nil? and @@azs[region]
|
|
@@ -356,6 +356,27 @@ module MU
|
|
|
356
356
|
# etc)
|
|
357
357
|
# @param deploy_id [MU::MommaCat]
|
|
358
358
|
def self.cleanDeploy(deploy_id, credentials: nil, noop: false)
|
|
359
|
+
|
|
360
|
+
if !noop
|
|
361
|
+
MU.log "Deleting s3://#{adminBucketName(credentials)}/#{deploy_id}-secret"
|
|
362
|
+
MU::Cloud::AWS.s3(credentials: credentials).delete_object(
|
|
363
|
+
bucket: adminBucketName(credentials),
|
|
364
|
+
key: "#{deploy_id}-secret"
|
|
365
|
+
)
|
|
366
|
+
listRegions(credentials: credentials).each { |r|
|
|
367
|
+
resp = MU::Cloud::AWS.ec2(region: r, credentials: credentials).describe_key_pairs(
|
|
368
|
+
filters: [{name: "key-name", values: ["deploy-#{MU.deploy_id}"]}]
|
|
369
|
+
)
|
|
370
|
+
resp.data.key_pairs.each { |keypair|
|
|
371
|
+
MU.log "Deleting key pair #{keypair.key_name} from #{r}"
|
|
372
|
+
MU::Cloud::AWS.ec2(region: r, credentials: credentials).delete_key_pair(key_name: keypair.key_name) if !noop
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
end
|
|
377
|
+
if hosted?
|
|
378
|
+
MU::Cloud::AWS.openFirewallForClients
|
|
379
|
+
end
|
|
359
380
|
end
|
|
360
381
|
|
|
361
382
|
# Plant a Mu deploy secret into a storage bucket somewhere for so our kittens can consume it
|
|
@@ -435,7 +456,7 @@ module MU
|
|
|
435
456
|
end
|
|
436
457
|
|
|
437
458
|
begin
|
|
438
|
-
Timeout.timeout(
|
|
459
|
+
Timeout.timeout(4) do
|
|
439
460
|
instance_id = open("http://169.254.169.254/latest/meta-data/instance-id").read
|
|
440
461
|
if !instance_id.nil? and instance_id.size > 0
|
|
441
462
|
@@is_in_aws = true
|
|
@@ -491,7 +512,32 @@ module MU
|
|
|
491
512
|
# @param cloudobj [MU::Cloud::AWS]: The resource from which to extract the habitat id
|
|
492
513
|
# @return [String,nil]
|
|
493
514
|
def self.habitat(cloudobj, nolookup: false, deploy: nil)
|
|
494
|
-
|
|
515
|
+
@@habmap ||= {}
|
|
516
|
+
# XXX whaddabout config['habitat'] HNNNGH
|
|
517
|
+
|
|
518
|
+
if cloudobj.respond_to?(:account_number) and cloudobj.account_number and
|
|
519
|
+
!cloudobj.account_number.empty?
|
|
520
|
+
return cloudobj.account_number
|
|
521
|
+
elsif cloudobj.config and cloudobj.config['account']
|
|
522
|
+
if nolookup
|
|
523
|
+
return cloudobj.config['account']
|
|
524
|
+
end
|
|
525
|
+
if @@habmap[cloudobj.config['account']]
|
|
526
|
+
return @@habmap[cloudobj.config['account']]
|
|
527
|
+
end
|
|
528
|
+
deploy ||= cloudobj.deploy if cloudobj.respond_to?(:deploy)
|
|
529
|
+
|
|
530
|
+
MU.log "Incomplete implementation: MU::Cloud::AWS.habitat", MU::DEBUG, details: deploy
|
|
531
|
+
|
|
532
|
+
# accountobj = accountLookup(cloudobj.config['account'], deploy, raise_on_fail: false)
|
|
533
|
+
|
|
534
|
+
# if accountobj
|
|
535
|
+
# @@habmap[cloudobj.config['account']] = accountobj.cloud_id
|
|
536
|
+
# return accountobj.cloud_id
|
|
537
|
+
# end
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
nil
|
|
495
541
|
end
|
|
496
542
|
|
|
497
543
|
|
|
@@ -506,7 +552,6 @@ module MU
|
|
|
506
552
|
|
|
507
553
|
return creds['account_number'] if creds['account_number']
|
|
508
554
|
|
|
509
|
-
user_list = MU::Cloud::AWS.iam(credentials: name).list_users.users
|
|
510
555
|
acct_num = MU::Cloud::AWS.iam(credentials: name).list_users.users.first.arn.split(/:/)[4]
|
|
511
556
|
acct_num.to_s
|
|
512
557
|
end
|
|
@@ -543,8 +588,8 @@ module MU
|
|
|
543
588
|
if !found
|
|
544
589
|
MU.log "Attempting to create log bucket #{cfg['log_bucket_name']} for credentials #{credentials}", MU::WARN
|
|
545
590
|
begin
|
|
546
|
-
|
|
547
|
-
rescue Aws::S3::Errors::BucketAlreadyExists
|
|
591
|
+
MU::Cloud::AWS.s3(credentials: credentials).create_bucket(bucket: cfg['log_bucket_name'], acl: "private")
|
|
592
|
+
rescue Aws::S3::Errors::BucketAlreadyExists
|
|
548
593
|
raise MuError, "AWS credentials #{credentials} need a log bucket, and the name #{cfg['log_bucket_name']} is unavailable. Use mu-configure to edit credentials '#{credentials}' or 'hostname'"
|
|
549
594
|
end
|
|
550
595
|
end
|
|
@@ -620,9 +665,9 @@ module MU
|
|
|
620
665
|
# Check each credential sets' resident account, then
|
|
621
666
|
$MU_CFG['aws'].each_pair { |acctname, cfg|
|
|
622
667
|
begin
|
|
623
|
-
|
|
668
|
+
MU::Cloud::AWS.iam(credentials: acctname).list_users.users
|
|
624
669
|
# rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
|
|
625
|
-
rescue
|
|
670
|
+
rescue StandardError => e
|
|
626
671
|
MU.log e.inspect, MU::WARN, details: cfg
|
|
627
672
|
next
|
|
628
673
|
end
|
|
@@ -653,7 +698,7 @@ module MU
|
|
|
653
698
|
# begin
|
|
654
699
|
# user_list = MU::Cloud::AWS.iam(region: credConfig['region']).list_users.users
|
|
655
700
|
## rescue ::Aws::IAM::Errors => e # XXX why does this NameError here?
|
|
656
|
-
# rescue
|
|
701
|
+
# rescue StandardError => e
|
|
657
702
|
# MU.log "Got #{e.inspect} while trying to figure out our account number", MU::WARN, details: caller
|
|
658
703
|
# end
|
|
659
704
|
# if user_list.nil? or user_list.size == 0
|
|
@@ -682,7 +727,6 @@ module MU
|
|
|
682
727
|
if @@regions.size == 0
|
|
683
728
|
return [] if credConfig.nil?
|
|
684
729
|
result = MU::Cloud::AWS.ec2(region: myRegion, credentials: credentials).describe_regions.regions
|
|
685
|
-
regions = []
|
|
686
730
|
@@regions_semaphore.synchronize {
|
|
687
731
|
begin
|
|
688
732
|
result.each { |r|
|
|
@@ -761,50 +805,47 @@ module MU
|
|
|
761
805
|
|
|
762
806
|
@@instance_types ||= {}
|
|
763
807
|
@@instance_types[region] ||= {}
|
|
764
|
-
next_token = nil
|
|
765
808
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
type: "TERM_MATCH"
|
|
786
|
-
}
|
|
787
|
-
],
|
|
788
|
-
next_token: next_token
|
|
789
|
-
)
|
|
790
|
-
resp.price_list.each { |pricing|
|
|
791
|
-
data = JSON.parse(pricing)
|
|
792
|
-
type = data["product"]["attributes"]["instanceType"]
|
|
793
|
-
next if @@instance_types[region].has_key?(type)
|
|
794
|
-
@@instance_types[region][type] = {}
|
|
795
|
-
["ecu", "vcpu", "memory", "storage"].each { |a|
|
|
796
|
-
@@instance_types[region][type][a] = data["product"]["attributes"][a]
|
|
809
|
+
# Pricing API isn't widely available, so ask a region we know supports
|
|
810
|
+
# it
|
|
811
|
+
resp = MU::Cloud::AWS.pricing(region: "us-east-1").get_products(
|
|
812
|
+
service_code: "AmazonEC2",
|
|
813
|
+
filters: [
|
|
814
|
+
{
|
|
815
|
+
field: "productFamily",
|
|
816
|
+
value: "Compute Instance",
|
|
817
|
+
type: "TERM_MATCH"
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
field: "tenancy",
|
|
821
|
+
value: "Shared",
|
|
822
|
+
type: "TERM_MATCH"
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
field: "location",
|
|
826
|
+
value: human_region,
|
|
827
|
+
type: "TERM_MATCH"
|
|
797
828
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
829
|
+
]
|
|
830
|
+
)
|
|
831
|
+
resp.price_list.each { |pricing|
|
|
832
|
+
data = JSON.parse(pricing)
|
|
833
|
+
type = data["product"]["attributes"]["instanceType"]
|
|
834
|
+
next if @@instance_types[region].has_key?(type)
|
|
835
|
+
@@instance_types[region][type] = {}
|
|
836
|
+
["ecu", "vcpu", "memory", "storage"].each { |a|
|
|
837
|
+
@@instance_types[region][type][a] = data["product"]["attributes"][a]
|
|
801
838
|
}
|
|
802
|
-
|
|
803
|
-
|
|
839
|
+
@@instance_types[region][type]["memory"].sub!(/ GiB/, "")
|
|
840
|
+
@@instance_types[region][type]["memory"] = @@instance_types[region][type]["memory"].to_f
|
|
841
|
+
@@instance_types[region][type]["vcpu"] = @@instance_types[region][type]["vcpu"].to_f
|
|
842
|
+
}
|
|
804
843
|
|
|
805
844
|
@@instance_types
|
|
806
845
|
end
|
|
807
846
|
|
|
847
|
+
@@certificates = {}
|
|
848
|
+
|
|
808
849
|
# AWS can stash API-available certificates in Amazon Certificate Manager
|
|
809
850
|
# or in IAM. Rather than make people crazy trying to get the syntax
|
|
810
851
|
# correct in our Baskets of Kittens, let's have a helper that tries to do
|
|
@@ -813,21 +854,24 @@ module MU
|
|
|
813
854
|
# @param name [String]: The name of the cert. For IAM certs this can be any IAM name; for ACM, it's usually the domain name. If multiple matches are found, or no matches, an exception is raised.
|
|
814
855
|
# @param id [String]: The ARN of a known certificate. We just validate that it exists. This is ignored if a name parameter is supplied.
|
|
815
856
|
# @return [String]: The ARN of a matching certificate that is known to exist. If it is an ACM certificate, we also know that it is not expired.
|
|
816
|
-
def self.findSSLCertificate(name: nil, id: nil, region: myRegion)
|
|
817
|
-
if name.nil?
|
|
857
|
+
def self.findSSLCertificate(name: nil, id: nil, region: myRegion, credentials: nil, raise_on_missing: true)
|
|
858
|
+
if (name.nil? or name.empty?) and (id.nil? or id.empty?)
|
|
818
859
|
raise MuError, "Can't call findSSLCertificate without specifying either a name or an id"
|
|
819
860
|
end
|
|
861
|
+
if id and @@certificates[id]
|
|
862
|
+
return [id, @@certificates[id]]
|
|
863
|
+
end
|
|
820
864
|
|
|
821
865
|
if !name.nil? and !name.empty?
|
|
822
866
|
matches = []
|
|
823
|
-
acmcerts = MU::Cloud::AWS.acm(region: region).list_certificates(
|
|
867
|
+
acmcerts = MU::Cloud::AWS.acm(region: region, credentials: credentials).list_certificates(
|
|
824
868
|
certificate_statuses: ["ISSUED"]
|
|
825
869
|
)
|
|
826
870
|
acmcerts.certificate_summary_list.each { |cert|
|
|
827
871
|
matches << cert.certificate_arn if cert.domain_name == name
|
|
828
872
|
}
|
|
829
873
|
begin
|
|
830
|
-
iamcert = MU::Cloud::AWS.iam.get_server_certificate(
|
|
874
|
+
iamcert = MU::Cloud::AWS.iam(credentials: credentials).get_server_certificate(
|
|
831
875
|
server_certificate_name: name
|
|
832
876
|
)
|
|
833
877
|
rescue Aws::IAM::Errors::ValidationError, Aws::IAM::Errors::NoSuchEntity
|
|
@@ -837,32 +881,45 @@ module MU
|
|
|
837
881
|
matches << iamcert.server_certificate.server_certificate_metadata.arn
|
|
838
882
|
end
|
|
839
883
|
if matches.size == 1
|
|
840
|
-
|
|
884
|
+
id = matches.first
|
|
841
885
|
elsif matches.size == 0
|
|
842
|
-
|
|
886
|
+
if raise_on_missing
|
|
887
|
+
raise MuError, "No IAM or ACM certificate named #{name} was found in #{region}"
|
|
888
|
+
else
|
|
889
|
+
return nil
|
|
890
|
+
end
|
|
843
891
|
elsif matches.size > 1
|
|
844
892
|
raise MuError, "Multiple certificates named #{name} were found in #{region}. Remove extras or use ssl_certificate_id to supply the exact ARN of the one you want to use."
|
|
845
893
|
end
|
|
846
894
|
end
|
|
847
895
|
|
|
896
|
+
domains = []
|
|
897
|
+
|
|
848
898
|
if id.match(/^arn:aws(?:-us-gov)?:acm/)
|
|
849
|
-
resp = MU::Cloud::AWS.acm(region: region).
|
|
899
|
+
resp = MU::Cloud::AWS.acm(region: region).describe_certificate(
|
|
850
900
|
certificate_arn: id
|
|
851
901
|
)
|
|
852
|
-
|
|
902
|
+
|
|
903
|
+
if resp.nil? or resp.certificate.nil?
|
|
853
904
|
raise MuError, "No such ACM certificate '#{id}'"
|
|
854
905
|
end
|
|
906
|
+
domains << resp.certificate.domain_name
|
|
907
|
+
if resp.certificate.subject_alternative_names
|
|
908
|
+
domains.concat(resp.certificate.subject_alternative_names)
|
|
909
|
+
end
|
|
855
910
|
elsif id.match(/^arn:aws(?:-us-gov)?:iam/)
|
|
856
911
|
resp = MU::Cloud::AWS.iam.list_server_certificates
|
|
857
912
|
if resp.nil?
|
|
858
913
|
raise MuError, "No such IAM certificate '#{id}'"
|
|
859
914
|
end
|
|
860
915
|
resp.server_certificate_metadata_list.each { |cert|
|
|
916
|
+
|
|
861
917
|
if cert.arn == id
|
|
862
918
|
if cert.expiration < Time.now
|
|
863
919
|
MU.log "IAM SSL certificate #{cert.server_certificate_name} (#{id}) is EXPIRED", MU::WARN
|
|
864
920
|
end
|
|
865
|
-
|
|
921
|
+
@@certificates[id] = [cert.server_certificate_name]
|
|
922
|
+
return [id, [cert.server_certificate_name]]
|
|
866
923
|
end
|
|
867
924
|
}
|
|
868
925
|
raise MuError, "No such IAM certificate '#{id}'"
|
|
@@ -870,7 +927,56 @@ module MU
|
|
|
870
927
|
raise MuError, "The format of '#{id}' doesn't look like an ARN for either Amazon Certificate Manager or IAM"
|
|
871
928
|
end
|
|
872
929
|
|
|
873
|
-
id
|
|
930
|
+
@@certificates[id] = domains.uniq
|
|
931
|
+
[id, domains.uniq]
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# Given a domain name and an ACM or IAM certificate identifier, sort out
|
|
935
|
+
# whether the domain name is "covered" by the certificate
|
|
936
|
+
# @param name [String]
|
|
937
|
+
# @param cert_id [String]
|
|
938
|
+
# @return [Boolean]
|
|
939
|
+
def self.nameMatchesCertificate(name, cert_id)
|
|
940
|
+
_id, domains = findSSLCertificate(id: cert_id)
|
|
941
|
+
return false if !domains
|
|
942
|
+
domains.each { |dom|
|
|
943
|
+
if dom == name or
|
|
944
|
+
(dom =~ /^\*/ and name =~ /.*#{Regexp.quote(dom[1..-1])}/)
|
|
945
|
+
return true
|
|
946
|
+
end
|
|
947
|
+
}
|
|
948
|
+
false
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
# Given a {MU::Config::Ref} block for an IAM or ACM SSL certificate,
|
|
952
|
+
# look up and validate the specified certificate. This is intended to be
|
|
953
|
+
# invoked from resource implementations' +validateConfig+ methods.
|
|
954
|
+
# @param certblock [Hash,MU::Config::Ref]:
|
|
955
|
+
# @param region [String]: Default region to use when looking up the certificate, if its configuration block does not specify any
|
|
956
|
+
# @param credentials [String]: Default credentials to use when looking up the certificate, if its configuration block does not specify any
|
|
957
|
+
# @return [Boolean]
|
|
958
|
+
def self.resolveSSLCertificate(certblock, region: nil, credentials: nil)
|
|
959
|
+
return false if !certblock
|
|
960
|
+
ok = true
|
|
961
|
+
|
|
962
|
+
certblock['region'] ||= region if !certblock['id']
|
|
963
|
+
certblock['credentials'] ||= credentials
|
|
964
|
+
cert_arn, cert_domains = MU::Cloud::AWS.findSSLCertificate(
|
|
965
|
+
name: certblock["name"],
|
|
966
|
+
id: certblock["id"],
|
|
967
|
+
region: certblock['region'],
|
|
968
|
+
credentials: certblock['credentials']
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
if cert_arn
|
|
972
|
+
certblock['id'] ||= cert_arn
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
['region', 'credentials'].each { |field|
|
|
976
|
+
certblock.delete(field) if certblock[field].nil?
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
[cert_arn, cert_domains]
|
|
874
980
|
end
|
|
875
981
|
|
|
876
982
|
# Amazon Certificate Manager API
|
|
@@ -990,6 +1096,14 @@ module MU
|
|
|
990
1096
|
@@cloudwatchlogs_api[credentials][region]
|
|
991
1097
|
end
|
|
992
1098
|
|
|
1099
|
+
# Amazon's CloudWatchEvents API
|
|
1100
|
+
def self.cloudwatchevents(region: MU.curRegion, credentials: nil)
|
|
1101
|
+
region ||= myRegion
|
|
1102
|
+
@@cloudwatchevents_api[credentials] ||= {}
|
|
1103
|
+
@@cloudwatchevents_api[credentials][region] ||= MU::Cloud::AWS::AmazonEndpoint.new(api: "CloudWatchEvents", region: region, credentials: credentials)
|
|
1104
|
+
@@cloudwatchevents_api[credentials][region]
|
|
1105
|
+
end
|
|
1106
|
+
|
|
993
1107
|
# Amazon's CloudFront API
|
|
994
1108
|
def self.cloudfront(region: MU.curRegion, credentials: nil)
|
|
995
1109
|
region ||= myRegion
|
|
@@ -1078,6 +1192,14 @@ module MU
|
|
|
1078
1192
|
@@dynamo_api[credentials][region]
|
|
1079
1193
|
end
|
|
1080
1194
|
|
|
1195
|
+
# Amazon's DynamoStream API
|
|
1196
|
+
def self.dynamostream(region: MU.curRegion, credentials: nil)
|
|
1197
|
+
region ||= myRegion
|
|
1198
|
+
@@dynamostream_api[credentials] ||= {}
|
|
1199
|
+
@@dynamostream_api[credentials][region] ||= MU::Cloud::AWS::AmazonEndpoint.new(api: "DynamoDBStreams", region: region, credentials: credentials)
|
|
1200
|
+
@@dynamostream_api[credentials][region]
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1081
1203
|
# Amazon's Pricing API
|
|
1082
1204
|
def self.pricing(region: MU.curRegion, credentials: nil)
|
|
1083
1205
|
region ||= myRegion
|
|
@@ -1126,6 +1248,14 @@ module MU
|
|
|
1126
1248
|
@@kms_api[credentials][region]
|
|
1127
1249
|
end
|
|
1128
1250
|
|
|
1251
|
+
# Amazon's CloudFront API
|
|
1252
|
+
def self.cloudfront(region: MU.curRegion, credentials: nil)
|
|
1253
|
+
region ||= myRegion
|
|
1254
|
+
@@cloudfront_api[credentials] ||= {}
|
|
1255
|
+
@@cloudfront_api[credentials][region] ||= MU::Cloud::AWS::AmazonEndpoint.new(api: "CloudFront", region: region, credentials: credentials)
|
|
1256
|
+
@@cloudfront_api[credentials][region]
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1129
1259
|
# Amazon's Organizations API
|
|
1130
1260
|
def self.orgs(credentials: nil)
|
|
1131
1261
|
@@organizations_api ||= {}
|
|
@@ -1154,12 +1284,60 @@ module MU
|
|
|
1154
1284
|
end
|
|
1155
1285
|
end
|
|
1156
1286
|
|
|
1287
|
+
# Tag a resource. Defaults to applying our MU deployment identifier, if no
|
|
1288
|
+
# arguments other than the resource identifier are given.
|
|
1289
|
+
#
|
|
1290
|
+
# @param resource [String]: The cloud provider identifier of the resource to tag
|
|
1291
|
+
# @param tag_name [String]: The name of the tag to create
|
|
1292
|
+
# @param tag_value [String]: The value of the tag
|
|
1293
|
+
# @param region [String]: The cloud provider region
|
|
1294
|
+
# @return [void]
|
|
1295
|
+
def self.createTag(resource = nil,
|
|
1296
|
+
tag_name="MU-ID",
|
|
1297
|
+
tag_value=MU.deploy_id,
|
|
1298
|
+
region: MU.curRegion,
|
|
1299
|
+
credentials: nil)
|
|
1300
|
+
attempts = 0
|
|
1301
|
+
|
|
1302
|
+
return nil if resource.nil?
|
|
1303
|
+
resource = [resource] if resource.is_a?(String)
|
|
1304
|
+
|
|
1305
|
+
if !MU::Cloud::CloudFormation.emitCloudFormation
|
|
1306
|
+
begin
|
|
1307
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).create_tags(
|
|
1308
|
+
resources: resource,
|
|
1309
|
+
tags: [
|
|
1310
|
+
{
|
|
1311
|
+
key: tag_name,
|
|
1312
|
+
value: tag_value
|
|
1313
|
+
}
|
|
1314
|
+
]
|
|
1315
|
+
)
|
|
1316
|
+
rescue Aws::EC2::Errors::ServiceError => e
|
|
1317
|
+
MU.log "Got #{e.inspect} tagging #{resource} with #{tag_name}=#{tag_value}", MU::WARN if attempts > 1
|
|
1318
|
+
if attempts < 5
|
|
1319
|
+
attempts = attempts + 1
|
|
1320
|
+
sleep 15
|
|
1321
|
+
retry
|
|
1322
|
+
else
|
|
1323
|
+
raise e
|
|
1324
|
+
end
|
|
1325
|
+
end
|
|
1326
|
+
MU.log "Created tag #{tag_name} with value #{tag_value} for resource #{resource}", MU::DEBUG
|
|
1327
|
+
else
|
|
1328
|
+
return {
|
|
1329
|
+
"Key" => tag_name,
|
|
1330
|
+
"Value" => tag_value
|
|
1331
|
+
}
|
|
1332
|
+
end
|
|
1333
|
+
end
|
|
1334
|
+
|
|
1157
1335
|
@syslog_port_semaphore = Mutex.new
|
|
1158
1336
|
# Punch AWS security group holes for client nodes to talk back to us, the
|
|
1159
1337
|
# Mu Master, if we're in AWS.
|
|
1160
1338
|
# @return [void]
|
|
1161
1339
|
def self.openFirewallForClients
|
|
1162
|
-
MU::Cloud.
|
|
1340
|
+
MU::Cloud.resourceClass("AWS", :FirewallRule)
|
|
1163
1341
|
begin
|
|
1164
1342
|
if File.exist?(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
|
1165
1343
|
::Chef::Config.from_file(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
|
@@ -1205,8 +1383,8 @@ module MU
|
|
|
1205
1383
|
)
|
|
1206
1384
|
sg_id = group.group_id
|
|
1207
1385
|
my_sgs << sg_id
|
|
1208
|
-
MU::
|
|
1209
|
-
MU::
|
|
1386
|
+
MU::Cloud::AWS.createTag sg_id, "Name", my_client_sg_name
|
|
1387
|
+
MU::Cloud::AWS.createTag sg_id, "MU-MASTER-IP", MU.mu_public_ip
|
|
1210
1388
|
MU::Cloud::AWS.ec2.modify_instance_attribute(
|
|
1211
1389
|
instance_id: my_instance_id,
|
|
1212
1390
|
groups: my_sgs
|
|
@@ -1237,7 +1415,7 @@ module MU
|
|
|
1237
1415
|
end
|
|
1238
1416
|
|
|
1239
1417
|
allow_ips = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
|
1240
|
-
MU::MommaCat.listAllNodes.
|
|
1418
|
+
MU::MommaCat.listAllNodes.values.each { |data|
|
|
1241
1419
|
next if data.nil? or !data.is_a?(Hash)
|
|
1242
1420
|
["public_ip_address"].each { |key|
|
|
1243
1421
|
if data.has_key?(key) and !data[key].nil? and !data[key].empty?
|
|
@@ -1266,7 +1444,7 @@ module MU
|
|
|
1266
1444
|
}
|
|
1267
1445
|
]
|
|
1268
1446
|
)
|
|
1269
|
-
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
|
1447
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
|
1270
1448
|
MU.log "Permission disappeared from #{sg_id} (port #{port.to_s}) before I could remove it", MU::WARN, details: MU.structToHash(rule.ip_ranges)
|
|
1271
1449
|
end
|
|
1272
1450
|
end
|
|
@@ -1300,8 +1478,6 @@ module MU
|
|
|
1300
1478
|
}
|
|
1301
1479
|
end
|
|
1302
1480
|
|
|
1303
|
-
private
|
|
1304
|
-
|
|
1305
1481
|
# XXX we shouldn't have to do this, but AWS does not provide a way to look
|
|
1306
1482
|
# it up, and the pricing API only returns the human-readable strings.
|
|
1307
1483
|
@@regionLookup = {
|
|
@@ -1337,7 +1513,7 @@ module MU
|
|
|
1337
1513
|
# Create an AWS API client
|
|
1338
1514
|
# @param region [String]: Amazon region so we know what endpoint to use
|
|
1339
1515
|
# @param api [String]: Which API are we wrapping?
|
|
1340
|
-
def initialize(region:
|
|
1516
|
+
def initialize(region: nil, api: "EC2", credentials: nil)
|
|
1341
1517
|
@cred_obj = MU::Cloud::AWS.loadCredentials(credentials)
|
|
1342
1518
|
@credentials = MU::Cloud::AWS.credConfig(credentials, name_only: true)
|
|
1343
1519
|
|
|
@@ -1346,6 +1522,8 @@ module MU
|
|
|
1346
1522
|
end
|
|
1347
1523
|
|
|
1348
1524
|
params = {}
|
|
1525
|
+
region ||= MU::Cloud::AWS.credConfig(credentials)['region']
|
|
1526
|
+
region ||= MU.myRegion
|
|
1349
1527
|
|
|
1350
1528
|
if region
|
|
1351
1529
|
@region = region
|
|
@@ -1362,21 +1540,98 @@ module MU
|
|
|
1362
1540
|
# Catch-all for AWS client methods. Essentially a pass-through with some
|
|
1363
1541
|
# rescues for known silly endpoint behavior.
|
|
1364
1542
|
def method_missing(method_sym, *arguments)
|
|
1543
|
+
# make sure error symbols are loaded for our exception handling later
|
|
1365
1544
|
require "aws-sdk-core"
|
|
1545
|
+
require "aws-sdk-core/rds"
|
|
1546
|
+
require "aws-sdk-core/ec2"
|
|
1547
|
+
require "aws-sdk-core/route53"
|
|
1548
|
+
require "aws-sdk-core/iam"
|
|
1549
|
+
require "aws-sdk-core/efs"
|
|
1550
|
+
require "aws-sdk-core/pricing"
|
|
1551
|
+
require "aws-sdk-core/apigateway"
|
|
1552
|
+
require "aws-sdk-core/ecs"
|
|
1553
|
+
require "aws-sdk-core/eks"
|
|
1554
|
+
require "aws-sdk-core/cloudwatchlogs"
|
|
1555
|
+
require "aws-sdk-core/cloudwatchevents"
|
|
1556
|
+
require "aws-sdk-core/elasticloadbalancing"
|
|
1557
|
+
require "aws-sdk-core/elasticloadbalancingv2"
|
|
1558
|
+
require "aws-sdk-core/autoscaling"
|
|
1559
|
+
require "aws-sdk-core/client_waiters"
|
|
1560
|
+
require "aws-sdk-core/waiters/errors"
|
|
1366
1561
|
|
|
1367
1562
|
retries = 0
|
|
1368
1563
|
begin
|
|
1369
1564
|
MU.log "Calling #{method_sym} in #{@region}", MU::DEBUG, details: arguments
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1565
|
+
|
|
1566
|
+
retval = if !arguments.nil? and arguments.size == 1
|
|
1567
|
+
@api.method(method_sym).call(arguments[0])
|
|
1568
|
+
elsif !arguments.nil? and arguments.size > 0
|
|
1569
|
+
@api.method(method_sym).call(*arguments)
|
|
1570
|
+
else
|
|
1571
|
+
@api.method(method_sym).call
|
|
1572
|
+
end
|
|
1573
|
+
|
|
1574
|
+
if !retval.nil?
|
|
1575
|
+
begin
|
|
1576
|
+
page_markers = {
|
|
1577
|
+
:marker => :marker,
|
|
1578
|
+
:next_token => :next_token,
|
|
1579
|
+
:next_marker => :marker
|
|
1580
|
+
}
|
|
1581
|
+
paginator = nil
|
|
1582
|
+
new_page = nil
|
|
1583
|
+
page_markers.each_key { |m|
|
|
1584
|
+
if !retval.nil? and retval.respond_to?(m)
|
|
1585
|
+
paginator = m
|
|
1586
|
+
new_page = retval.send(m)
|
|
1587
|
+
break
|
|
1588
|
+
end
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
if paginator and new_page and !new_page.empty?
|
|
1592
|
+
resp = retval.respond_to?(:__getobj__) ? retval.__getobj__ : retval
|
|
1593
|
+
concat_to = resp.class.instance_methods(false).reject { |m|
|
|
1594
|
+
m.to_s.match(/=$/) or m == paginator or resp.send(m).nil? or !resp.send(m).is_a?(Array)
|
|
1595
|
+
}
|
|
1596
|
+
if concat_to.size != 1
|
|
1597
|
+
MU.log "Tried to figure out where I might append paginated results for a #{resp.class.name}, but failed", MU::DEBUG, details: concat_to
|
|
1598
|
+
else
|
|
1599
|
+
concat_to = concat_to.first
|
|
1600
|
+
new_args = arguments ? arguments.dup : [{}]
|
|
1601
|
+
begin
|
|
1602
|
+
if new_args.is_a?(Array)
|
|
1603
|
+
new_args << {} if new_args.empty?
|
|
1604
|
+
if new_args.size == 1 and new_args.first.is_a?(Hash)
|
|
1605
|
+
new_args[0][page_markers[paginator]] = new_page
|
|
1606
|
+
else
|
|
1607
|
+
MU.log "I don't know how to insert a #{paginator} into these arguments for #{method_sym}", MU::WARN, details: new_args
|
|
1608
|
+
end
|
|
1609
|
+
elsif new_args.is_a?(Hash)
|
|
1610
|
+
new_args[page_markers[paginator]] = new_page
|
|
1611
|
+
end
|
|
1612
|
+
|
|
1613
|
+
MU.log "Attempting magic pagination for #{method_sym}", MU::DEBUG, details: new_args
|
|
1614
|
+
|
|
1615
|
+
# resp = if !arguments.nil? and arguments.size == 1
|
|
1616
|
+
# @api.method(method_sym).call(new_args[0])
|
|
1617
|
+
# elsif !arguments.nil? and arguments.size > 0
|
|
1618
|
+
resp = @api.method(method_sym).call(*new_args)
|
|
1619
|
+
# end
|
|
1620
|
+
break if resp.nil?
|
|
1621
|
+
resp = resp.__getobj__ if resp.respond_to?(:__getobj__)
|
|
1622
|
+
retval.send(concat_to).concat(resp.send(concat_to))
|
|
1623
|
+
new_page = resp.send(paginator) if !resp.nil?
|
|
1624
|
+
end while !resp.nil? and !new_page.nil? and !new_page.empty?
|
|
1625
|
+
end
|
|
1626
|
+
end
|
|
1627
|
+
rescue StandardError => e
|
|
1628
|
+
MU.log "Made a good-faith effort to auto-paginate API call to #{method_sym} and failed with #{e.message}", MU::DEBUG, details: arguments
|
|
1629
|
+
raise e
|
|
1630
|
+
end
|
|
1377
1631
|
end
|
|
1632
|
+
|
|
1378
1633
|
return retval
|
|
1379
|
-
rescue Aws::EC2::Errors::InternalError, Aws::EC2::Errors::RequestLimitExceeded, Aws::EC2::Errors::Unavailable, Aws::Route53::Errors::Throttling, Aws::ElasticLoadBalancing::Errors::HttpFailureException, Aws::EC2::Errors::Http503Error, Aws::AutoScaling::Errors::Http503Error, Aws::AutoScaling::Errors::InternalFailure, Aws::AutoScaling::Errors::ServiceUnavailable, Aws::Route53::Errors::ServiceUnavailable, Aws::ElasticLoadBalancing::Errors::Throttling, Aws::RDS::Errors::ClientUnavailable, Aws::Waiters::Errors::UnexpectedError, Aws::ElasticLoadBalancing::Errors::ServiceUnavailable, Aws::ElasticLoadBalancingV2::Errors::Throttling, Seahorse::Client::NetworkingError, Aws::IAM::Errors::Throttling, Aws::EFS::Errors::ThrottlingException, Aws::Pricing::Errors::ThrottlingException, Aws::APIGateway::Errors::TooManyRequestsException, Aws::ECS::Errors::ThrottlingException, Net::ReadTimeout, Faraday::TimeoutError, Aws::CloudWatchLogs::Errors::ThrottlingException => e
|
|
1634
|
+
rescue Aws::Lambda::Errors::TooManyRequestsException, Aws::RDS::Errors::Throttling, Aws::EC2::Errors::InternalError, Aws::EC2::Errors::RequestLimitExceeded, Aws::EC2::Errors::Unavailable, Aws::Route53::Errors::Throttling, Aws::ElasticLoadBalancing::Errors::HttpFailureException, Aws::EC2::Errors::Http503Error, Aws::AutoScaling::Errors::Http503Error, Aws::AutoScaling::Errors::InternalFailure, Aws::AutoScaling::Errors::ServiceUnavailable, Aws::Route53::Errors::ServiceUnavailable, Aws::ElasticLoadBalancing::Errors::Throttling, Aws::RDS::Errors::ClientUnavailable, Aws::Waiters::Errors::UnexpectedError, Aws::ElasticLoadBalancing::Errors::ServiceUnavailable, Aws::ElasticLoadBalancingV2::Errors::Throttling, Seahorse::Client::NetworkingError, Aws::IAM::Errors::Throttling, Aws::EFS::Errors::ThrottlingException, Aws::Pricing::Errors::ThrottlingException, Aws::APIGateway::Errors::TooManyRequestsException, Aws::ECS::Errors::ThrottlingException, Net::ReadTimeout, Faraday::TimeoutError, Aws::CloudWatchLogs::Errors::ThrottlingException => e
|
|
1380
1635
|
if e.class.name == "Seahorse::Client::NetworkingError" and e.message.match(/Name or service not known/)
|
|
1381
1636
|
MU.log e.inspect, MU::ERR
|
|
1382
1637
|
raise e
|
|
@@ -1397,7 +1652,7 @@ module MU
|
|
|
1397
1652
|
MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}, waiting #{interval.to_s}s and retrying. Args were: #{arguments}", debuglevel, details: caller
|
|
1398
1653
|
sleep interval
|
|
1399
1654
|
retry
|
|
1400
|
-
rescue
|
|
1655
|
+
rescue StandardError => e
|
|
1401
1656
|
MU.log "Got #{e.inspect} calling EC2's #{method_sym} in #{@region} with credentials #{@credentials}", MU::DEBUG, details: arguments
|
|
1402
1657
|
raise e
|
|
1403
1658
|
end
|
|
@@ -1418,6 +1673,7 @@ module MU
|
|
|
1418
1673
|
@@wafglobal = {}
|
|
1419
1674
|
@@waf = {}
|
|
1420
1675
|
@@cloudwatchlogs_api = {}
|
|
1676
|
+
@@cloudwatchevents_api = {}
|
|
1421
1677
|
@@cloudfront_api = {}
|
|
1422
1678
|
@@elasticache_api = {}
|
|
1423
1679
|
@@sns_api = {}
|
|
@@ -1436,6 +1692,8 @@ module MU
|
|
|
1436
1692
|
@@kms_api ={}
|
|
1437
1693
|
@@organization_api ={}
|
|
1438
1694
|
@@dynamo_api ={}
|
|
1695
|
+
@@dynamostream_api ={}
|
|
1696
|
+
@@cloudfront_api ={}
|
|
1439
1697
|
end
|
|
1440
1698
|
end
|
|
1441
1699
|
end
|