aws-partitions 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bcd64cee1eb0c323f8692ff5a4c7dca11389772b
4
+ data.tar.gz: 0adcedec22ecafcc3d905eef56a8e44db74ab6d3
5
+ SHA512:
6
+ metadata.gz: e5bf87351f61caedae8f502e12e6697fd30983961307e629ba2829990a95e6e58abd16ab4602a6f602ed9f308ece8779f4ea5313fc92c2bce084e98da8ef77cb
7
+ data.tar.gz: ecdb63091ac2d9a8023ab1637d95299a4d418d7d2a2c0131c13166129d1eb89b02ed7d5d7a0773a8f0e04696e35477b592c514d964f651f987e358b8dc6a1764
@@ -0,0 +1,306 @@
1
+ require_relative 'aws-partitions/endpoint_provider'
2
+ require_relative 'aws-partitions/partition'
3
+ require_relative 'aws-partitions/partition_list'
4
+ require_relative 'aws-partitions/region'
5
+ require_relative 'aws-partitions/service'
6
+
7
+ require 'json'
8
+
9
+ module Aws
10
+
11
+ # A {Partition} is a group of AWS {Region} and {Service} objects. You
12
+ # can use a partition to determine what services are available in a region,
13
+ # or what regions a service is available in.
14
+ #
15
+ # ## Partitions
16
+ #
17
+ # **AWS accounts are scoped to a single partition**. You can get a partition
18
+ # by name. Valid partition names include:
19
+ #
20
+ # * `"aws"` - Public AWS partition
21
+ # * `"aws-cn"` - AWS China
22
+ # * `"aws-us-gov"` - AWS GovCloud
23
+ #
24
+ # To get a partition by name:
25
+ #
26
+ # aws = Aws::Partitions.partition('aws')
27
+ #
28
+ # You can also enumerate all partitions:
29
+ #
30
+ # Aws::Partitions.each do |partition|
31
+ # puts partition.name
32
+ # end
33
+ #
34
+ # ## Regions
35
+ #
36
+ # A {Partition} is divided up into one or more regions. For example, the
37
+ # "aws" partition contains, "us-east-1", "us-west-1", etc. You can get
38
+ # a region by name. Calling {Partition#region} will return an instance
39
+ # of {Region}.
40
+ #
41
+ # region = Aws::Partitions.partition('aws').region('us-west-2')
42
+ # region.name
43
+ # #=> "us-west-2"
44
+ #
45
+ # You can also enumerate all regions within a partition:
46
+ #
47
+ # Aws::Partitions.partition('aws').regions.each do |region|
48
+ # puts region.name
49
+ # end
50
+ #
51
+ # Each {Region} object has a name, description and a list of services
52
+ # available to that region:
53
+ #
54
+ # us_west_2 = Aws::Partitions.partition('aws').region('us-west-2')
55
+ #
56
+ # us_west_2.name #=> "us-west-2"
57
+ # us_west_2.description #=> "US West (Oregon)"
58
+ # us_west_2.partition_name "aws"
59
+ # us_west_2.services #=> #<Set: {"APIGateway", "AutoScaling", ... }
60
+ #
61
+ # To know if a service is available within a region, you can call `#include?`
62
+ # on the set of service names:
63
+ #
64
+ # region.services.include?('DynamoDB') #=> true/false
65
+ #
66
+ # The service name should be the service's module name as used by
67
+ # the AWS SDK for Ruby. To find the complete list of supported
68
+ # service names, see {Partition#services}.
69
+ #
70
+ # Its also possible to enumerate every service for every region in
71
+ # every partition.
72
+ #
73
+ # Aws::Partitions.partitions.each do |partition|
74
+ # partition.regions.each do |region|
75
+ # region.services.each do |service_name|
76
+ # puts "#{partition.name} -> #{region.name} -> #{service_name}"
77
+ # end
78
+ # end
79
+ # end
80
+ #
81
+ # ## Services
82
+ #
83
+ # A {Partition} has a list of services available. You can get a
84
+ # single {Service} by name:
85
+ #
86
+ # Aws::Partitions.partition('aws').service('DynamoDB')
87
+ #
88
+ # You can also enumerate all services in a partition:
89
+ #
90
+ # Aws::Partitions.partition('aws').services.each do |service|
91
+ # puts service.name
92
+ # end
93
+ #
94
+ # Each {Service} object has a name, and information about regions
95
+ # that service is available in.
96
+ #
97
+ # service.name #=> "DynamoDB"
98
+ # service.partition_name #=> "aws"
99
+ # service.regions #=> #<Set: {"us-east-1", "us-west-1", ... }
100
+ #
101
+ # Some services have multiple regions, and others have a single partition
102
+ # wide region. For example, {Aws::IAM} has a single region in the "aws"
103
+ # partition. The {Service#regionalized?} method indicates when this is
104
+ # the case.
105
+ #
106
+ # iam = Aws::Partitions.partition('aws').service('IAM')
107
+ #
108
+ # iam.regionalized? #=> false
109
+ # service.partition_region #=> "aws-global"
110
+ #
111
+ # Its also possible to enumerate every region for every service in
112
+ # every partition.
113
+ #
114
+ # Aws::Partitions.partitions.each do |partition|
115
+ # partition.services.each do |service|
116
+ # service.regions.each do |region_name|
117
+ # puts "#{partition.name} -> #{region_name} -> #{service.name}"
118
+ # end
119
+ # end
120
+ # end
121
+ #
122
+ # ## Service Names
123
+ #
124
+ # {Service} names are those used by the the AWS SDK for Ruby. They
125
+ # correspond to the service's module.
126
+ #
127
+ module Partitions
128
+
129
+ class << self
130
+
131
+ include Enumerable
132
+
133
+ # @return [Enumerable<Partition>]
134
+ def each(&block)
135
+ default_partition_list.each(&block)
136
+ end
137
+
138
+ # Return the partition with the given name. A partition describes
139
+ # the services and regions available in that partition.
140
+ #
141
+ # aws = Aws::Partitions.partition('aws')
142
+ #
143
+ # puts "Regions available in the aws partition:\n"
144
+ # aws.regions.each do |region|
145
+ # puts region.name
146
+ # end
147
+ #
148
+ # puts "Services available in the aws partition:\n"
149
+ # aws.services.each do |services|
150
+ # puts services.name
151
+ # end
152
+ #
153
+ # @param [String] name The name of the partition to return.
154
+ # Valid names include "aws", "aws-cn", and "aws-us-gov".
155
+ #
156
+ # @return [Partition]
157
+ #
158
+ # @raise [ArgumentError] Raises an `ArgumentError` if a partition is
159
+ # not found with the given name. The error message contains a list
160
+ # of valid partition names.
161
+ def partition(name)
162
+ default_partition_list.partition(name)
163
+ end
164
+
165
+ # Returns an array with every partitions. A partition describes
166
+ # the services and regions available in that partition.
167
+ #
168
+ # Aws::Partitions.partitions.each do |partition|
169
+ #
170
+ # puts "Regions available in #{partition.name}:\n"
171
+ # partition.regions.each do |region|
172
+ # puts region.name
173
+ # end
174
+ #
175
+ # puts "Services available in #{partition.name}:\n"
176
+ # partition.services.each do |service|
177
+ # puts service.name
178
+ # end
179
+ # end
180
+ #
181
+ # @return [Enumerable<Partition>] Returns an enumerable of all
182
+ # known partitions.
183
+ def partitions
184
+ default_partition_list
185
+ end
186
+
187
+ # @param [Hash] new_partitions
188
+ # @api private For internal use only.
189
+ def add(new_partitions)
190
+ new_partitions['partitions'].each do |partition|
191
+ default_partition_list.add_partition(Partition.build(partition))
192
+ defaults['partitions'] << partition
193
+ end
194
+ end
195
+
196
+ # @api private For internal use only.
197
+ def clear
198
+ default_partition_list.clear
199
+ defaults['partitions'].clear
200
+ end
201
+
202
+ # @return [PartitionList]
203
+ # @api private
204
+ def default_partition_list
205
+ @default_partition_list ||= PartitionList.build(defaults)
206
+ end
207
+
208
+ # @return [Hash]
209
+ # @api private
210
+ def defaults
211
+ @defaults ||= begin
212
+ path = File.expand_path('../../partitions.json', __FILE__)
213
+ JSON.load(File.read(path))
214
+ end
215
+ end
216
+
217
+ # @return [Hash<String,String>] Returns a map of service module names
218
+ # to their id as used in the endpoints.json document.
219
+ # @api private For internal use only.
220
+ def service_ids
221
+ @service_ids ||= begin
222
+ # service ids
223
+ {
224
+ 'ACM' => 'acm',
225
+ 'APIGateway' => 'apigateway',
226
+ 'ApplicationAutoScaling' => 'application-autoscaling',
227
+ 'ApplicationDiscoveryService' => 'discovery',
228
+ 'AutoScaling' => 'autoscaling',
229
+ 'Budgets' => 'budgets',
230
+ 'CloudFormation' => 'cloudformation',
231
+ 'CloudFront' => 'cloudfront',
232
+ 'CloudHSM' => 'cloudhsm',
233
+ 'CloudSearch' => 'cloudsearch',
234
+ 'CloudTrail' => 'cloudtrail',
235
+ 'CloudWatch' => 'monitoring',
236
+ 'CloudWatchEvents' => 'events',
237
+ 'CloudWatchLogs' => 'logs',
238
+ 'CodeCommit' => 'codecommit',
239
+ 'CodeDeploy' => 'codedeploy',
240
+ 'CodePipeline' => 'codepipeline',
241
+ 'CognitoIdentity' => 'cognito-identity',
242
+ 'CognitoIdentityProvider' => 'cognito-idp',
243
+ 'CognitoSync' => 'cognito-sync',
244
+ 'ConfigService' => 'config',
245
+ 'DataPipeline' => 'datapipeline',
246
+ 'DatabaseMigrationService' => 'dms',
247
+ 'DeviceFarm' => 'devicefarm',
248
+ 'DirectConnect' => 'directconnect',
249
+ 'DirectoryService' => 'ds',
250
+ 'DynamoDB' => 'dynamodb',
251
+ 'DynamoDBStreams' => 'streams.dynamodb',
252
+ 'EC2' => 'ec2',
253
+ 'ECR' => 'ecr',
254
+ 'ECS' => 'ecs',
255
+ 'EFS' => 'elasticfilesystem',
256
+ 'EMR' => 'elasticmapreduce',
257
+ 'ElastiCache' => 'elasticache',
258
+ 'ElasticBeanstalk' => 'elasticbeanstalk',
259
+ 'ElasticLoadBalancing' => 'elasticloadbalancing',
260
+ 'ElasticLoadBalancingV2' => 'elasticloadbalancing',
261
+ 'ElasticTranscoder' => 'elastictranscoder',
262
+ 'ElasticsearchService' => 'es',
263
+ 'Firehose' => 'firehose',
264
+ 'GameLift' => 'gamelift',
265
+ 'Glacier' => 'glacier',
266
+ 'IAM' => 'iam',
267
+ 'ImportExport' => 'importexport',
268
+ 'Inspector' => 'inspector',
269
+ 'IoT' => 'iot',
270
+ 'IoTDataPlane' => 'data.iot',
271
+ 'KMS' => 'kms',
272
+ 'Kinesis' => 'kinesis',
273
+ 'KinesisAnalytics' => 'kinesisanalytics',
274
+ 'Lambda' => 'lambda',
275
+ 'LambdaPreview' => 'lambda',
276
+ 'MachineLearning' => 'machinelearning',
277
+ 'MarketplaceCommerceAnalytics' => 'marketplacecommerceanalytics',
278
+ 'MarketplaceMetering' => 'metering.marketplace',
279
+ 'OpsWorks' => 'opsworks',
280
+ 'RDS' => 'rds',
281
+ 'Redshift' => 'redshift',
282
+ 'Route53' => 'route53',
283
+ 'Route53Domains' => 'route53domains',
284
+ 'S3' => 's3',
285
+ 'SES' => 'email',
286
+ 'SMS' => 'sms',
287
+ 'SNS' => 'sns',
288
+ 'SQS' => 'sqs',
289
+ 'SSM' => 'ssm',
290
+ 'STS' => 'sts',
291
+ 'SWF' => 'swf',
292
+ 'ServiceCatalog' => 'servicecatalog',
293
+ 'SimpleDB' => 'sdb',
294
+ 'Snowball' => 'snowball',
295
+ 'StorageGateway' => 'storagegateway',
296
+ 'Support' => 'support',
297
+ 'WAF' => 'waf',
298
+ 'WorkSpaces' => 'workspaces',
299
+ }
300
+ # end service ids
301
+ end
302
+ end
303
+
304
+ end
305
+ end
306
+ end
@@ -0,0 +1,115 @@
1
+ module Aws
2
+ module Partitions
3
+ # @api private
4
+ class EndpointProvider
5
+
6
+ # Intentionally marked private. The format of the endpoint rules
7
+ # is an implementation detail.
8
+ # @api private
9
+ def initialize(rules)
10
+ @rules = rules
11
+ end
12
+
13
+ # @param [String] region
14
+ # @param [String] service The endpoint prefix for the service, e.g. "monitoring" for
15
+ # cloudwatch.
16
+ # @api private Use the static class methods instead.
17
+ def resolve(region, service)
18
+ "https://" + endpoint_for(region, service)
19
+ end
20
+
21
+ # @api private Use the static class methods instead.
22
+ def signing_region(region, service)
23
+ get_partition(region).
24
+ fetch("services", {}).
25
+ fetch(service, {}).
26
+ fetch("endpoints", {}).
27
+ fetch(region, {}).
28
+ fetch("credentialScope", {}).
29
+ fetch("region", region)
30
+ end
31
+
32
+ # @api private Use the static class methods instead.
33
+ def dns_suffix_for(region)
34
+ partition = get_partition(region)
35
+ partition['dnsSuffix']
36
+ end
37
+
38
+ private
39
+
40
+ def endpoint_for(region, service)
41
+ partition = get_partition(region)
42
+ endpoint = default_endpoint(partition, service, region)
43
+ service_cfg = partition.fetch("services", {}).fetch(service, {})
44
+
45
+ # Check for service-level default endpoint.
46
+ endpoint = service_cfg.fetch("defaults", {}).fetch("hostname", endpoint)
47
+
48
+ # Check for global endpoint.
49
+ if service_cfg["isRegionalized"] == false
50
+ region = service_cfg.fetch("partitionEndpoint", region)
51
+ end
52
+
53
+ # Check for service/region level endpoint.
54
+ endpoint = service_cfg.fetch("endpoints", {}).
55
+ fetch(region, {}).fetch("hostname", endpoint)
56
+
57
+ endpoint
58
+ end
59
+
60
+ def default_endpoint(partition, service, region)
61
+ hostname_template = partition["defaults"]["hostname"]
62
+ hostname_template.
63
+ sub('{region}', region).
64
+ sub('{service}', service).
65
+ sub('{dnsSuffix}', partition["dnsSuffix"])
66
+ end
67
+
68
+ def get_partition(region)
69
+ partition_containing_region(region) ||
70
+ partition_matching_region(region) ||
71
+ default_partition
72
+ end
73
+
74
+ def partition_containing_region(region)
75
+ @rules['partitions'].find do |p|
76
+ p['regions'].key?(region)
77
+ end
78
+ end
79
+
80
+ def partition_matching_region(region)
81
+ @rules['partitions'].find do |p|
82
+ region.match(p["regionRegex"]) ||
83
+ p['services'].values.find { |svc| svc['endpoints'].key?(region) }
84
+ end
85
+ end
86
+
87
+ def default_partition
88
+ @rules['partitions'].find { |p| p["partition"] == "aws" } ||
89
+ @rules['partitions'].first
90
+ end
91
+
92
+ class << self
93
+
94
+ def resolve(region, service)
95
+ default_provider.resolve(region, service)
96
+ end
97
+
98
+ def signing_region(region, service)
99
+ default_provider.signing_region(region, service)
100
+ end
101
+
102
+ def dns_suffix_for(region)
103
+ default_provider.dns_suffix_for(region)
104
+ end
105
+
106
+ private
107
+
108
+ def default_provider
109
+ @default_provider ||= EndpointProvider.new(Partitions.defaults)
110
+ end
111
+
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,95 @@
1
+ module Aws
2
+ module Partitions
3
+ class Partition
4
+
5
+ # @option options [required, String] :name
6
+ # @option options [required, Hash<String,Region>] :regions
7
+ # @option options [required, Hash<String,Service>] :services
8
+ # @api private
9
+ def initialize(options = {})
10
+ @name = options[:name]
11
+ @regions = options[:regions]
12
+ @services = options[:services]
13
+ end
14
+
15
+ # @return [String] The partition name, e.g. "aws", "aws-cn", "aws-us-gov".
16
+ attr_reader :name
17
+
18
+ # @param [String] region_name The name of the region, e.g. "us-east-1".
19
+ # @return [Region]
20
+ # @raise [ArgumentError] Raises `ArgumentError` for unknown region name.
21
+ def region(region_name)
22
+ if @regions.key?(region_name)
23
+ @regions[region_name]
24
+ else
25
+ msg = "invalid region name #{region_name.inspect}; valid region "
26
+ msg << "names include %s" % [@regions.keys.join(', ')]
27
+ raise ArgumentError, msg
28
+ end
29
+ end
30
+
31
+ # @return [Array<Region>]
32
+ def regions
33
+ @regions.values
34
+ end
35
+
36
+ # @param [String] service_name The service module name.
37
+ # @return [Service]
38
+ # @raise [ArgumentError] Raises `ArgumentError` for unknown service name.
39
+ def service(service_name)
40
+ if @services.key?(service_name)
41
+ @services[service_name]
42
+ else
43
+ msg = "invalid service name #{service_name.inspect}; valid service "
44
+ msg << "names include %s" % [@services.keys.join(', ')]
45
+ raise ArgumentError, msg
46
+ end
47
+ end
48
+
49
+ # @return [Array<Service>]
50
+ def services
51
+ @services.values
52
+ end
53
+
54
+ class << self
55
+
56
+ # @api private
57
+ def build(partition)
58
+ Partition.new(
59
+ name: partition['partition'],
60
+ regions: build_regions(partition),
61
+ services: build_services(partition),
62
+ )
63
+ end
64
+
65
+ private
66
+
67
+ # @param [Hash] partition
68
+ # @return [Hash<String,Region>]
69
+ def build_regions(partition)
70
+ partition['regions'].inject({}) do |regions, (region_name, region)|
71
+ unless region_name == "#{partition['partition']}-global"
72
+ regions[region_name] = Region.build(region_name, region, partition)
73
+ end
74
+ regions
75
+ end
76
+ end
77
+
78
+ # @param [Hash] partition
79
+ # @return [Hash<String,Service>]
80
+ def build_services(partition)
81
+ Partitions.service_ids.inject({}) do |services, (svc_name, svc_id)|
82
+ if partition['services'].key?(svc_id)
83
+ svc_data = partition['services'][svc_id]
84
+ services[svc_name] = Service.build(svc_name, svc_data, partition)
85
+ else
86
+ services[svc_name] = Service.build(svc_name, {'endpoints' => {}}, partition)
87
+ end
88
+ services
89
+ end
90
+ end
91
+
92
+ end
93
+ end
94
+ end
95
+ end