Skip to content

Commit 6c80beb

Browse files
authored
Adding service endpoint section in config file (#5944)
* Adding service endpoint section in ini file * Adding INI file services section parsing * Removed not needed file * Fixing test names and adding changelog * Fix checkstyle * Adding java doc * Relocating test to decrease generated test case count * Adding comment about current behavior deviating from the standard * Fix comments on the PR --------- Co-authored-by: Ran Vaknin <[email protected]>
1 parent fce580e commit 6c80beb

File tree

5 files changed

+177
-2
lines changed

5 files changed

+177
-2
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Added functionality to be able to configure an endpoint override through the [services] section in the aws config file for specific services. \nhttps://docs.aws.amazon.com/sdkref/latest/guide/feature-ss-endpoints.html"
6+
}

core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
* <li>The service-agnostic endpoint override system property (i.e. 'aws.endpointUrl')</li>
5151
* <li>The service-specific endpoint override environment variable (e.g. 'AWS_ENDPOINT_URL_S3')</li>
5252
* <li>The service-agnostic endpoint override environment variable (i.e. 'AWS_ENDPOINT_URL')</li>
53+
* <li>The service-specific endpoint override from services section (e.g. '[services dev] s3.endpoint_url')</li>
5354
* <li>The service-specific endpoint override profile property (e.g. 's3.endpoint_url')</li>
5455
* <li>The service-agnostic endpoint override profile property (i.e. 'endpoint_url')</li>
5556
* <li>The {@link ServiceMetadata} for the service</li>
@@ -129,6 +130,15 @@ private Optional<ClientEndpoint> clientEndpointFromEnvironment(Builder builder)
129130
() -> systemProperty(GLOBAL_ENDPOINT_OVERRIDE_SYSTEM_PROPERTY),
130131
() -> environmentVariable(builder.serviceEndpointOverrideEnvironmentVariable),
131132
() -> environmentVariable(GLOBAL_ENDPOINT_OVERRIDE_ENVIRONMENT_VARIABLE),
133+
() -> servicesProperty(builder),
134+
135+
/*
136+
* This is a deviation from the cross-SDK standard.
137+
* There should not have been support for service-specific
138+
* endpoint override under the [profile] section.
139+
* It is in this order to maintain backwards compatibility, and to reflect that
140+
* service-specific endpoint overrides from the [services] section should be preferred.
141+
*/
132142
() -> profileProperty(builder,
133143
builder.serviceProfileProperty + "."
134144
+ ProfileProperty.ENDPOINT_URL),
@@ -156,6 +166,20 @@ private Optional<URI> profileProperty(Builder builder, String profileProperty) {
156166
.flatMap(p -> p.property(profileProperty)));
157167
}
158168

