aws-partitions 1.329.0 → 1.887.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.887.0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Partitions
3
5
  # @api private
@@ -35,53 +37,130 @@ module Aws
35
37
  # "monitoring" for cloudwatch.
36
38
  # @param [String] sts_regional_endpoints [STS only] Whether to use
37
39
  # `legacy` (global endpoint for legacy regions) or `regional` mode for
38
- # using regional endpoint for supported regions except 'aws-global'
40
+ # using regional endpoint for supported regions except 'aws-global'
41
+ # @param [Hash] variants Endpoint variants such as 'fips' or 'dualstack'
42
+ # @option variants [Boolean] :dualstack When true, resolve a dualstack
43
+ # endpoint.
44
+ # @option variants [Boolean] :fips When true, resolve a FIPS endpoint.
39
45
  # @api private Use the static class methods instead.
40
- def resolve(region, service, sts_regional_endpoints)
41
- 'https://' + endpoint_for(region, service, sts_regional_endpoints)
46
+ def resolve(region, service, sts_regional_endpoints, variants)
47
+ 'https://' + endpoint_for(region, service, build_is_global_fn(sts_regional_endpoints), variants)
42
48
  end
43
49
 
44
50
  # @api private Use the static class methods instead.
45
- def signing_region(region, service)
46
- get_partition(region)
47
- .fetch('services', {})
48
- .fetch(service, {})
49
- .fetch('endpoints', {})
50
- .fetch(region, {})
51
- .fetch('credentialScope', {})
51
+ def signing_region(region, service, sts_regional_endpoints)
52
+ credential_scope(region, service, build_is_global_fn(sts_regional_endpoints))
52
53
  .fetch('region', region)
53
54
  end
54
55
 
55
56
  # @api private Use the static class methods instead.
56
- def dns_suffix_for(region)
57
- get_partition(region)['dnsSuffix']
57
+ def signing_service(region, service)
58
+ # don't default to the service name
59
+ # signers should prefer the api metadata's signingName
60
+ # if no service is set in the credentialScope
61
+ credential_scope(region, service, build_is_global_fn('regional'))
62
+ .fetch('service', nil)
63
+ end
64
+
65
+ # @param [String] region The region used to fetch the partition.
66
+ # @param [String] service Used only if dualstack is true. Used to find a
67
+ # DNS suffix for a specific service.
68
+ # @param [Hash] variants Endpoint variants such as 'fips' or 'dualstack'
69
+ # @option variants [Boolean] :dualstack When true, resolve a dualstack
70
+ # endpoint.
71
+ # @option variants [Boolean] :fips When true, resolve a FIPS endpoint.
72
+ # @api private Use the static class methods instead.
73
+ def dns_suffix_for(region, service, variants)
74
+ if configured_variants?(variants)
75
+ resolve_variant(region, service, variants)['dnsSuffix']
76
+ else
77
+ get_partition(region)['dnsSuffix']
78
+ end
58
79
  end
59
80
 
60
81
  private
61
82
 
