Unverified Commit 84ed110f authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Add Endpoint Resolver Implementation (#2030)

* Add Endpoint Resolver Implementation

This commit adds `EndpointDecorator`, standard libary + tests that can be used to add endpoints 2.0 to the AWS SDK.

It _does not_ actually wire these things up. We'll follow up with a PR that actually integrates everything.

* CR Feedback

* CR feedback II
parent 7c86ecfc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ impl ResolveEndpoint<Params> for EndpointShim {
                    .ok_or_else(|| ResolveEndpointError::message("no region in params"))?,
            )
            .map_err(|err| {
                ResolveEndpointError::message("failure resolving endpoint").with_source(err)
                ResolveEndpointError::message("failure resolving endpoint").with_source(Some(err))
            })?;
        let uri = aws_endpoint.endpoint().uri();
        let mut auth_scheme =
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package software.amazon.smithy.rustsdk

import software.amazon.smithy.model.node.Node
import software.amazon.smithy.model.node.ObjectNode
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.CustomRuntimeFunction
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rulesgen.awsStandardLib
import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ClientProtocolGenerator
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
import kotlin.io.path.readText

/**
 * Standard library functions for AWS-specific endpoint standard library functions.
 *
 * This decorator uses partitions.json to source a default partition map for the partition resolver (when used).
 *
 * For test purposes, [awsStandardLib] can be used directly with a manually supplied partitions.json
 */
class AwsEndpointsStdLib() : RustCodegenDecorator<ClientProtocolGenerator, ClientCodegenContext> {
    private var partitionsCache: ObjectNode? = null
    override val name: String = "AwsEndpointsStdLib"
    override val order: Byte = 0

    override fun supportsCodegenContext(clazz: Class<out CodegenContext>): Boolean {
        return clazz.isAssignableFrom(ClientCodegenContext::class.java)
    }

    private fun partitionMetadata(sdkSettings: SdkSettings): ObjectNode {
        if (partitionsCache == null) {
            val partitionsJson = when (val path = sdkSettings.partitionsConfigPath) {
                null -> (
                    javaClass.getResource("/default-partitions.json")
                        ?: throw IllegalStateException("Failed to find default-partitions.json in the JAR")
                    ).readText()

                else -> path.readText()
            }
            partitionsCache = Node.parse(partitionsJson).expectObjectNode()
        }
        return partitionsCache!!
    }

    override fun endpointCustomizations(codegenContext: ClientCodegenContext): List<EndpointCustomization> {
        return listOf<EndpointCustomization>(
            object : EndpointCustomization {
                override fun customRuntimeFunctions(codegenContext: ClientCodegenContext): List<CustomRuntimeFunction> {
                    val sdkSettings = SdkSettings.from(codegenContext.settings)
                    return awsStandardLib(codegenContext.runtimeConfig, partitionMetadata(sdkSettings))
                }
            },
        )
    }
}
+9 −8
Original line number Diff line number Diff line
@@ -10,7 +10,8 @@ import software.amazon.smithy.rulesengine.language.syntax.parameters.Builtins
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.RulesEngineBuiltInResolver
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.CustomRuntimeFunction
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.ClientProtocolGenerator
@@ -100,18 +101,18 @@ class RegionDecorator : RustCodegenDecorator<ClientProtocolGenerator, ClientCode
        return baseCustomizations + PubUseRegion(codegenContext.runtimeConfig)
    }

    override fun builtInResolvers(codegenContext: ClientCodegenContext): List<RulesEngineBuiltInResolver> {
    override fun endpointCustomizations(codegenContext: ClientCodegenContext): List<EndpointCustomization> {
        return listOf(
            object : RulesEngineBuiltInResolver {
                override fun defaultFor(
                    parameter: Parameter,
                    configRef: String,
                ): Writable? {
            object : EndpointCustomization {
                override fun builtInDefaultValue(parameter: Parameter, configRef: String): Writable? {
                    return when (parameter) {
                        Builtins.REGION -> writable { rust("$configRef.region.as_ref().map(|r|r.as_ref())") }
                        Builtins.REGION -> writable { rust("$configRef.region.as_ref().map(|r|r.as_ref().to_owned())") }
                        else -> null
                    }
                }

                override fun customRuntimeFunctions(codegenContext: ClientCodegenContext): List<CustomRuntimeFunction> =
                    listOf()
            },
        )
    }
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,11 @@ class SdkSettings private constructor(private val awsSdk: ObjectNode?) {
        get() =
            awsSdk?.getStringMember("endpointsConfigPath")?.orNull()?.value?.let { Paths.get(it) }

    /** Path to the `default-partitions.json` configuration */
    val partitionsConfigPath: Path?
        get() =
            awsSdk?.getStringMember("partitionsConfigPath")?.orNull()?.value?.let { Paths.get(it) }

    /** Path to AWS SDK integration tests */
    val integrationTestPath: String
        get() =
+105 −0
Original line number Diff line number Diff line
{
  "version": "1.1",
  "partitions": [
    {
      "id": "aws",
      "regionRegex": "^(us|eu|ap|sa|ca|me|af)-\\w+-\\d+$",
      "regions": {
        "af-south-1": {},
        "ap-east-1": {},
        "ap-northeast-1": {},
        "ap-northeast-2": {},
        "ap-northeast-3": {},
        "ap-south-1": {},
        "ap-southeast-1": {},
        "ap-southeast-2": {},
        "ap-southeast-3": {},
        "ca-central-1": {},
        "eu-central-1": {},
        "eu-north-1": {},
        "eu-south-1": {},
        "eu-west-1": {},
        "eu-west-2": {},
        "eu-west-3": {},
        "me-central-1": {},
        "me-south-1": {},
        "sa-east-1": {},
        "us-east-1": {},
        "us-east-2": {},
        "us-west-1": {},
        "us-west-2": {},
        "aws-global": {}
      },
      "outputs": {
        "name": "aws",
        "dnsSuffix": "amazonaws.com",
        "dualStackDnsSuffix": "api.aws",
        "supportsFIPS": true,
        "supportsDualStack": true
      }
    },
    {
      "id": "aws-us-gov",
      "regionRegex": "^us\\-gov\\-\\w+\\-\\d+$",
      "regions": {
        "us-gov-west-1": {},
        "us-gov-east-1": {},
        "aws-us-gov-global": {}
      },
      "outputs": {
        "name": "aws-us-gov",
        "dnsSuffix": "amazonaws.com",
        "dualStackDnsSuffix": "api.aws",
        "supportsFIPS": true,
        "supportsDualStack": true
      }
    },
    {
      "id": "aws-cn",
      "regionRegex": "^cn\\-\\w+\\-\\d+$",
      "regions": {
        "cn-north-1": {},
        "cn-northwest-1": {},
        "aws-cn-global": {}
      },
      "outputs": {
        "name": "aws-cn",
        "dnsSuffix": "amazonaws.com.cn",
        "dualStackDnsSuffix": "api.amazonwebservices.com.cn",
        "supportsFIPS": true,
        "supportsDualStack": true
      }
    },
    {
      "id": "aws-iso",
      "regionRegex": "^us\\-iso\\-\\w+\\-\\d+$",
      "outputs": {
        "name": "aws-iso",
        "dnsSuffix": "c2s.ic.gov",
        "supportsFIPS": true,
        "supportsDualStack": false,
        "dualStackDnsSuffix": "c2s.ic.gov"
      },
      "regions": {
        "us-iso-east-1":  {},
        "us-iso-west-1": {},
        "aws-iso-global": {}
      }
    },
    {
      "id": "aws-iso-b",
      "regionRegex": "^us\\-isob\\-\\w+\\-\\d+$",
      "outputs": {
        "name": "aws-iso-b",
        "dnsSuffix": "sc2s.sgov.gov",
        "supportsFIPS": true,
        "supportsDualStack": false,
        "dualStackDnsSuffix": "sc2s.sgov.gov"
      },
      "regions": {
        "us-isob-east-1": {},
        "aws-iso-b-global": {}
      }
    }
  ]
}
Loading