Skip to content

Commit

Permalink
Source account Id from credentials to use in endpoint construction (a…
Browse files Browse the repository at this point in the history
…ws#5119)

* Adds account ID as a built-in endpoint parameter (aws#4016)

* Refactors credential identity with separate implementing classes (aws#4024) (aws#4028)

* Adds accountId as a parameter to AWS credentials identity (aws#4029)

* Adds accountId to STS credentials providers (aws#4040)

* Adding accountId support to environment variable credential provider (aws#4327)

* Adds accountId support to process credentials provider (aws#4332)

* Adds account ID support for profile credentials provider sources (aws#4340)

* Adds accountId endpoint mode (aws#4984)

* Adding back existing endpoint files (aws#5120)

* changelog (aws#5121)
  • Loading branch information
cenedhryn authored and akidambisrinivasan committed Jun 28, 2024
1 parent d4d18c6 commit 194b2ca
Show file tree
Hide file tree
Showing 77 changed files with 2,032 additions and 526 deletions.
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavaV2-aac00fa.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java V2",
"contributor": "",
"description": "Source account Id from credentials to use in endpoint construction"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.codegen.model.internal;

import com.squareup.javapoet.CodeBlock;

/**
* Represents a generic parameter that can be code generated, but isn't tied to a model shape
*/
public class LocalParameter {

private final String name;
private final Class<?> type;
private final CodeBlock documentation;

public LocalParameter(String name, Class<?> type, CodeBlock documentation) {
this.name = name;
this.type = type;
this.documentation = documentation;
}

public String name() {
return name;
}

public Class<?> type() {
return type;
}

public CodeBlock documentation() {
return documentation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public enum BuiltInParameter {
AWS_USE_DUAL_STACK,
AWS_USE_FIPS,
SDK_ENDPOINT,
AWS_AUTH_ACCOUNT_ID,
AWS_AUTH_ACCOUNT_ID_ENDPOINT_MODE,
AWS_STS_USE_GLOBAL_ENDPOINT,
AWS_S3_FORCE_PATH_STYLE,
AWS_S3_ACCELERATE,
Expand All @@ -43,6 +45,10 @@ public static BuiltInParameter fromValue(String s) {
return AWS_USE_FIPS;
case "sdk::endpoint":
return SDK_ENDPOINT;
case "aws::auth::accountid":
return AWS_AUTH_ACCOUNT_ID;
case "aws::auth::accountidendpointmode":
return AWS_AUTH_ACCOUNT_ID_ENDPOINT_MODE;
case "aws::sts::useglobalendpoint":
return AWS_STS_USE_GLOBAL_ENDPOINT;
case "aws::s3::forcepathstyle":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils;
import software.amazon.awssdk.codegen.poet.auth.scheme.ModelAuthSchemeClassesKnowledgeIndex;
import software.amazon.awssdk.codegen.poet.model.ServiceClientConfigurationUtils;
import software.amazon.awssdk.codegen.poet.rules.EndpointParamsKnowledgeIndex;
import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils;
import software.amazon.awssdk.codegen.utils.AuthUtils;
import software.amazon.awssdk.core.SdkPlugin;
Expand Down Expand Up @@ -87,6 +88,7 @@ public class BaseClientBuilderClass implements ClassSpec {
private final EndpointRulesSpecUtils endpointRulesSpecUtils;
private final AuthSchemeSpecUtils authSchemeSpecUtils;
private final ServiceClientConfigurationUtils configurationUtils;
private final EndpointParamsKnowledgeIndex endpointParamsKnowledgeIndex;

public BaseClientBuilderClass(IntermediateModel model) {
this.model = model;
Expand All @@ -96,6 +98,7 @@ public BaseClientBuilderClass(IntermediateModel model) {
this.endpointRulesSpecUtils = new EndpointRulesSpecUtils(model);
this.authSchemeSpecUtils = new AuthSchemeSpecUtils(model);
this.configurationUtils = new ServiceClientConfigurationUtils(model);
this.endpointParamsKnowledgeIndex = EndpointParamsKnowledgeIndex.of(model);
}

@Override
Expand Down Expand Up @@ -162,6 +165,8 @@ public TypeSpec poetSpec() {
});
}

endpointParamsKnowledgeIndex.accountIdEndpointModeClassMethodSpec().ifPresent(builder::addMethod);

if (model.getCustomizationConfig().getServiceConfig().getClassName() != null) {
builder.addMethod(setServiceConfigurationMethod())
.addMethod(beanStyleSetServiceConfigurationMethod());
Expand All @@ -176,8 +181,10 @@ public TypeSpec poetSpec() {
addServiceHttpConfigIfNeeded(builder, model);
builder.addMethod(invokePluginsMethod());
builder.addMethod(internalPluginsMethod());
builder.addMethod(validateClientOptionsMethod());

endpointParamsKnowledgeIndex.resolveAccountIdEndpointModeMethod().ifPresent(builder::addMethod);

builder.addMethod(validateClientOptionsMethod());

return builder.build();
}
Expand Down Expand Up @@ -430,6 +437,11 @@ private MethodSpec finalizeServiceConfigurationMethod() {
builder.addCode(".option($T.CLIENT_CONTEXT_PARAMS, clientContextParams.build())", SdkClientOption.class);
}

if (endpointParamsKnowledgeIndex.hasAccountIdEndpointModeBuiltIn()) {
builder.addCode(".option($T.$L, resolveAccountIdEndpointMode(config))",
AwsClientOption.class, model.getNamingStrategy().getEnumValueName("accountIdEndpointMode"));
}

builder.addCode(";\n");
builder.addStatement("return builder.build()");
return builder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.poet.auth.scheme.AuthSchemeSpecUtils;
import software.amazon.awssdk.codegen.poet.rules.EndpointParamsKnowledgeIndex;
import software.amazon.awssdk.codegen.poet.rules.EndpointRulesSpecUtils;
import software.amazon.awssdk.codegen.utils.AuthUtils;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
Expand All @@ -53,12 +54,15 @@ public class BaseClientBuilderInterface implements ClassSpec {
private final EndpointRulesSpecUtils endpointRulesSpecUtils;
private final AuthSchemeSpecUtils authSchemeSpecUtils;

private final EndpointParamsKnowledgeIndex endpointParamsKnowledgeIndex;

public BaseClientBuilderInterface(IntermediateModel model) {
this.model = model;
this.basePackage = model.getMetadata().getFullClientPackageName();
this.builderInterfaceName = ClassName.get(basePackage, model.getMetadata().getBaseBuilderInterface());
this.endpointRulesSpecUtils = new EndpointRulesSpecUtils(model);
this.authSchemeSpecUtils = new AuthSchemeSpecUtils(model);
this.endpointParamsKnowledgeIndex = EndpointParamsKnowledgeIndex.of(model);
}

@Override
Expand Down Expand Up @@ -87,17 +91,16 @@ public TypeSpec poetSpec() {
builder.addMethod(authSchemeProviderMethod());

if (hasClientContextParams()) {
model.getClientContextParams().forEach((n, m) -> {
builder.addMethod(clientContextParamSetter(n, m));
});
model.getClientContextParams().forEach((n, m) -> builder.addMethod(clientContextParamSetter(n, m)));
}

if (hasSdkClientContextParams()) {
model.getCustomizationConfig().getCustomClientContextParams().forEach((n, m) -> {
builder.addMethod(clientContextParamSetter(n, m));
});
model.getCustomizationConfig().getCustomClientContextParams()
.forEach((n, m) -> builder.addMethod(clientContextParamSetter(n, m)));
}

endpointParamsKnowledgeIndex.accountIdEndpointModeInterfaceMethodSpec().ifPresent(builder::addMethod);

if (generateTokenProviderMethod()) {
builder.addMethod(tokenProviderMethod());
builder.addMethod(tokenIdentityProviderMethod());
Expand Down Expand Up @@ -185,9 +188,9 @@ private MethodSpec clientContextParamSetter(String name, ClientContextParam para
TypeName type = endpointRulesSpecUtils.toJavaType(param.getType());

MethodSpec.Builder b = MethodSpec.methodBuilder(setterName)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(type, setterName)
.returns(TypeVariableName.get("B"));
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(type, setterName)
.returns(TypeVariableName.get("B"));

PoetUtils.addJavadoc(b::addJavadoc, param.getDocumentation());

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.codegen.poet.rules;

import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.STATIC;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.awscore.client.config.AwsClientOption;
import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode;
import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver;
import software.amazon.awssdk.codegen.internal.Utils;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.internal.LocalParameter;
import software.amazon.awssdk.codegen.model.rules.endpoints.BuiltInParameter;
import software.amazon.awssdk.codegen.model.rules.endpoints.ParameterModel;
import software.amazon.awssdk.core.SelectedAuthScheme;
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
import software.amazon.awssdk.core.client.config.SdkClientOption;
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
import software.amazon.awssdk.identity.spi.Identity;
import software.amazon.awssdk.utils.CompletableFutureUtils;
import software.amazon.awssdk.utils.internal.CodegenNamingUtils;

/**
* Knowledge index to get access to endpoint parameters known to the client builder classes.
*/
public final class EndpointParamsKnowledgeIndex {
private static final Map<BuiltInParameter, LocalParameter> BUILT_IN_PARAMS_FOR_CLIENT_BUILDER =
new EnumMap<>(BuiltInParameter.class);
private final IntermediateModel intermediateModel;
private Map<BuiltInParameter, LocalParameter> parametersToGenerate = new EnumMap<>(BuiltInParameter.class);

static {
BUILT_IN_PARAMS_FOR_CLIENT_BUILDER.put(
BuiltInParameter.AWS_AUTH_ACCOUNT_ID_ENDPOINT_MODE,
new LocalParameter("accountIdEndpointMode",
AccountIdEndpointMode.class,
CodeBlock.of("Sets the behavior when account ID based endpoints are created. "
+ "See {@link $T} for values", AccountIdEndpointMode.class)));
}

private EndpointParamsKnowledgeIndex(IntermediateModel intermediateModel) {
this.intermediateModel = intermediateModel;
this.parametersToGenerate = builtInsForClientBuilder(intermediateModel.getEndpointRuleSetModel().getParameters());
}

/**
* Creates a new {@link EndpointParamsKnowledgeIndex} using the given {@code intermediateModel}..
*/
public static EndpointParamsKnowledgeIndex of(IntermediateModel intermediateModel) {
return new EndpointParamsKnowledgeIndex(intermediateModel);
}

public boolean hasAccountIdEndpointModeBuiltIn() {
return parametersToGenerate.containsKey(BuiltInParameter.AWS_AUTH_ACCOUNT_ID_ENDPOINT_MODE);
}

public Optional<MethodSpec> accountIdEndpointModeClassMethodSpec() {
if (hasAccountIdEndpointModeBuiltIn()) {
return Optional.of(clientClassBuilderParamSetter(accountIdEndpointModeBuiltInParam()));
}
return Optional.empty();
}

public Optional<MethodSpec> accountIdEndpointModeInterfaceMethodSpec() {
if (hasAccountIdEndpointModeBuiltIn()) {
return Optional.of(clientInterfaceBuilderParamSetter(accountIdEndpointModeBuiltInParam()));
}
return Optional.empty();
}

private LocalParameter accountIdEndpointModeBuiltInParam() {
return parametersToGenerate.get(BuiltInParameter.AWS_AUTH_ACCOUNT_ID_ENDPOINT_MODE);
}

private MethodSpec clientClassBuilderParamSetter(LocalParameter param) {
String setterName = Utils.unCapitalize(CodegenNamingUtils.pascalCase(param.name()));
String keyName = intermediateModel.getNamingStrategy().getEnumValueName(param.name());
TypeName type = TypeName.get(param.type());

return MethodSpec.methodBuilder(setterName)
.addModifiers(Modifier.PUBLIC)
.returns(TypeVariableName.get("B"))
.addParameter(type, setterName)
.addStatement("clientConfiguration.option($T.$L, $L)",
AwsClientOption.class, keyName, setterName)
.addStatement("return thisBuilder()")
.build();
}

private MethodSpec clientInterfaceBuilderParamSetter(LocalParameter param) {
String setterName = Utils.unCapitalize(CodegenNamingUtils.pascalCase(param.name()));
TypeName type = TypeName.get(param.type());

MethodSpec.Builder b = MethodSpec.methodBuilder(setterName)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(type, setterName)
.addJavadoc(param.documentation())
.returns(TypeVariableName.get("B"));

return b.build();
}

public Optional<MethodSpec> resolveAccountIdEndpointModeMethod() {
if (!hasAccountIdEndpointModeBuiltIn()) {
return Optional.empty();
}

String name = "accountIdEndpointMode";
String keyName = intermediateModel.getNamingStrategy().getEnumValueName(name);
TypeName typeName = TypeName.get(AccountIdEndpointMode.class);

MethodSpec.Builder builder = MethodSpec.methodBuilder("resolveAccountIdEndpointMode")
.addModifiers(PRIVATE)
.addParameter(SdkClientConfiguration.class, "config")
.returns(typeName);

builder.addStatement("$T configuredMode = config.option($T.$L)", typeName, AwsClientOption.class, keyName);

builder.beginControlFlow("if (configuredMode == null)");
builder.addCode("configuredMode = $T.create()", AccountIdEndpointModeResolver.class);
builder.addCode(".profileFile(config.option($T.PROFILE_FILE_SUPPLIER))", SdkClientOption.class);
builder.addCode(".profileName(config.option($T.PROFILE_NAME))", SdkClientOption.class);
builder.addCode(".defaultMode($T.PREFERRED)", typeName);
builder.addStatement(".resolve()");
builder.endControlFlow();

builder.addStatement("return configuredMode");
return Optional.of(builder.build());
}

private Map<BuiltInParameter, LocalParameter> builtInsForClientBuilder(Map<String, ParameterModel> serviceEndpointParams) {
Map<BuiltInParameter, LocalParameter> actualParams = new EnumMap<>(BuiltInParameter.class);
serviceEndpointParams.forEach((k, v) -> {
BuiltInParameter builtInEnum = v.getBuiltInEnum();
if (builtInEnum != null && BUILT_IN_PARAMS_FOR_CLIENT_BUILDER.containsKey(builtInEnum)) {
actualParams.put(builtInEnum, BUILT_IN_PARAMS_FOR_CLIENT_BUILDER.get(builtInEnum));
}
});
return actualParams;
}

public Optional<MethodSpec> accountIdFromIdentityMethod() {
if (!hasAccountIdEndpointModeBuiltIn()) {
return Optional.empty();
}

ParameterizedTypeName paramType = ParameterizedTypeName.get(ClassName.get(SelectedAuthScheme.class),
TypeVariableName.get("T"));

MethodSpec.Builder builder = MethodSpec.methodBuilder("accountIdFromIdentity")
.addModifiers(PRIVATE, STATIC)
.addTypeVariable(TypeVariableName.get("T", Identity.class))
.addParameter(paramType, "selectedAuthScheme")
.returns(String.class);

builder.addStatement("$T identity = $T.joinLikeSync(selectedAuthScheme.identity())", TypeVariableName.get("T"),
CompletableFutureUtils.class);
builder.addStatement("$T accountId = null", String.class);
builder.beginControlFlow("if (identity instanceof $T)", AwsCredentialsIdentity.class);
builder.addStatement("accountId = (($T) identity).accountId().orElse(null)", AwsCredentialsIdentity.class);
builder.endControlFlow();
builder.addStatement("return accountId");
return Optional.of(builder.build());
}
}
Loading

0 comments on commit 194b2ca

Please sign in to comment.