62
- def endpoint_for(region, service, sts_regional_endpoints)
83
+ def configured_variants?(variants)
84
+ variants.values.any?
85
+ end
86
+
87
+ def fetch_variant(cfg, tags)
88
+ variants = cfg.fetch('variants', [])
89
+ variants.find { |v| tags == Set.new(v['tags']) } || {}
90
+ end
91
+
92
+ def resolve_variant(region, service, config_variants)
93
+ tags = Set.new(config_variants.select { |_k,v| v == true }.map { |k,_v| k.to_s })
94
+ is_global_fn = build_is_global_fn # ignore legacy STS config for variants
95
+
96
+ partition_cfg = get_partition(region)
97
+ service_cfg = partition_cfg.fetch('services', {})
98
+ .fetch(service, {})
99
+
100
+ endpoints_cfg = service_cfg.fetch('endpoints', {})
101
+
102
+ if is_global_fn.call(service, region, endpoints_cfg, service_cfg)
103
+ region = service_cfg.fetch('partitionEndpoint', region)
104
+ end
105
+
106
+ region_cfg = endpoints_cfg.fetch(region, {})
107
+ warn_deprecation(service, region) if region_cfg['deprecated']
108
+
109
+ partition_defaults = fetch_variant(partition_cfg.fetch('defaults', {}), tags)
110
+ service_defaults = fetch_variant(service_cfg.fetch('defaults', {}), tags)
111
+ endpoint_cfg = fetch_variant(region_cfg, tags)
112
+
113
+ # merge upwards, preferring values from endpoint > service > partition
114
+ partition_defaults.merge(service_defaults.merge(endpoint_cfg))
115
+ end
116
+
117
+ def validate_variant!(config_variants, resolved_variant)
118
+ unless resolved_variant['hostname'] && resolved_variant['dnsSuffix']
119
+ enabled_variants = config_variants.select { |_k, v| v}.map { |k, _v| k.to_s }.join(', ')
120
+ raise ArgumentError,
121
+ "#{enabled_variants} not supported for this region and partition."
122
+ end
123
+ end
124
+
125
+ def endpoint_for(region, service, is_global_fn, variants)
126
+ if configured_variants?(variants)
127
+ endpoint_with_variants_for(region, service, variants)
128
+ else
129
+ endpoint_no_variants_for(region, service, is_global_fn)
130
+ end
131
+ end
132
+
133
+ def endpoint_with_variants_for(region, service, variants)
134
+ variant = resolve_variant(region, service, variants)
135
+ validate_variant!(variants, variant)
136
+ variant['hostname'].sub('{region}', region)
137
+ .sub('{service}', service)
138
+ .sub('{dnsSuffix}', variant['dnsSuffix'])
139
+ end
140
+
141
+ def endpoint_no_variants_for(region, service, is_global_fn)
63
142
  partition = get_partition(region)
64
143
  service_cfg = partition.fetch('services', {}).fetch(service, {})
65
144
 
66
145
  # Find the default endpoint
67
- endpoint = service_cfg
146
+ default_endpoint = service_cfg
68
147
  .fetch('defaults', {})
69
148
  .fetch('hostname', partition['defaults']['hostname'])
70
149
 
71
- # Check for sts legacy behavior
72
- sts_legacy = service == 'sts' &&
73
- sts_regional_endpoints == 'legacy' &&
74
- STS_LEGACY_REGIONS.include?(region)
150
+ endpoints = service_cfg.fetch('endpoints', {})
75
151
 
76
152
  # Check for global endpoint.
77
- if sts_legacy || service_cfg['isRegionalized'] == false
153
+ if is_global_fn.call(service, region, endpoints, service_cfg)
78
154
  region = service_cfg.fetch('partitionEndpoint', region)
79
155
  end
80
156
 
81
157
  # Check for service/region level endpoint.
82
- endpoint = service_cfg
83
- .fetch('endpoints', {})
84
- .fetch(region, {}).fetch('hostname', endpoint)
158
+ region_cfg = endpoints
159
+ .fetch(region, {})
160
+ endpoint = region_cfg
161
+ .fetch('hostname', default_endpoint)
162
+
163
+ warn_deprecation(service, region) if region_cfg['deprecated']
85
164
 
86
165
  # Replace placeholders from the endpoints
87
166
  endpoint.sub('{region}', region)
@@ -89,9 +168,51 @@ module Aws
89
168
  .sub('{dnsSuffix}', partition['dnsSuffix'])
90
169
  end
91
170
 
92
- def get_partition(region)
93
- partition_containing_region(region) ||
94
- partition_matching_region(region) ||
171
+ def warn_deprecation(service, region)
172
+ warn("The endpoint for service: #{service}, region: #{region}"\
173
+ ' is deprecated.')
174
+ end
175
+
176
+ # returns a callable that takes a region
177
+ # and returns true if the service is global
178
+ def build_is_global_fn(sts_regional_endpoints='regional')
179
+ lambda do |service, region, endpoints, service_cfg|
180
+ # Check for sts legacy behavior
181
+ sts_legacy = service == 'sts' &&
182
+ sts_regional_endpoints == 'legacy' &&
183
+ STS_LEGACY_REGIONS.include?(region)
184
+
185
+ is_global = !endpoints.key?(region) &&
186
+ service_cfg['isRegionalized'] == false
187
+
188
+ sts_legacy || is_global
189
+ end
190
+ end
191
+
192
+ def credential_scope(region, service, is_global_fn)
193
+ partition = get_partition(region)
194
+ service_cfg = partition.fetch('services', {})
195
+ .fetch(service, {})
196
+ endpoints = service_cfg.fetch('endpoints', {})
197
+
198
+ # Check for global endpoint.
199
+ if is_global_fn.call(service, region, endpoints, service_cfg)
200
+ region = service_cfg.fetch('partitionEndpoint', region)
201
+ end
202
+
203
+ default_credential_scope = service_cfg
204
+ .fetch('defaults', {})
205
+ .fetch('credentialScope', {})
206
+
207
+ endpoints
208
+ .fetch(region, {})
209
+ .fetch('credentialScope', default_credential_scope)
210
+ end
211
+
212
+ def get_partition(region_or_partition)
213
+ partition_containing_region(region_or_partition) ||
214
+ partition_matching_region(region_or_partition) ||
215
+ partition_matching_name(region_or_partition) ||
95
216
  default_partition