169+
private Optional<URI> servicesProperty(Builder builder) {
170+
Optional<ProfileFile> profileFile = Optional.ofNullable(builder.profileFile.get());
171+
Optional<String> servicesSectionName = profileFile
172+
.flatMap(pf -> pf.profile(builder.profileName))
173+
.flatMap(p -> p.property("services"));
174+
175+
Optional<String> serviceEndpoint = servicesSectionName
176+
.flatMap(name -> profileFile.flatMap(pf -> pf.getSection("services", name)))
177+
.flatMap(p -> p.property(builder.serviceProfileProperty
178+
+ "." + ProfileProperty.ENDPOINT_URL));
179+
180+
return createUri("services section property", serviceEndpoint);
181+
}
182+
159183
private Optional<ClientEndpoint> clientEndpointFromServiceMetadata(Builder builder) {
160184
// This value is generally overridden after endpoints 2.0. It seems to exist for backwards-compatibility
161185
// with older client versions or interceptors.

core/profiles/src/main/java/software/amazon/awssdk/profiles/internal/ProfileSection.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ public enum ProfileSection {
2929
* are part of a named collection of attributes.
3030
* This `sso-session` section is referenced by the user when configuring a profile to derive an SSO token.
3131
*/
32-
SSO_SESSION("sso-session", "sso_session");
32+
SSO_SESSION("sso-session", "sso_session"),
33+
34+
/**
35+
* A `services` section declares a group of service-specific configurations that can be referenced by profiles.
36+
* Service sub-sections use standardized names derived from the AWS service identifiers.
37+
*/
38+
SERVICES("services", "services");
3339

3440
private final String sectionTitle;
3541
private final String propertyKeyName;

test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/EndpointSharedConfigTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ public void resolvesCorrectEndpoint() {
7676
.append(" endpoint_url = ").append(testCase.serviceProfileSetting).append("\n");
7777
}
7878

79+
if (testCase.serviceSectionProfileSetting != null) {
80+
profileFileContent.append("services = dev\n\n");
81+
profileFileContent.append("[services dev] \n")
82+
.append("amazonprotocolrestjson =\n")
83+
.append(" endpoint_url = ").append(testCase.serviceSectionProfileSetting).append("\n");
84+
}
85+
7986
ProfileFile profileFile =
8087
ProfileFile.builder()
8188
.type(ProfileFile.Type.CONFIGURATION)
@@ -119,6 +126,7 @@ public static Iterable<TestCase> testCases() {
119126
"Global system property",
120127
"Service environment variable",
121128
"Global environment variable",
129+
"Services Section profile file",
122130
"Service profile file",
123131
"Global profile file");
124132

@@ -209,6 +217,7 @@ public static class TestCase {
209217
"https://global-system-property-endpoint.com",
210218
"https://service-env-var-endpoint.com",
211219
"https://global-env-var-endpoint.com",
220+
"https://service-section-endpoint.com",
212221
"https://service-profile-endpoint.com",
213222
"https://global-profile-endpoint.com");
214223

@@ -219,12 +228,13 @@ public static class TestCase {
219228
private final String globalEnvVarSetting;
220229
private final String serviceProfileSetting;
221230
private final String globalProfileSetting;
231+
private final String serviceSectionProfileSetting;
222232
private final String caseName;
223233
private final String expectedEndpoint;
224234

225235
public TestCase(boolean[] settings, Integer expectedEndpointIndex, String caseName) {
226236
this(endpoint(settings, 0), endpoint(settings, 1), endpoint(settings, 2), endpoint(settings, 3),
227-
endpoint(settings, 4), endpoint(settings, 5), endpoint(settings, 6),
237+
endpoint(settings, 4), endpoint(settings, 5), endpoint(settings, 6), endpoint(settings, 7),
228238
endpointForIndex(expectedEndpointIndex), caseName);
229239
}
230240

@@ -244,6 +254,7 @@ private TestCase(String clientSetting,
244254
String globalSystemPropSetting,
245255
String serviceEnvVarSetting,
246256
String globalEnvVarSetting,
257+
String serviceSectionProfileSetting,
247258
String serviceProfileSetting,
248259
String globalProfileSetting,
249260
String expectedEndpoint,
@@ -255,6 +266,7 @@ private TestCase(String clientSetting,
255266
this.globalEnvVarSetting = globalEnvVarSetting;
256267
this.serviceProfileSetting = serviceProfileSetting;
257268
this.globalProfileSetting = globalProfileSetting;
269+
this.serviceSectionProfileSetting = serviceSectionProfileSetting;
258270
this.expectedEndpoint = expectedEndpoint;
259271
this.caseName = caseName;
260272
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.services;
17+
18+
import java.util.Optional;
19+
import org.junit.jupiter.api.Test;
20+
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
21+
import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider;
22+
import software.amazon.awssdk.profiles.Profile;
23+
import software.amazon.awssdk.profiles.ProfileFile;
24+
import software.amazon.awssdk.regions.Region;
25+
import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient;
26+
import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClientBuilder;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
public class ProfileFileServicesTest {
31+
32+
@Test
33+
public void servicesSection_shouldRecognizeServicesSection() {
34+
String profileContent =
35+
"[services dev]\n" +
36+
"s3 = \n" +
37+
" endpoint_url = https://foo.bar:9000\n";
38+
39+
ProfileFile profileFile = ProfileFile.builder()
40+
.content(profileContent)
41+
.type(ProfileFile.Type.CONFIGURATION)
42+
.build();
43+
44+
Optional<Profile> servicesSection = profileFile.getSection("services", "dev");
45+
assertThat(servicesSection).isPresent();
46+
}
47+
48+
@Test
49+
public void servicesSection_canParseServicesSectionProperties() {
50+
String profileContent =
51+
"[services dev]\n" +
52+
"s3 = \n" +
53+
" endpoint_url = https://foo.bar:9000\n" +
54+
" foo = bar\n" +
55+
"\n" +
56+
"[profile test-profile]\n" +
57+
"services = dev";
58+
59+
ProfileFile profileFile = ProfileFile.builder()
60+
.content(profileContent)
61+
.type(ProfileFile.Type.CONFIGURATION)
62+
.build();
63+
64+
Optional<Profile> servicesSection = profileFile.getSection("services", "dev");
65+
assertThat(servicesSection).isPresent();
66+
67+
Profile services = servicesSection.get();
68+
assertThat(services.properties())
69+
.containsEntry("s3.endpoint_url", "https://foo.bar:9000");
70+
}
71+
72+
73+
@Test
74+
public void servicesSection_canParseMultipleServicesInSection() {
75+
String profileContent =
76+
"[services testing-s3-and-eb]\n" +
77+
"s3 = \n" +
78+
" endpoint_url = http://localhost:4567\n" +
79+
"elastic_beanstalk = \n" +
80+
" endpoint_url = http://localhost:8000\n" +
81+
"\n" +
82+
"[profile dev]\n" +
83+
"services = testing-s3-and-eb";
84+
85+
ProfileFile profileFile = ProfileFile.builder()
86+
.content(profileContent)
87+
.type(ProfileFile.Type.CONFIGURATION)
88+
.build();
89+
90+
Optional<Profile> servicesSection = profileFile.getSection("services", "testing-s3-and-eb");
91+
assertThat(servicesSection).isPresent();
92+
93+
Profile services = servicesSection.get();
94+
assertThat(services.properties())
95+
.containsEntry("s3.endpoint_url", "http://localhost:4567")
96+
.containsEntry("elastic_beanstalk.endpoint_url", "http://localhost:8000");
97+
}
98+
99+
@org.junit.Test(expected = EndpointCapturingInterceptor.CaptureCompletedException.class)
100+
public void invalidNestedBlockFormat_shouldThrowCaptureCompletedException() {
101+
StringBuilder profileFileContent = new StringBuilder();
102+
profileFileContent.append("[default] \n")
103+
.append("services = dev \n")
104+
.append("\n")
105+
.append("[services dev] \n")
106+
.append("amazonprotocolrestjson =\n")
107+
.append("endpoint_url =");
108+
109+
ProfileFile profileFile = ProfileFile.builder()
110+
.type(ProfileFile.Type.CONFIGURATION)
111+
.content(profileFileContent.toString())
112+
.build();
113+
114+
ProtocolRestJsonClientBuilder builder = ProtocolRestJsonClient.builder()
115+
.region(Region.US_WEST_2)
116+
.credentialsProvider(AnonymousCredentialsProvider.create())
117+
.overrideConfiguration(c -> c.defaultProfileFile(profileFile)
118+
.defaultProfileName("default"));
119+
120+
EndpointCapturingInterceptor interceptor = new EndpointCapturingInterceptor();
121+
builder.overrideConfiguration(b -> b.addExecutionInterceptor(interceptor));
122+
123+
ProtocolRestJsonClient client = builder.build();
124+
125+
client.allTypes();
126+
}
127+
}

0 commit comments

Comments
 (0)