Skip to content

Commit 82cd0bc

Browse files
committed
Suggest customers use a global region for IAM if their calls fail. If usability studies show this is the right route, we should update this to work automatically based on the endpoints.json isRegionalized flag so that other services are included automatically.
1 parent 04543c0 commit 82cd0bc

File tree

7 files changed

+120
-32
lines changed

7 files changed

+120
-32
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2010-2018 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.awscore.interceptor;
17+
18+
import java.net.UnknownHostException;
19+
import software.amazon.awssdk.auth.AwsExecutionAttributes;
20+
import software.amazon.awssdk.core.exception.SdkClientException;
21+
import software.amazon.awssdk.core.interceptor.Context;
22+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
23+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
24+
25+
/**
26+
* An interceptor that can be used for global services that will tell the customer when they're using a global service that
27+
* doesn't support non-global regions.
28+
*/
29+
public class GlobalServiceExecutionInterceptor implements ExecutionInterceptor {
30+
@Override
31+
public void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) {
32+
if (hasCause(context.exception(), UnknownHostException.class) &&
33+
!executionAttributes.getAttribute(AwsExecutionAttributes.AWS_REGION).isGlobalRegion()) {
34+
throw new SdkClientException("This is a global service. Consider setting AWS_GLOBAL or another global " +
35+
"region when creating your client.", context.exception());
36+
}
37+
}
38+
39+
private boolean hasCause(Throwable thrown, Class<? extends Throwable> cause) {
40+
if (thrown == null) {
41+
return false;
42+
}
43+
44+
if (cause.isAssignableFrom(thrown.getClass())) {
45+
return true;
46+
}
47+
48+
return hasCause(thrown.getCause(), cause);
49+
}
50+
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,20 @@ public class CustomizationConfig {
9090
*/
9191
private boolean skipSmokeTests;
9292

93+
/**
94+
* Exclude the create() method on a client. This is useful for global services that will need a global region configured to
95+
* work.
96+
*/
97+
private boolean excludeClientCreateMethod = false;
98+
9399
/**
94100
* A service name that this service client should share models with. The models and non-request marshallers will be generated
95101
* into the same directory as the provided service's models.
96102
*/
97103
private String shareModelsWith;
98104

99105
/**
100-
* Expression to return a service specific instance of {@link software.amazon.awssdk.http.SdkHttpConfigurationOptions}. If
106+
* Expression to return a service specific instance of {@link software.amazon.awssdk.http.SdkHttpConfigurationOption}. If
101107
* present, the client builder will override the hook to return service specific HTTP config and inject this expression into
102108
* that method. At some point we may want to have a more data driven way to declare these settings but right now we don't
103109
* have any requirements to necessitate that and referencing handwritten code is simpler. See SWF customization.config
@@ -259,6 +265,14 @@ public void setSkipSmokeTests(boolean skipSmokeTests) {
259265
this.skipSmokeTests = skipSmokeTests;
260266
}
261267

268+
public boolean isExcludeClientCreateMethod() {
269+
return excludeClientCreateMethod;
270+
}
271+
272+
public void setExcludeClientCreateMethod(boolean excludeClientCreateMethod) {
273+
this.excludeClientCreateMethod = excludeClientCreateMethod;
274+
}
275+
262276
public String getShareModelsWith() {
263277
return shareModelsWith;
264278
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientInterface.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,24 @@ public AsyncClientInterface(IntermediateModel model) {
6868

6969
@Override
7070
public TypeSpec poetSpec() {
71-
return PoetUtils.createInterfaceBuilder(className)
72-
.addSuperinterface(SdkClient.class)
73-
.addSuperinterface(SdkAutoCloseable.class)
74-
.addJavadoc(getJavadoc())
75-
.addField(FieldSpec.builder(String.class, "SERVICE_NAME")
76-
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
77-
.initializer("$S", model.getMetadata().getSigningName())
78-
.build())
79-
.addMethod(create())
80-
.addMethod(builder())
81-
.addMethods(operationsAndSimpleMethods())
82-
.build();
71+
TypeSpec.Builder result = PoetUtils.createInterfaceBuilder(className);
72+
73+
result.addSuperinterface(SdkClient.class)
74+
.addSuperinterface(SdkAutoCloseable.class)
75+
.addJavadoc(getJavadoc())
76+
.addField(FieldSpec.builder(String.class, "SERVICE_NAME")
77+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
78+
.initializer("$S", model.getMetadata().getSigningName())
79+
.build());
80+
81+
if (!model.getCustomizationConfig().isExcludeClientCreateMethod()) {
82+
result.addMethod(create());
83+
}
84+
85+
result.addMethod(builder())
86+
.addMethods(operationsAndSimpleMethods());
87+
88+
return result.build();
8389
}
8490

8591
@Override

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/SyncClientInterface.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,25 @@ public SyncClientInterface(IntermediateModel model) {
6868

6969
@Override
7070
public TypeSpec poetSpec() {
71-
return PoetUtils.createInterfaceBuilder(className)
72-
.addSuperinterface(SdkClient.class)
73-
.addSuperinterface(SdkAutoCloseable.class)
74-
.addJavadoc(getJavadoc())
75-
.addField(FieldSpec.builder(String.class, "SERVICE_NAME")
76-
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
77-
.initializer("$S", model.getMetadata().getSigningName())
78-
.build())
79-
.addMethod(create())
80-
.addMethod(builder())
81-
.addMethods(operations())
82-
.addMethod(serviceMetadata())
83-
.build();
71+
TypeSpec.Builder result = PoetUtils.createInterfaceBuilder(className);
72+
73+
result.addSuperinterface(SdkClient.class)
74+
.addSuperinterface(SdkAutoCloseable.class)
75+
.addJavadoc(getJavadoc())
76+
.addField(FieldSpec.builder(String.class, "SERVICE_NAME")
77+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
78+
.initializer("$S", model.getMetadata().getSigningName())
79+
.build());
80+
81+
if (!model.getCustomizationConfig().isExcludeClientCreateMethod()) {
82+
result.addMethod(create());
83+
}
84+
85+
result.addMethod(builder())
86+
.addMethods(operations())
87+
.addMethod(serviceMetadata());
88+
89+
return result.build();
8490
}
8591

8692
@Override

regions/src/main/java/software/amazon/awssdk/regions/Region.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,20 @@ public class Region extends AbstractEnum {
6262
public static final Region US_WEST_1 = Region.of("us-west-1");
6363
public static final Region US_WEST_2 = Region.of("us-west-2");
6464

65-
public static final Region AWS_GLOBAL = Region.of("aws-global");
65+
public static final Region AWS_GLOBAL = Region.of("aws-global", true);
6666

6767
// AWS CN Partition Regions
6868

6969
public static final Region CN_NORTH_1 = Region.of("cn-north-1");
7070
public static final Region CN_NORTHWEST_1 = Region.of("cn-northwest-1");
71-
public static final Region AWS_CN_GLOBAL = Region.of("aws-cn-global");
71+
public static final Region AWS_CN_GLOBAL = Region.of("aws-cn-global", true);
7272

7373
/**
7474
* AWS Gov Cloud Partition Regions.
7575
*/
7676
public static final class GovCloud {
7777
public static final Region US_GOV_WEST_1 = Region.of("us-gov-west-1");
78-
public static final Region AWS_US_GOV_GLOBAL = Region.of("aws-us-gov-global");
78+
public static final Region AWS_US_GOV_GLOBAL = Region.of("aws-us-gov-global", true);
7979

8080
public static final List<Region> REGIONS = Collections.unmodifiableList(Arrays.asList(
8181
US_GOV_WEST_1,
@@ -110,8 +110,11 @@ public static List<Region> getRegions() {
110110
CN_NORTHWEST_1,
111111
AWS_CN_GLOBAL));
112112

113-
private Region(String value) {
113+
private final boolean isGlobalRegion;
114+
115+
private Region(String value, boolean isGlobalRegion) {
114116
super(value);
117+
this.isGlobalRegion = isGlobalRegion;
115118
}
116119

117120
/**
@@ -125,8 +128,12 @@ private Region(String value) {
125128
* @return The region associated with the provided name.
126129
*/
127130
public static Region of(String value) {
131+
return of(value, false);
132+
}
133+
134+
private static Region of(String value, boolean isGlobalRegion) {
128135
Validate.paramNotBlank(value, "region");
129-
return AbstractEnum.value(value, Region.class, Region::new);
136+
return AbstractEnum.value(value, Region.class, v -> new Region(v, isGlobalRegion));
130137
}
131138

132139
/**
@@ -136,4 +143,7 @@ public static List<Region> getRegions() {
136143
return REGIONS;
137144
}
138145

146+
public boolean isGlobalRegion() {
147+
return isGlobalRegion;
148+
}
139149
}

services/iam/src/main/resources/codegen-resources/customization.config

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
"listSigningCertificates",
1717
"listAccessKeys"
1818
],
19-
"blacklistedSimpleMethods" : ["updateAccountPasswordPolicy"]
19+
"blacklistedSimpleMethods" : ["updateAccountPasswordPolicy"],
20+
"excludeClientCreateMethod": true
2021
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
software.amazon.awssdk.awscore.interceptor.GlobalServiceExecutionInterceptor

0 commit comments

Comments
 (0)