96
217
  end
97
218
 
@@ -103,29 +224,37 @@ module Aws
103
224
 
104
225
  def partition_matching_region(region)
105
226
  @rules['partitions'].find do |p|
106
- region.match(p['regionRegex']) ||
227
+ p['regionRegex'] && region.match(p['regionRegex']) ||
107
228
  p['services'].values.find do |svc|
108
229
  svc['endpoints'].key?(region) if svc.key?('endpoints')
109
230
  end
110
231
  end
111
232
  end
112
233
 
234
+ def partition_matching_name(partition_name)
235
+ @rules['partitions'].find { |p| p['partition'] == partition_name }
236
+ end
237
+
113
238
  def default_partition
114
239
  @rules['partitions'].find { |p| p['partition'] == 'aws' } ||
115
240
  @rules['partitions'].first
116
241
  end
117
242
 
118
243
  class << self
119
- def resolve(region, service, sts_regional_endpoints = 'regional')
120
- default_provider.resolve(region, service, sts_regional_endpoints)
244
+ def resolve(region, service, sts_endpoint = 'regional', variants = {})
245
+ default_provider.resolve(region, service, sts_endpoint, variants)
246
+ end
247
+
248
+ def signing_region(region, service, sts_regional_endpoints = 'regional')
249
+ default_provider.signing_region(region, service, sts_regional_endpoints)
121
250
  end
122
251
 
123
- def signing_region(region, service)
124
- default_provider.signing_region(region, service)
252
+ def signing_service(region, service)
253
+ default_provider.signing_service(region, service)
125
254
  end
126
255
 
127
- def dns_suffix_for(region)
128
- default_provider.dns_suffix_for(region)
256
+ def dns_suffix_for(region, service = nil, variants = {})
257
+ default_provider.dns_suffix_for(region, service, variants)
129
258
  end
130
259
 
131
260
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Partitions
3
5
  class Partition
@@ -8,12 +10,20 @@ module Aws
8
10
  def initialize(options = {})
9
11
  @name = options[:name]
10
12
  @regions = options[:regions]
13
+ @region_regex = options[:region_regex]
11
14
  @services = options[:services]
15
+ @metadata = options[:metadata]
12
16
  end
13
17
 
14
18
  # @return [String] The partition name, e.g. "aws", "aws-cn", "aws-us-gov".
15
19
  attr_reader :name
16
20
 
21
+ # @return [String] The regex representing the region format.
22
+ attr_reader :region_regex
23
+
24
+ # @return [Metadata] The metadata for the partition.
25
+ attr_reader :metadata
26
+
17
27
  # @param [String] region_name The name of the region, e.g. "us-east-1".
18
28
  # @return [Region]
19
29
  # @raise [ArgumentError] Raises `ArgumentError` for unknown region name.
@@ -68,6 +78,7 @@ module Aws
68
78
  Partition.new(
69
79
  name: partition['partition'],
70
80
  regions: build_regions(partition),
81
+ region_regex: partition['regionRegex'],
71
82
  services: build_services(partition)
72
83
  )
73
84
  end
@@ -77,8 +88,7 @@ module Aws
77
88
  # @param [Hash] partition
78
89
  # @return [Hash<String,Region>]
79
90
  def build_regions(partition)
80
- partition['regions'].each_with_object({}) do
81
- |(region_name, region), regions|
91
+ partition['regions'].each_with_object({}) do |(region_name, region), regions|
82
92
  next if region_name == "#{partition['partition']}-global"
83
93
 
