From 5a972e633681698c2db8adc3325d2037c7a74a65 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Mon, 18 Oct 2021 17:40:20 -0400 Subject: [PATCH 01/10] refactor!: remove AuthConfig and RegionConfig; replace with AwsClientConfig; removing SigningRegion from config properties; add placeholders for loading config --- .../runtime/config/AwsClientConfigLoader.kt | 24 +++++++++++++++ .../aws/sdk/kotlin/runtime/auth/AuthConfig.kt | 25 ---------------- .../kotlin/runtime/client/AwsClientConfig.kt | 25 ++++++++++++++++ .../sdk/kotlin/runtime/region/RegionConfig.kt | 17 ----------- .../codegen/AwsServiceConfigIntegration.kt | 29 +++++-------------- 5 files changed, 57 insertions(+), 63 deletions(-) create mode 100644 aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt delete mode 100644 aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/auth/AuthConfig.kt create mode 100644 aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/client/AwsClientConfig.kt delete mode 100644 aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/region/RegionConfig.kt diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt new file mode 100644 index 00000000000..d36d3ac41f8 --- /dev/null +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt @@ -0,0 +1,24 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +package aws.sdk.kotlin.runtime.config + +import aws.sdk.kotlin.runtime.client.AwsClientConfig + +/** + * Options that control how an [aws.sdk.kotlin.runtime.client.AwsClientConfig] is resolved + */ +public class AwsClientConfigLoadOptions { + // TODO - see for an idea https://github.com/aws/aws-sdk-go-v2/blob/973e5f5e9477e0690bcb4be3145bb72e956651cc/config/load_options.go#L22 + // Most of these will not be needed if you are using a corresponding environment variable or system property but there should be an explicit + // option to control behavior. +} + +/** + * Load the AWS client configuration from the environment. + */ +public suspend fun AwsClientConfig.Companion.loadFromEnvironment( + block: AwsClientConfigLoadOptions.() -> Unit = {} +): AwsClientConfig = TODO() diff --git a/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/auth/AuthConfig.kt b/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/auth/AuthConfig.kt deleted file mode 100644 index ca10df221b2..00000000000 --- a/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/auth/AuthConfig.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -package aws.sdk.kotlin.runtime.auth - -import aws.sdk.kotlin.runtime.auth.credentials.CredentialsProvider - -/** - * A common interface that all AWS service clients implement as part of their configuration state. - */ -public interface AuthConfig { - - /** - * Specifies zero or more credential providers that will be called to resolve credentials before making - * AWS service calls. If not provided a default credential provider chain is used. - */ - public val credentialsProvider: CredentialsProvider? - - /** - * AWS Region to be used for signing the request. This is not always same as `region` in case of global services. - */ - public val signingRegion: String? -} diff --git a/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/client/AwsClientConfig.kt b/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/client/AwsClientConfig.kt new file mode 100644 index 00000000000..e8f0f8c61a0 --- /dev/null +++ b/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/client/AwsClientConfig.kt @@ -0,0 +1,25 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +package aws.sdk.kotlin.runtime.client + +import aws.sdk.kotlin.runtime.auth.credentials.CredentialsProvider + +/** + * Shared AWS service client configuration that all AWS service clients implement as part of their configuration state. + */ +public interface AwsClientConfig { + /** + * The AWS region to make requests to + */ + public val region: String + + /** + * The [CredentialsProvider] that will be called to resolve credentials before making AWS service calls + */ + public val credentialsProvider: CredentialsProvider + + public companion object {} +} diff --git a/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/region/RegionConfig.kt b/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/region/RegionConfig.kt deleted file mode 100644 index 1723ddd46ee..00000000000 --- a/aws-runtime/aws-types/common/src/aws/sdk/kotlin/runtime/region/RegionConfig.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -package aws.sdk.kotlin.runtime.region - -/** - * A common interface that all AWS service clients implement as part of their configuration state. - */ -public interface RegionConfig { - /** - * AWS Region the client was configured with. Note that this is not always the signing region in the case of global - * services like IAM. - */ - public val region: String? -} diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index 2a02c5915f7..93d9d3327c3 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -17,7 +17,6 @@ class AwsServiceConfigIntegration : KotlinIntegration { // AuthConfig properties val CredentialsProviderProp: ClientConfigProperty - val SigningRegionProp: ClientConfigProperty val EndpointResolverProp: ClientConfigProperty = ClientConfigProperty { name = "endpointResolver" @@ -33,9 +32,9 @@ class AwsServiceConfigIntegration : KotlinIntegration { } init { - val regionConfigSymbol = buildSymbol { - name = "RegionConfig" - namespace(AwsKotlinDependency.AWS_TYPES, subpackage = "region") + val awsClientConfigSymbol = buildSymbol { + name = "AwsClientConfig" + namespace(AwsKotlinDependency.AWS_TYPES) } RegionProp = ClientConfigProperty.String( @@ -43,26 +42,12 @@ class AwsServiceConfigIntegration : KotlinIntegration { documentation = """ AWS region to make requests to """.trimIndent(), - baseClass = regionConfigSymbol - ) - - val authConfigSymbol = buildSymbol { - name = "AuthConfig" - namespace(AwsKotlinDependency.AWS_TYPES, subpackage = "auth") - } - - SigningRegionProp = ClientConfigProperty.String( - "signingRegion", - documentation = """ - AWS region to be used for signing the request. This is not necessarily the same as `region` - in the case of global services like IAM - """.trimIndent(), - baseClass = authConfigSymbol + baseClass = awsClientConfigSymbol ) CredentialsProviderProp = ClientConfigProperty { symbol = AwsRuntimeTypes.Types.CredentialsProvider - baseClass = authConfigSymbol + baseClass = awsClientConfigSymbol documentation = """ The AWS credentials provider to use for authenticating requests. If not provided a [${symbol?.namespace}.DefaultChainCredentialsProvider] instance will be used. @@ -71,6 +56,8 @@ class AwsServiceConfigIntegration : KotlinIntegration { } } + // FIXME - credentials and endpoint resolver need defaulted but ONLY in the constructor not the builder. We have no way (yet) of + // expressing this override fun additionalServiceConfigProps(ctx: CodegenContext): List = - listOf(RegionProp, SigningRegionProp, CredentialsProviderProp, EndpointResolverProp) + listOf(RegionProp, CredentialsProviderProp, EndpointResolverProp) } From 3c84ded390898fd655d6eb7b9aa2087f5c07ff0a Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 11:10:10 -0400 Subject: [PATCH 02/10] update configuration properties to use new property type; refactor resolver and cred provider to be required with a default --- .../codegen/AwsServiceConfigIntegration.kt | 26 +++++++--- .../sdk/kotlin/codegen/PresignerGenerator.kt | 7 +-- .../AwsServiceConfigIntegrationTest.kt | 52 +++++++++++++++++++ .../kotlin/codegen/PresignerGeneratorTest.kt | 4 +- 4 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index 93d9d3327c3..b9d7817ff2e 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -4,11 +4,14 @@ */ package aws.sdk.kotlin.codegen +import aws.sdk.kotlin.codegen.protocols.core.EndpointResolverGenerator import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration +import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes import software.amazon.smithy.kotlin.codegen.model.buildSymbol import software.amazon.smithy.kotlin.codegen.model.namespace import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigProperty +import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigPropertyType class AwsServiceConfigIntegration : KotlinIntegration { companion object { @@ -29,6 +32,8 @@ class AwsServiceConfigIntegration : KotlinIntegration { name = "EndpointResolver" namespace(AwsKotlinDependency.AWS_CORE, subpackage = "endpoint") } + + propertyType = ClientConfigPropertyType.RequiredWithDefault("${EndpointResolverGenerator.typeName}()") } init { @@ -37,27 +42,32 @@ class AwsServiceConfigIntegration : KotlinIntegration { namespace(AwsKotlinDependency.AWS_TYPES) } - RegionProp = ClientConfigProperty.String( - "region", + RegionProp = ClientConfigProperty { + name = "region" + symbol = KotlinTypes.String + baseClass = awsClientConfigSymbol documentation = """ AWS region to make requests to - """.trimIndent(), - baseClass = awsClientConfigSymbol - ) + """.trimIndent() + propertyType = ClientConfigPropertyType.Required() + } CredentialsProviderProp = ClientConfigProperty { - symbol = AwsRuntimeTypes.Types.CredentialsProvider + val defaultProvider = AwsRuntimeTypes.Config.Credentials.DefaultChainCredentialsProvider + symbol = AwsRuntimeTypes.Types.CredentialsProvider.toBuilder() + .addReference(defaultProvider) + .build() baseClass = awsClientConfigSymbol documentation = """ The AWS credentials provider to use for authenticating requests. If not provided a [${symbol?.namespace}.DefaultChainCredentialsProvider] instance will be used. """.trimIndent() + + propertyType = ClientConfigPropertyType.RequiredWithDefault("${defaultProvider.name}()") } } } - // FIXME - credentials and endpoint resolver need defaulted but ONLY in the constructor not the builder. We have no way (yet) of - // expressing this override fun additionalServiceConfigProps(ctx: CodegenContext): List = listOf(RegionProp, CredentialsProviderProp, EndpointResolverProp) } diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt index eb415e44fe8..45f070a4d24 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt @@ -29,6 +29,7 @@ import software.amazon.smithy.kotlin.codegen.model.expectTrait import software.amazon.smithy.kotlin.codegen.model.namespace import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigGenerator import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigProperty +import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigPropertyType import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpBindingProtocolGenerator import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpBindingResolver import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpTraitResolver @@ -220,21 +221,21 @@ class PresignerGenerator : KotlinIntegration { name = "region" documentation = "AWS region to make requests for" baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig - required = true + propertyType = ClientConfigPropertyType.Required() } val signingNameProperty = ClientConfigProperty { symbol = KotlinTypes.String name = "signingName" documentation = "Service identifier used to sign requests" baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig - constantValue = """"$sigv4ServiceName"""" + propertyType = ClientConfigPropertyType.ConstantValue(""""$sigv4ServiceName"""") } val serviceIdProperty = ClientConfigProperty { symbol = KotlinTypes.String name = "serviceId" documentation = "Service identifier used to resolve endpoints" baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig - constantValue = """"$serviceId"""" + propertyType = ClientConfigPropertyType.ConstantValue(""""$serviceId"""") } val ccg = ClientConfigGenerator( diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt new file mode 100644 index 00000000000..74ccdfa12f1 --- /dev/null +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt @@ -0,0 +1,52 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +package aws.sdk.kotlin.codegen + +import org.junit.jupiter.api.Test +import software.amazon.smithy.kotlin.codegen.core.KotlinWriter +import software.amazon.smithy.kotlin.codegen.model.expectShape +import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigGenerator +import software.amazon.smithy.kotlin.codegen.test.* +import software.amazon.smithy.model.shapes.ServiceShape + +class AwsServiceConfigIntegrationTest { + @Test + fun testServiceConfigurationProperties() { + val model = """ + namespace com.test + + use aws.protocols#awsJson1_1 + use aws.api#service + + @service(sdkId: "service with overrides", endpointPrefix: "service-with-overrides") + @awsJson1_1 + service Example { + version: "1.0.0", + operations: [GetFoo] + } + + operation GetFoo {} + """.toSmithyModel() + + val serviceShape = model.expectShape("com.test#Example") + + val testCtx = model.newTestContext(serviceName = "Example") + val writer = KotlinWriter("com.test") + + val renderingCtx = testCtx.toRenderingContext(writer, serviceShape) + .copy(integrations = listOf(AwsServiceConfigIntegration())) + + ClientConfigGenerator(renderingCtx, detectDefaultProps = false).render() + val contents = writer.toString() + + val expectedProps = """ + override val credentialsProvider: CredentialsProvider = builder.credentialsProvider ?: DefaultChainCredentialsProvider() + val endpointResolver: EndpointResolver = builder.endpointResolver ?: DefaultEndpointResolver() + override val region: String = requireNotNull(builder.region) { "region is a required configuration property" } +""" + contents.shouldContainOnlyOnceWithDiff(expectedProps) + } +} diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt index 7118d818a4e..e4537a57f44 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt @@ -227,13 +227,13 @@ class PresignerGeneratorTest { class TestPresignConfig private constructor(builder: BuilderImpl): ServicePresignConfig { override val credentialsProvider: CredentialsProvider = builder.credentialsProvider override val endpointResolver: EndpointResolver = builder.endpointResolver - override val region: String = builder.region ?: throw ClientException("region must be set") + override val region: String = requireNotNull(builder.region) { "region is a required configuration property" } override val serviceId: String = "example" override val signingName: String = "example-signing-name" companion object { @JvmStatic fun fluentBuilder(): FluentBuilder = BuilderImpl() - fun builder(): DslBuilder = BuilderImpl() + operator fun invoke(block: DslBuilder.() -> kotlin.Unit): ServicePresignConfig = BuilderImpl().apply(block).build() } From 22e12d9cfc315e8ef36b0e8cfa7a419a4287237f Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 11:36:23 -0400 Subject: [PATCH 03/10] fix aws service config integration properties --- .../codegen/AwsServiceConfigIntegration.kt | 47 +++++++++++-------- .../core/AwsHttpProtocolClientGenerator.kt | 6 +-- .../middleware/AwsSignatureVersion4.kt | 3 +- .../middleware/EndpointResolverMiddleware.kt | 10 +--- .../AwsServiceConfigIntegrationTest.kt | 7 +++ 5 files changed, 39 insertions(+), 34 deletions(-) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index b9d7817ff2e..f2c1013e121 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -8,6 +8,7 @@ import aws.sdk.kotlin.codegen.protocols.core.EndpointResolverGenerator import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes +import software.amazon.smithy.kotlin.codegen.model.boxed import software.amazon.smithy.kotlin.codegen.model.buildSymbol import software.amazon.smithy.kotlin.codegen.model.namespace import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigProperty @@ -21,30 +22,15 @@ class AwsServiceConfigIntegration : KotlinIntegration { // AuthConfig properties val CredentialsProviderProp: ClientConfigProperty - val EndpointResolverProp: ClientConfigProperty = ClientConfigProperty { - name = "endpointResolver" - documentation = """ - Determines the endpoint (hostname) to make requests to. When not provided a default - resolver is configured automatically. This is an advanced client option. - """.trimIndent() - - symbol = buildSymbol { - name = "EndpointResolver" - namespace(AwsKotlinDependency.AWS_CORE, subpackage = "endpoint") - } - - propertyType = ClientConfigPropertyType.RequiredWithDefault("${EndpointResolverGenerator.typeName}()") - } - init { val awsClientConfigSymbol = buildSymbol { name = "AwsClientConfig" - namespace(AwsKotlinDependency.AWS_TYPES) + namespace(AwsKotlinDependency.AWS_TYPES, subpackage = "client") } RegionProp = ClientConfigProperty { name = "region" - symbol = KotlinTypes.String + symbol = KotlinTypes.String.toBuilder().boxed().build() baseClass = awsClientConfigSymbol documentation = """ AWS region to make requests to @@ -68,6 +54,29 @@ class AwsServiceConfigIntegration : KotlinIntegration { } } - override fun additionalServiceConfigProps(ctx: CodegenContext): List = - listOf(RegionProp, CredentialsProviderProp, EndpointResolverProp) + override fun additionalServiceConfigProps(ctx: CodegenContext): List { + // we can't construct this without the actual package name due to the generated DefaultEndpointResolver symbol + val endpointResolverProperty = ClientConfigProperty { + name = "endpointResolver" + documentation = """ + Determines the endpoint (hostname) to make requests to. When not provided a default + resolver is configured automatically. This is an advanced client option. + """.trimIndent() + + val defaultResolver = buildSymbol { + name = EndpointResolverGenerator.typeName + namespace = "${ctx.settings.pkg.name}.internal" + } + + symbol = buildSymbol { + name = "EndpointResolver" + namespace(AwsKotlinDependency.AWS_CORE, subpackage = "endpoint") + reference(defaultResolver) + } + + propertyType = ClientConfigPropertyType.RequiredWithDefault("${defaultResolver.name}()") + } + + return listOf(RegionProp, CredentialsProviderProp, endpointResolverProperty) + } } diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpProtocolClientGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpProtocolClientGenerator.kt index 9ca0f0567f7..ede50d006f5 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpProtocolClientGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/core/AwsHttpProtocolClientGenerator.kt @@ -77,16 +77,14 @@ open class AwsHttpProtocolClientGenerator( // FIXME - we also need a way to tie in config properties added via integrations that need to influence the context writer.addImport(RuntimeTypes.Core.ExecutionContext) writer.addImport("SdkClientOption", KotlinDependency.CORE, "${KotlinDependency.CORE.namespace}.client") - writer.addImport(AwsRuntimeTypes.Config.Region.resolveRegionForOperation) writer.addImport(AwsRuntimeTypes.Core.AuthAttributes) writer.addImport(AwsRuntimeTypes.Core.AwsClientOption) writer.addImport("putIfAbsent", KotlinDependency.UTILS) writer.dokka("merge the defaults configured for the service into the execution context before firing off a request") writer.openBlock("private suspend fun mergeServiceDefaults(ctx: ExecutionContext) {", "}") { - writer.write("val region = #T(ctx, config)", AwsRuntimeTypes.Config.Region.resolveRegionForOperation) - writer.write("ctx.putIfAbsent(AwsClientOption.Region, region)") - writer.write("ctx.putIfAbsent(AuthAttributes.SigningRegion, config.signingRegion ?: region)") + writer.write("ctx.putIfAbsent(AwsClientOption.Region, config.region)") + writer.write("ctx.putIfAbsent(AuthAttributes.SigningRegion, config.region)") writer.write("ctx.putIfAbsent(SdkClientOption.ServiceName, serviceName)") writer.write("ctx.putIfAbsent(SdkClientOption.LogMode, config.sdkLogMode)") diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/AwsSignatureVersion4.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/AwsSignatureVersion4.kt index 0c2f46b6200..3d19411ebb5 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/AwsSignatureVersion4.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/AwsSignatureVersion4.kt @@ -39,9 +39,8 @@ open class AwsSignatureVersion4(private val signingServiceName: String) : HttpFe override fun renderConfigure(writer: KotlinWriter) { writer.addImport(AwsRuntimeTypes.Signing.AwsSigV4SigningMiddleware) - writer.addImport(AwsRuntimeTypes.Config.Credentials.DefaultChainCredentialsProvider) - writer.write("this.credentialsProvider = config.credentialsProvider ?: DefaultChainCredentialsProvider()") + writer.write("this.credentialsProvider = config.credentialsProvider") writer.write("this.signingService = #S", signingServiceName) } diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/EndpointResolverMiddleware.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/EndpointResolverMiddleware.kt index 04a06edeba0..8e079779435 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/EndpointResolverMiddleware.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/protocols/middleware/EndpointResolverMiddleware.kt @@ -22,17 +22,9 @@ class EndpointResolverMiddleware(private val ctx: ProtocolGenerator.GenerationCo name = "ServiceEndpointResolver" namespace(AwsKotlinDependency.AWS_HTTP, subpackage = "middleware") } - - // generated symbol - val defaultResolverSymbol = buildSymbol { - name = "DefaultEndpointResolver" - namespace = "${ctx.settings.pkg.name}.internal" - } - writer.addImport(resolverFeatureSymbol) - writer.addImport(defaultResolverSymbol) writer.write("serviceId = ServiceId") - writer.write("resolver = config.endpointResolver ?: DefaultEndpointResolver()") + writer.write("resolver = config.endpointResolver") } } diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt index 74ccdfa12f1..07be8f95946 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegrationTest.kt @@ -48,5 +48,12 @@ class AwsServiceConfigIntegrationTest { override val region: String = requireNotNull(builder.region) { "region is a required configuration property" } """ contents.shouldContainOnlyOnceWithDiff(expectedProps) + + val expectedImpl = """ + override var credentialsProvider: CredentialsProvider? = null + override var endpointResolver: EndpointResolver? = null + override var region: String? = null +""" + contents.shouldContainOnlyOnceWithDiff(expectedImpl) } } From 77465581ef7f10f6b6106c7690a8e492700b58ef Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 12:20:21 -0400 Subject: [PATCH 04/10] refactor: override AWS client construction --- .../aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt | 4 ++ .../codegen/AwsServiceConfigIntegration.kt | 56 +++++++++++++++++++ .../kotlin/codegen/PresignerGeneratorTest.kt | 1 - 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt index 53e37628765..5bffefef5bc 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt @@ -40,6 +40,7 @@ object AwsRuntimeTypes { object Types { val CredentialsProvider = runtimeSymbol("CredentialsProvider", AwsKotlinDependency.AWS_TYPES, "auth.credentials") val Credentials = runtimeSymbol("Credentials", AwsKotlinDependency.AWS_TYPES, "auth.credentials") + val AwsClientConfig = runtimeSymbol("AwsClientConfig", AwsKotlinDependency.AWS_TYPES, "client") } object Config { @@ -51,6 +52,9 @@ object AwsRuntimeTypes { val DefaultChainCredentialsProvider = runtimeSymbol("DefaultChainCredentialsProvider", AwsKotlinDependency.AWS_CONFIG, "auth.credentials") val StaticCredentialsProvider = runtimeSymbol("StaticCredentialsProvider", AwsKotlinDependency.AWS_CONFIG, "auth.credentials") } + + val AwsClientConfigLoadOptions = runtimeSymbol("AwsClientConfigLoadOptions", AwsKotlinDependency.AWS_CONFIG, "config") + val loadFromEnvironment = runtimeSymbol("loadFromEnvironment", AwsKotlinDependency.AWS_CONFIG, "config") } object Signing { diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index f2c1013e121..e3aab12cecc 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -5,14 +5,18 @@ package aws.sdk.kotlin.codegen import aws.sdk.kotlin.codegen.protocols.core.EndpointResolverGenerator +import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.kotlin.codegen.core.* import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration +import software.amazon.smithy.kotlin.codegen.integration.SectionWriter +import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes import software.amazon.smithy.kotlin.codegen.model.boxed import software.amazon.smithy.kotlin.codegen.model.buildSymbol import software.amazon.smithy.kotlin.codegen.model.namespace import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigProperty import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigPropertyType +import software.amazon.smithy.kotlin.codegen.rendering.ServiceGenerator class AwsServiceConfigIntegration : KotlinIntegration { companion object { @@ -52,8 +56,60 @@ class AwsServiceConfigIntegration : KotlinIntegration { propertyType = ClientConfigPropertyType.RequiredWithDefault("${defaultProvider.name}()") } } + + private val overrideServiceCompanionObjectWriter = SectionWriter { writer, _ -> + // override the service client companion object for how a client is constructed + val serviceSymbol: Symbol = writer.getContextValue(ServiceGenerator.ServiceInterfaceCompanionObject.ServiceSymbol) + writer.withBlock("companion object {", "}") { + withBlock( + "operator fun invoke(sharedConfig: #T? = null, block: Config.DslBuilder.() -> Unit = {}): #L {", + "}", + AwsRuntimeTypes.Types.AwsClientConfig, + serviceSymbol.name + ) { + withBlock( + "val config = Config.BuilderImpl().apply { ", + "}.apply(block).build()" + ) { + write("region = sharedConfig?.region") + write("credentialsProvider = sharedConfig?.credentialsProvider") + } + write("return Default${serviceSymbol.name}(config)") + } + + // generate a convenience init to resolve a client from the current environment + listOf( + AwsRuntimeTypes.Types.AwsClientConfig, + AwsRuntimeTypes.Config.AwsClientConfigLoadOptions, + AwsRuntimeTypes.Config.loadFromEnvironment + ).forEach(writer::addImport) + + write("") + dokka { + write("Construct a [${serviceSymbol.name}] by resolving the configuration from the current environment.") + write("NOTE: If you are constructing multiple clients it is more efficient to construct an") + write("[#Q] and share the configuration across clients.", AwsRuntimeTypes.Types.AwsClientConfig) + } + writer.withBlock( + "suspend fun loadFromEnvironment(block: #1T.() -> Unit = {}): #2T {", + "}", + AwsRuntimeTypes.Config.AwsClientConfigLoadOptions, + serviceSymbol + ) { + write( + "val sharedConfig = #T.#T(block)", + AwsRuntimeTypes.Types.AwsClientConfig, + AwsRuntimeTypes.Config.loadFromEnvironment + ) + write("return #T(sharedConfig)", serviceSymbol) + } + } + } } + override val sectionWriters: List = + listOf(SectionWriterBinding(ServiceGenerator.ServiceInterfaceCompanionObject, overrideServiceCompanionObjectWriter)) + override fun additionalServiceConfigProps(ctx: CodegenContext): List { // we can't construct this without the actual package name due to the generated DefaultEndpointResolver symbol val endpointResolverProperty = ClientConfigProperty { diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt index e4537a57f44..8c8b74b10f2 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt @@ -260,7 +260,6 @@ class PresignerGeneratorTest { */ var region: String? - fun build(): TestPresignConfig } internal class BuilderImpl() : FluentBuilder, DslBuilder { From 80cfa94b7009b3f29fbfd7e354318f2d1ae84b09 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 13:19:23 -0400 Subject: [PATCH 05/10] refactor how region is resolved and fill in load from environment --- .../runtime/config/AwsClientConfigLoader.kt | 38 ++++++++++++++++++- .../region/DefaultRegionProviderChain.kt | 2 +- .../runtime/region/ImdsRegionProvider.kt | 2 +- .../kotlin/runtime/region/ResolveRegion.kt | 32 +++------------- .../config/AwsClientConfigLoaderTest.kt | 28 ++++++++++++++ .../runtime/region/ResolveRegionTest.kt | 31 --------------- .../region/DefaultRegionProviderChainJVM.kt | 2 +- .../runtime/client/AwsAdvancedClientOption.kt | 19 ---------- 8 files changed, 72 insertions(+), 82 deletions(-) create mode 100644 aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/config/AwsClientConfigLoaderTest.kt delete mode 100644 aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/region/ResolveRegionTest.kt delete mode 100644 aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/client/AwsAdvancedClientOption.kt diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt index d36d3ac41f8..607fcdf165f 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt @@ -5,15 +5,31 @@ package aws.sdk.kotlin.runtime.config +import aws.sdk.kotlin.runtime.auth.credentials.CredentialsProvider +import aws.sdk.kotlin.runtime.auth.credentials.DefaultChainCredentialsProvider import aws.sdk.kotlin.runtime.client.AwsClientConfig +import aws.sdk.kotlin.runtime.region.resolveRegion +import aws.smithy.kotlin.runtime.util.Platform +import aws.smithy.kotlin.runtime.util.PlatformProvider /** * Options that control how an [aws.sdk.kotlin.runtime.client.AwsClientConfig] is resolved */ public class AwsClientConfigLoadOptions { - // TODO - see for an idea https://github.com/aws/aws-sdk-go-v2/blob/973e5f5e9477e0690bcb4be3145bb72e956651cc/config/load_options.go#L22 + // TODO - see Go SDK for an idea of possible knobs + // https://github.com/aws/aws-sdk-go-v2/blob/973e5f5e9477e0690bcb4be3145bb72e956651cc/config/load_options.go#L22 // Most of these will not be needed if you are using a corresponding environment variable or system property but there should be an explicit // option to control behavior. + + /** + * The region to make requests to. When set, region will not attempt to be resolved from other sources + */ + public var region: String? = null + + /** + * The [CredentialsProvider] to use when sourcing [aws.sdk.kotlin.runtime.auth.credentials.Credentials]. + */ + public var credentialsProvider: CredentialsProvider? = null } /** @@ -21,4 +37,22 @@ public class AwsClientConfigLoadOptions { */ public suspend fun AwsClientConfig.Companion.loadFromEnvironment( block: AwsClientConfigLoadOptions.() -> Unit = {} -): AwsClientConfig = TODO() +): AwsClientConfig = loadAwsClientConfig(Platform, block) + +internal suspend fun loadAwsClientConfig( + platformProvider: PlatformProvider, + block: AwsClientConfigLoadOptions.() -> Unit +): AwsClientConfig { + val opts = AwsClientConfigLoadOptions().apply(block) + + val region = opts.region ?: resolveRegion(platformProvider) + + val credentialsProvider = opts.credentialsProvider ?: DefaultChainCredentialsProvider() + + return ResolvedAwsConfig(region, credentialsProvider) +} + +private data class ResolvedAwsConfig( + override val region: String, + override val credentialsProvider: CredentialsProvider +) : AwsClientConfig diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChain.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChain.kt index 76998b644d6..d490a5810e3 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChain.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChain.kt @@ -16,6 +16,6 @@ import aws.smithy.kotlin.runtime.util.PlatformProvider * 3. Check the AWS config files/profile for region information * 4. If running on EC2, check the EC2 metadata service for region */ -public expect class DefaultRegionProviderChain public constructor( +internal expect class DefaultRegionProviderChain constructor( platformProvider: PlatformProvider = Platform ) : RegionProvider, Closeable diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ImdsRegionProvider.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ImdsRegionProvider.kt index c064a99ff11..8fd7822cbc9 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ImdsRegionProvider.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ImdsRegionProvider.kt @@ -21,7 +21,7 @@ private const val REGION_PATH: String = "/latest/meta-data/placement/region" * @param client the IMDS client to use to resolve region information with * @param platformProvider the [PlatformEnvironProvider] instance */ -public class ImdsRegionProvider( +internal class ImdsRegionProvider( private val client: Lazy = lazy { ImdsClient() }, private val platformProvider: PlatformEnvironProvider = Platform, ) : RegionProvider, Closeable { diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt index 4025868724e..6e1e2ac6152 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt @@ -6,35 +6,13 @@ package aws.sdk.kotlin.runtime.region import aws.sdk.kotlin.runtime.ClientException -import aws.sdk.kotlin.runtime.InternalSdkApi -import aws.sdk.kotlin.runtime.client.AwsAdvancedClientOption -import aws.sdk.kotlin.runtime.client.AwsClientOption -import aws.smithy.kotlin.runtime.client.ExecutionContext +import aws.smithy.kotlin.runtime.io.use +import aws.smithy.kotlin.runtime.util.PlatformProvider /** * Attempt to resolve the region to make requests to. - * - * Regions are resolved in the following order: - * 1. From the existing [ctx] - * 2. From the region [config] - * 3. Using default region detection (only if-enabled) */ -@InternalSdkApi -public suspend fun resolveRegionForOperation(ctx: ExecutionContext, config: RegionConfig): String { - // favor the context if it's already set - val regionFromCtx = ctx.getOrNull(AwsClientOption.Region) - if (regionFromCtx != null) return regionFromCtx - - // use the default from the service config if configured - if (config.region != null) return config.region!! - - // attempt to detect - val allowDefaultRegionDetect = ctx.getOrNull(AwsAdvancedClientOption.EnableDefaultRegionDetection) ?: true - if (!allowDefaultRegionDetect) { - throw ClientException("No region was configured and region detection has been disabled") +internal suspend fun resolveRegion(platformProvider: PlatformProvider): String = + DefaultRegionProviderChain(platformProvider).use { providerChain -> + providerChain.getRegion() ?: throw ClientException("unable to auto detect AWS region, tried: $providerChain") } - - // TODO - propagate any relevant ctx/config to the default chain - val providerChain = DefaultRegionProviderChain() - return providerChain.getRegion() ?: throw ClientException("unable to auto detect AWS region, tried: $providerChain") -} diff --git a/aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/config/AwsClientConfigLoaderTest.kt b/aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/config/AwsClientConfigLoaderTest.kt new file mode 100644 index 00000000000..020d5a126b7 --- /dev/null +++ b/aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/config/AwsClientConfigLoaderTest.kt @@ -0,0 +1,28 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +package aws.sdk.kotlin.runtime.config + +import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider +import aws.sdk.kotlin.runtime.testing.TestPlatformProvider +import aws.sdk.kotlin.runtime.testing.runSuspendTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class AwsClientConfigLoaderTest { + @Test + fun testExplicit(): Unit = runSuspendTest { + val provider = TestPlatformProvider() + val actual = loadAwsClientConfig(provider) { + region = "us-east-2" + credentialsProvider = StaticCredentialsProvider { + accessKeyId = "AKID" + secretAccessKey = "secret" + } + } + assertEquals("us-east-2", actual.region) + assertEquals("AKID", actual.credentialsProvider.getCredentials().accessKeyId) + } +} diff --git a/aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/region/ResolveRegionTest.kt b/aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/region/ResolveRegionTest.kt deleted file mode 100644 index 2cffb4e5a40..00000000000 --- a/aws-runtime/aws-config/common/test/aws/sdk/kotlin/runtime/region/ResolveRegionTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -package aws.sdk.kotlin.runtime.region - -import aws.sdk.kotlin.runtime.client.AwsClientOption -import aws.sdk.kotlin.runtime.testing.runSuspendTest -import aws.smithy.kotlin.runtime.client.ExecutionContext -import kotlin.test.Test -import kotlin.test.assertEquals - -class ResolveRegionTest { - - @Test - fun testResolutionOrder() = runSuspendTest { - // from context - val config = object : RegionConfig { - override val region: String = "us-west-2" - } - - // context has highest priority - val actual = resolveRegionForOperation(ctx = ExecutionContext().apply { set(AwsClientOption.Region, "us-east-1") }, config) - assertEquals("us-east-1", actual) - - // from config is next - val actual2 = resolveRegionForOperation(ExecutionContext(), config) - assertEquals("us-west-2", actual2) - } -} diff --git a/aws-runtime/aws-config/jvm/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChainJVM.kt b/aws-runtime/aws-config/jvm/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChainJVM.kt index 0f864cb7d0b..a1673e284c9 100644 --- a/aws-runtime/aws-config/jvm/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChainJVM.kt +++ b/aws-runtime/aws-config/jvm/src/aws/sdk/kotlin/runtime/region/DefaultRegionProviderChainJVM.kt @@ -8,7 +8,7 @@ package aws.sdk.kotlin.runtime.region import aws.smithy.kotlin.runtime.io.Closeable import aws.smithy.kotlin.runtime.util.PlatformProvider -public actual class DefaultRegionProviderChain public actual constructor( +internal actual class DefaultRegionProviderChain actual constructor( platformProvider: PlatformProvider ) : RegionProvider, Closeable, diff --git a/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/client/AwsAdvancedClientOption.kt b/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/client/AwsAdvancedClientOption.kt deleted file mode 100644 index 97a173b8c4c..00000000000 --- a/aws-runtime/aws-core/common/src/aws/sdk/kotlin/runtime/client/AwsAdvancedClientOption.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -package aws.sdk.kotlin.runtime.client - -import aws.smithy.kotlin.runtime.client.ClientOption - -/** - * A collection of advanced options that can be configured on an AWS service client - */ -public object AwsAdvancedClientOption { - /** - * Whether region detection should be enabled. Region detection is used when the region is not specified - * when building a client. This is enabled by default. - */ - public val EnableDefaultRegionDetection: ClientOption = ClientOption("EnableDefaultRegionDetection") -} From c9e2979a5298ae0c6c1cbd5105ccead3ec9f28a5 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 13:30:38 -0400 Subject: [PATCH 06/10] change exception type --- .../common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt index 6e1e2ac6152..574cc178888 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/region/ResolveRegion.kt @@ -5,7 +5,7 @@ package aws.sdk.kotlin.runtime.region -import aws.sdk.kotlin.runtime.ClientException +import aws.sdk.kotlin.runtime.ConfigurationException import aws.smithy.kotlin.runtime.io.use import aws.smithy.kotlin.runtime.util.PlatformProvider @@ -14,5 +14,5 @@ import aws.smithy.kotlin.runtime.util.PlatformProvider */ internal suspend fun resolveRegion(platformProvider: PlatformProvider): String = DefaultRegionProviderChain(platformProvider).use { providerChain -> - providerChain.getRegion() ?: throw ClientException("unable to auto detect AWS region, tried: $providerChain") + providerChain.getRegion() ?: throw ConfigurationException("unable to auto detect AWS region, tried: $providerChain") } From 369fe8c9a4a8e0974013872aa0aae9c33ccebc9c Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 14:22:29 -0400 Subject: [PATCH 07/10] render service client config with explicit constructor --- .../aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index e3aab12cecc..9ce008d570d 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -77,6 +77,9 @@ class AwsServiceConfigIntegration : KotlinIntegration { write("return Default${serviceSymbol.name}(config)") } + write("") + write("operator fun invoke(config: Config): ${serviceSymbol.name} = Default${serviceSymbol.name}(config)") + // generate a convenience init to resolve a client from the current environment listOf( AwsRuntimeTypes.Types.AwsClientConfig, From 1736a9a9c607c248af5a15cb1af2e0503c3277b0 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 14:35:35 -0400 Subject: [PATCH 08/10] add future action item --- .../src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt index 607fcdf165f..1bf1864888f 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt @@ -30,6 +30,8 @@ public class AwsClientConfigLoadOptions { * The [CredentialsProvider] to use when sourcing [aws.sdk.kotlin.runtime.auth.credentials.Credentials]. */ public var credentialsProvider: CredentialsProvider? = null + + // FIXME - expose profile name override and thread through region/cred provider chains } /** From 016d56646db60c8ab5b58a702cc9609e19a426b4 Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Tue, 19 Oct 2021 15:38:39 -0400 Subject: [PATCH 09/10] update presign config generation to use new property type capabilities --- .../sdk/kotlin/codegen/PresignerGenerator.kt | 37 ++++------ .../kotlin/codegen/PresignerGeneratorTest.kt | 72 +++++++++---------- 2 files changed, 50 insertions(+), 59 deletions(-) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt index 45f070a4d24..c3529a51f1c 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt @@ -26,7 +26,6 @@ import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes import software.amazon.smithy.kotlin.codegen.model.buildSymbol import software.amazon.smithy.kotlin.codegen.model.expectShape import software.amazon.smithy.kotlin.codegen.model.expectTrait -import software.amazon.smithy.kotlin.codegen.model.namespace import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigGenerator import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigProperty import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigPropertyType @@ -191,26 +190,18 @@ class PresignerGenerator : KotlinIntegration { writer.addImport(AwsRuntimeTypes.Core.ClientException) writer.putContext("configClass.name", presignConfigTypeName) val credentialsProviderProperty = ClientConfigProperty { - symbol = buildSymbol { - name = "CredentialsProvider" - defaultValue = "DefaultChainCredentialsProvider()" - namespace(AwsKotlinDependency.AWS_SIGNING) - nullable = false - } + symbol = AwsRuntimeTypes.Types.CredentialsProvider name = "credentialsProvider" documentation = "The AWS credentials provider to use for authenticating requests. If not provided a [aws.sdk.kotlin.runtime.auth.credentials.DefaultChainCredentialsProvider] instance will be used." baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig + propertyType = ClientConfigPropertyType.RequiredWithDefault("DefaultChainCredentialsProvider()") } val endpointResolverProperty = ClientConfigProperty { - symbol = buildSymbol { - name = "EndpointResolver" - namespace(AwsKotlinDependency.AWS_CORE, "endpoint") - defaultValue = "DefaultEndpointResolver()" - nullable = false - } + symbol = AwsRuntimeTypes.Endpoint.EndpointResolver name = "endpointResolver" documentation = "Determines the endpoint (hostname) to make requests to. When not provided a default resolver is configured automatically. This is an advanced client option." baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig + propertyType = ClientConfigPropertyType.RequiredWithDefault("DefaultEndpointResolver()") } val region = ClientConfigProperty { symbol = buildSymbol { @@ -326,31 +317,31 @@ class PresignerGenerator : KotlinIntegration { ) { writer.dokka { write("Presign a [$requestTypeName] using a [$serviceClientTypeName].") - write("@param serviceClient the client providing properties used to generate the presigned request.") + write("@param config the client configuration used to generate the presigned request.") write("@param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity.") write("@return The [HttpRequest] that can be invoked within the specified time window.") } // FIXME ~ Replace or add additional function, swap ULong type for kotlin.time.Duration when type becomes stable - writer.withBlock("suspend fun $requestTypeName.presign(serviceClient: $serviceClientTypeName, durationSeconds: ULong): HttpRequest {", "}\n") { - withBlock("val serviceClientConfig = $presignConfigTypeName {", "}") { - write("credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider()") - write("endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver()") - write("region = requireNotNull(serviceClient.config.region) { \"Service client must set a region.\" }") + writer.withBlock("suspend fun $requestTypeName.presign(config: $serviceClientTypeName.Config, durationSeconds: ULong): HttpRequest {", "}\n") { + withBlock("val presignConfig = $presignConfigTypeName {", "}") { + write("credentialsProvider = config.credentialsProvider") + write("endpointResolver = config.endpointResolver") + write("region = config.region") } - write("return createPresignedRequest(serviceClientConfig, $requestConfigFnName(this, durationSeconds))") + write("return createPresignedRequest(presignConfig, $requestConfigFnName(this, durationSeconds))") } } private fun renderPresignFromConfigFn(writer: KotlinWriter, requestTypeName: String, requestConfigFnName: String) { writer.dokka { write("Presign a [$requestTypeName] using a [ServicePresignConfig].") - write("@param serviceClientConfig the client configuration used to generate the presigned request") + write("@param presignConfig the configuration used to generate the presigned request") write("@param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity.") write("@return The [HttpRequest] that can be invoked within the specified time window.") } // FIXME ~ Replace or add additional function, swap ULong type for kotlin.time.Duration when type becomes stable - writer.withBlock("suspend fun $requestTypeName.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest {", "}\n") { - write("return createPresignedRequest(serviceClientConfig, $requestConfigFnName(this, durationSeconds))") + writer.withBlock("suspend fun $requestTypeName.presign(presignConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest {", "}\n") { + write("return createPresignedRequest(presignConfig, $requestConfigFnName(this, durationSeconds))") } } diff --git a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt index 8c8b74b10f2..65368882fd8 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/test/kotlin/aws/sdk/kotlin/codegen/PresignerGeneratorTest.kt @@ -107,27 +107,27 @@ class PresignerGeneratorTest { /** * Presign a [GetFooRequest] using a [ServicePresignConfig]. - * @param serviceClientConfig the client configuration used to generate the presigned request + * @param presignConfig the configuration used to generate the presigned request * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun GetFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { - return createPresignedRequest(serviceClientConfig, getFooPresignConfig(this, durationSeconds)) + suspend fun GetFooRequest.presign(presignConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { + return createPresignedRequest(presignConfig, getFooPresignConfig(this, durationSeconds)) } /** * Presign a [GetFooRequest] using a [TestClient]. - * @param serviceClient the client providing properties used to generate the presigned request. + * @param config the client configuration used to generate the presigned request. * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun GetFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): HttpRequest { - val serviceClientConfig = TestPresignConfig { - credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider() - endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver() - region = requireNotNull(serviceClient.config.region) { "Service client must set a region." } + suspend fun GetFooRequest.presign(config: TestClient.Config, durationSeconds: ULong): HttpRequest { + val presignConfig = TestPresignConfig { + credentialsProvider = config.credentialsProvider + endpointResolver = config.endpointResolver + region = config.region } - return createPresignedRequest(serviceClientConfig, getFooPresignConfig(this, durationSeconds)) + return createPresignedRequest(presignConfig, getFooPresignConfig(this, durationSeconds)) } private suspend fun getFooPresignConfig(input: GetFooRequest, durationSeconds: ULong) : PresignedRequestConfig { @@ -145,27 +145,27 @@ class PresignerGeneratorTest { /** * Presign a [PostFooRequest] using a [ServicePresignConfig]. - * @param serviceClientConfig the client configuration used to generate the presigned request + * @param presignConfig the configuration used to generate the presigned request * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PostFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { - return createPresignedRequest(serviceClientConfig, postFooPresignConfig(this, durationSeconds)) + suspend fun PostFooRequest.presign(presignConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { + return createPresignedRequest(presignConfig, postFooPresignConfig(this, durationSeconds)) } /** * Presign a [PostFooRequest] using a [TestClient]. - * @param serviceClient the client providing properties used to generate the presigned request. + * @param config the client configuration used to generate the presigned request. * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PostFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): HttpRequest { - val serviceClientConfig = TestPresignConfig { - credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider() - endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver() - region = requireNotNull(serviceClient.config.region) { "Service client must set a region." } + suspend fun PostFooRequest.presign(config: TestClient.Config, durationSeconds: ULong): HttpRequest { + val presignConfig = TestPresignConfig { + credentialsProvider = config.credentialsProvider + endpointResolver = config.endpointResolver + region = config.region } - return createPresignedRequest(serviceClientConfig, postFooPresignConfig(this, durationSeconds)) + return createPresignedRequest(presignConfig, postFooPresignConfig(this, durationSeconds)) } private suspend fun postFooPresignConfig(input: PostFooRequest, durationSeconds: ULong) : PresignedRequestConfig { @@ -183,27 +183,27 @@ class PresignerGeneratorTest { /** * Presign a [PutFooRequest] using a [ServicePresignConfig]. - * @param serviceClientConfig the client configuration used to generate the presigned request + * @param presignConfig the configuration used to generate the presigned request * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PutFooRequest.presign(serviceClientConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { - return createPresignedRequest(serviceClientConfig, putFooPresignConfig(this, durationSeconds)) + suspend fun PutFooRequest.presign(presignConfig: ServicePresignConfig, durationSeconds: ULong): HttpRequest { + return createPresignedRequest(presignConfig, putFooPresignConfig(this, durationSeconds)) } /** * Presign a [PutFooRequest] using a [TestClient]. - * @param serviceClient the client providing properties used to generate the presigned request. + * @param config the client configuration used to generate the presigned request. * @param durationSeconds the amount of time from signing for which the request is valid, with seconds granularity. * @return The [HttpRequest] that can be invoked within the specified time window. */ - suspend fun PutFooRequest.presign(serviceClient: TestClient, durationSeconds: ULong): HttpRequest { - val serviceClientConfig = TestPresignConfig { - credentialsProvider = serviceClient.config.credentialsProvider ?: DefaultChainCredentialsProvider() - endpointResolver = serviceClient.config.endpointResolver ?: DefaultEndpointResolver() - region = requireNotNull(serviceClient.config.region) { "Service client must set a region." } + suspend fun PutFooRequest.presign(config: TestClient.Config, durationSeconds: ULong): HttpRequest { + val presignConfig = TestPresignConfig { + credentialsProvider = config.credentialsProvider + endpointResolver = config.endpointResolver + region = config.region } - return createPresignedRequest(serviceClientConfig, putFooPresignConfig(this, durationSeconds)) + return createPresignedRequest(presignConfig, putFooPresignConfig(this, durationSeconds)) } private suspend fun putFooPresignConfig(input: PutFooRequest, durationSeconds: ULong) : PresignedRequestConfig { @@ -225,8 +225,8 @@ class PresignerGeneratorTest { * instance is not available. */ class TestPresignConfig private constructor(builder: BuilderImpl): ServicePresignConfig { - override val credentialsProvider: CredentialsProvider = builder.credentialsProvider - override val endpointResolver: EndpointResolver = builder.endpointResolver + override val credentialsProvider: CredentialsProvider = builder.credentialsProvider ?: DefaultChainCredentialsProvider() + override val endpointResolver: EndpointResolver = builder.endpointResolver ?: DefaultEndpointResolver() override val region: String = requireNotNull(builder.region) { "region is a required configuration property" } override val serviceId: String = "example" override val signingName: String = "example-signing-name" @@ -248,12 +248,12 @@ class PresignerGeneratorTest { /** * The AWS credentials provider to use for authenticating requests. If not provided a [aws.sdk.kotlin.runtime.auth.credentials.DefaultChainCredentialsProvider] instance will be used. */ - var credentialsProvider: CredentialsProvider + var credentialsProvider: CredentialsProvider? /** * Determines the endpoint (hostname) to make requests to. When not provided a default resolver is configured automatically. This is an advanced client option. */ - var endpointResolver: EndpointResolver + var endpointResolver: EndpointResolver? /** * AWS region to make requests for @@ -263,8 +263,8 @@ class PresignerGeneratorTest { } internal class BuilderImpl() : FluentBuilder, DslBuilder { - override var credentialsProvider: CredentialsProvider = DefaultChainCredentialsProvider() - override var endpointResolver: EndpointResolver = DefaultEndpointResolver() + override var credentialsProvider: CredentialsProvider? = null + override var endpointResolver: EndpointResolver? = null override var region: String? = null override fun build(): TestPresignConfig = TestPresignConfig(this) From a831ab02585a708a76bca42daa7bad5de07a594e Mon Sep 17 00:00:00 2001 From: Aaron J Todd Date: Thu, 21 Oct 2021 08:57:53 -0400 Subject: [PATCH 10/10] loadFromEnvironment -> fromEnvironment; use additionalImports --- .../runtime/config/AwsClientConfigLoader.kt | 2 +- .../aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt | 2 +- .../codegen/AwsServiceConfigIntegration.kt | 36 +++++++------------ .../sdk/kotlin/codegen/PresignerGenerator.kt | 5 +-- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt index 1bf1864888f..2fd33371398 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsClientConfigLoader.kt @@ -37,7 +37,7 @@ public class AwsClientConfigLoadOptions { /** * Load the AWS client configuration from the environment. */ -public suspend fun AwsClientConfig.Companion.loadFromEnvironment( +public suspend fun AwsClientConfig.Companion.fromEnvironment( block: AwsClientConfigLoadOptions.() -> Unit = {} ): AwsClientConfig = loadAwsClientConfig(Platform, block) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt index 5bffefef5bc..e62cc73e219 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt @@ -54,7 +54,7 @@ object AwsRuntimeTypes { } val AwsClientConfigLoadOptions = runtimeSymbol("AwsClientConfigLoadOptions", AwsKotlinDependency.AWS_CONFIG, "config") - val loadFromEnvironment = runtimeSymbol("loadFromEnvironment", AwsKotlinDependency.AWS_CONFIG, "config") + val fromEnvironment = runtimeSymbol("fromEnvironment", AwsKotlinDependency.AWS_CONFIG, "config") } object Signing { diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index 9ce008d570d..da4c25bed70 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -13,7 +13,6 @@ import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes import software.amazon.smithy.kotlin.codegen.model.boxed import software.amazon.smithy.kotlin.codegen.model.buildSymbol -import software.amazon.smithy.kotlin.codegen.model.namespace import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigProperty import software.amazon.smithy.kotlin.codegen.rendering.ClientConfigPropertyType import software.amazon.smithy.kotlin.codegen.rendering.ServiceGenerator @@ -27,15 +26,10 @@ class AwsServiceConfigIntegration : KotlinIntegration { val CredentialsProviderProp: ClientConfigProperty init { - val awsClientConfigSymbol = buildSymbol { - name = "AwsClientConfig" - namespace(AwsKotlinDependency.AWS_TYPES, subpackage = "client") - } - RegionProp = ClientConfigProperty { name = "region" symbol = KotlinTypes.String.toBuilder().boxed().build() - baseClass = awsClientConfigSymbol + baseClass = AwsRuntimeTypes.Types.AwsClientConfig documentation = """ AWS region to make requests to """.trimIndent() @@ -43,17 +37,16 @@ class AwsServiceConfigIntegration : KotlinIntegration { } CredentialsProviderProp = ClientConfigProperty { - val defaultProvider = AwsRuntimeTypes.Config.Credentials.DefaultChainCredentialsProvider - symbol = AwsRuntimeTypes.Types.CredentialsProvider.toBuilder() - .addReference(defaultProvider) - .build() - baseClass = awsClientConfigSymbol + symbol = AwsRuntimeTypes.Types.CredentialsProvider + baseClass = AwsRuntimeTypes.Types.AwsClientConfig documentation = """ The AWS credentials provider to use for authenticating requests. If not provided a [${symbol?.namespace}.DefaultChainCredentialsProvider] instance will be used. """.trimIndent() + val defaultProvider = AwsRuntimeTypes.Config.Credentials.DefaultChainCredentialsProvider propertyType = ClientConfigPropertyType.RequiredWithDefault("${defaultProvider.name}()") + additionalImports = listOf(defaultProvider) } } @@ -84,17 +77,17 @@ class AwsServiceConfigIntegration : KotlinIntegration { listOf( AwsRuntimeTypes.Types.AwsClientConfig, AwsRuntimeTypes.Config.AwsClientConfigLoadOptions, - AwsRuntimeTypes.Config.loadFromEnvironment + AwsRuntimeTypes.Config.fromEnvironment ).forEach(writer::addImport) write("") dokka { write("Construct a [${serviceSymbol.name}] by resolving the configuration from the current environment.") - write("NOTE: If you are constructing multiple clients it is more efficient to construct an") - write("[#Q] and share the configuration across clients.", AwsRuntimeTypes.Types.AwsClientConfig) + write("NOTE: If you are using multiple AWS service clients you may wish to share the configuration among them") + write("by constructing a [#Q] and passing it to each client at construction.", AwsRuntimeTypes.Types.AwsClientConfig) } writer.withBlock( - "suspend fun loadFromEnvironment(block: #1T.() -> Unit = {}): #2T {", + "suspend fun fromEnvironment(block: #1T.() -> Unit = {}): #2T {", "}", AwsRuntimeTypes.Config.AwsClientConfigLoadOptions, serviceSymbol @@ -102,7 +95,7 @@ class AwsServiceConfigIntegration : KotlinIntegration { write( "val sharedConfig = #T.#T(block)", AwsRuntimeTypes.Types.AwsClientConfig, - AwsRuntimeTypes.Config.loadFromEnvironment + AwsRuntimeTypes.Config.fromEnvironment ) write("return #T(sharedConfig)", serviceSymbol) } @@ -126,14 +119,9 @@ class AwsServiceConfigIntegration : KotlinIntegration { name = EndpointResolverGenerator.typeName namespace = "${ctx.settings.pkg.name}.internal" } - - symbol = buildSymbol { - name = "EndpointResolver" - namespace(AwsKotlinDependency.AWS_CORE, subpackage = "endpoint") - reference(defaultResolver) - } - + symbol = AwsRuntimeTypes.Endpoint.EndpointResolver propertyType = ClientConfigPropertyType.RequiredWithDefault("${defaultResolver.name}()") + additionalImports = listOf(defaultResolver) } return listOf(RegionProp, CredentialsProviderProp, endpointResolverProperty) diff --git a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt index c3529a51f1c..5a471e7c570 100644 --- a/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt +++ b/codegen/smithy-aws-kotlin-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/PresignerGenerator.kt @@ -34,6 +34,7 @@ import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpBindingResol import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpTraitResolver import software.amazon.smithy.kotlin.codegen.rendering.protocol.hasHttpBody import software.amazon.smithy.kotlin.codegen.rendering.serde.serializerName +import software.amazon.smithy.kotlin.codegen.utils.dq import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId @@ -219,14 +220,14 @@ class PresignerGenerator : KotlinIntegration { name = "signingName" documentation = "Service identifier used to sign requests" baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig - propertyType = ClientConfigPropertyType.ConstantValue(""""$sigv4ServiceName"""") + propertyType = ClientConfigPropertyType.ConstantValue(sigv4ServiceName.dq()) } val serviceIdProperty = ClientConfigProperty { symbol = KotlinTypes.String name = "serviceId" documentation = "Service identifier used to resolve endpoints" baseClass = AwsRuntimeTypes.Signing.ServicePresignConfig - propertyType = ClientConfigPropertyType.ConstantValue(""""$serviceId"""") + propertyType = ClientConfigPropertyType.ConstantValue(serviceId.dq()) } val ccg = ClientConfigGenerator(