84
94
  regions[region_name] = Region.build(
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Partitions
3
5
  class PartitionList
@@ -40,12 +42,62 @@ module Aws
40
42
  end
41
43
  end
42
44
 
45
+ # @param [Partition] partitions_metadata
46
+ # @api private
47
+ def merge_metadata(partitions_metadata)
48
+ partitions_metadata['partitions'].each do |partition_metadata|
49
+ outputs = partition_metadata['outputs']
50
+
51
+ if existing = @partitions[partition_metadata['id']]
52
+ @partitions[partition_metadata['id']] = Partition.new(
53
+ name: existing.name,
54
+ regions: build_metadata_regions(
55
+ partition_metadata['id'],
56
+ partition_metadata['regions'],
57
+ existing),
58
+ region_regex: partition_metadata['regionRegex'],
59
+ services: existing.services.each_with_object({}) do |s, services|
60
+ services[s.name] = s
61
+ end,
62
+ metadata: outputs
63
+ )
64
+ else
65
+ @partitions[partition_metadata['id']] = Partition.new(
66
+ name: partition_metadata['id'],
67
+ regions: build_metadata_regions(
68
+ partition_metadata['id'], partition_metadata['regions']
69
+ ),
70
+ region_regex: partition_metadata['regionRegex'],
71
+ services: {},
72
+ metadata: outputs
73
+ )
74
+ end
75
+ end
76
+ end
77
+
43
78
  # Removed all partitions.
44
79
  # @api private
45
80
  def clear
46
81
  @partitions = {}
47
82
  end
48
83
 
84
+ private
85
+
86
+ def build_metadata_regions(partition_name, metadata_regions, existing = nil)
87
+ metadata_regions.each_with_object({}) do |(region_name, region), regions|
88
+ if existing && existing.region?(region_name)
89
+ regions[region_name] = existing.region(region_name)
90
+ else
91
+ regions[region_name] = Region.new(
92
+ name: region_name,
93
+ description: region['description'],
94
+ partition_name: partition_name,
95
+ services: Set.new
96
+ )
97
+ end
98
+ end
99
+ end
100
+
49
101
  class << self
50
102
 
51
103
  # @api private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module Aws
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module Aws
@@ -14,6 +16,8 @@ module Aws
14
16
  @name = options[:name]
15
17
  @partition_name = options[:partition_name]
16
18
  @regions = options[:regions]
19
+ @fips_regions = options[:fips_regions]
20
+ @dualstack_regions = options[:dualstack_regions]
17
21
  @regionalized = options[:regionalized]
18
22
  @partition_region = options[:partition_region]
19
23
  end
@@ -29,6 +33,14 @@ module Aws
29
33
  # Regions are scoped to the partition.
30
34
  attr_reader :regions
31
35
 
36
+ # @return [Set<String>] The FIPS compatible regions this service is
37
+ # available in. Regions are scoped to the partition.
38
+ attr_reader :fips_regions
39
+
40
+ # @return [Set<String>] The Dualstack compatible regions this service is
41
+ # available in. Regions are scoped to the partition.
42
+ attr_reader :dualstack_regions
43
+
32
44
  # @return [String,nil] The global patition endpoint for this service.
33
45
  # May be `nil`.
34
46
  attr_reader :partition_region
@@ -52,6 +64,8 @@ module Aws
52
64
  name: service_name,
53
65
  partition_name: partition['partition'],
54
66
  regions: regions(service, partition),
67
+ fips_regions: variant_regions('fips', service, partition),
68
+ dualstack_regions: variant_regions('dualstack', service, partition),
55
69
  regionalized: service['isRegionalized'] != false,
56
70
  partition_region: partition_region(service)
57
71
  )
@@ -65,6 +79,21 @@ module Aws
65
79
  names - ["#{partition['partition']}-global"]
66
80
  end
67
81
 
82
+ def variant_regions(variant_name, service, partition)
83
+ svc_endpoints = service.fetch('endpoints', {})
84
+ names = Set.new
85
+ svc_endpoints.each do |key, value|
86
+ variants = value.fetch('variants', [])
87
+ variants.each do |variant|
88
+ tags = variant.fetch('tags', [])
89
+ if tags.include?(variant_name) && partition['regions'].key?(key)
90
+ names << key
91
+ end
92
+ end
93
+ end
94
+ names - ["#{partition['partition']}-global"]
95
+ end
96
+
68
97
  def partition_region(service)
69
98
  service['partitionEndpoint']
70
99
  end