Skip to content

Commit

Permalink
fix: Add service client version to user-agent (#1812)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbelkins authored Nov 6, 2024
1 parent 30c7bf8 commit 5540683
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,7 @@ private func target(_ service: String) -> Target {
.awsSDKEventStreamsAuth,
.awsSDKChecksums,
],
path: "Sources/Services/\(service)/Sources/\(service)",
resources: [.process("Resources")]
path: "Sources/Services/\(service)/Sources/\(service)"
)
}

Expand Down
3 changes: 1 addition & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,7 @@ private func target(_ service: String) -> Target {
.awsSDKEventStreamsAuth,
.awsSDKChecksums,
],
path: "Sources/Services/\(service)/Sources/\(service)",
resources: [.process("Resources")]
path: "Sources/Services/\(service)/Sources/\(service)"
)
}

Expand Down
3 changes: 0 additions & 3 deletions ServiceClientVersions.json

This file was deleted.

40 changes: 10 additions & 30 deletions codegen/sdk-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
// This build file has been adapted from the Go v2 SDK, here:
// https://github.com/aws/aws-sdk-go-v2/blob/master/codegen/sdk-codegen/build.gradle.kts

import org.jetbrains.kotlin.com.google.common.primitives.Chars
import software.amazon.smithy.gradle.tasks.SmithyBuild
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.node.Node
import software.amazon.smithy.model.shapes.ServiceShape
import java.nio.charset.Charset
import java.util.Properties
Expand Down Expand Up @@ -65,20 +63,6 @@ fun getProperty(name: String): String? {
return null
}

// TODO: Update this list with more services (currently just services with integration tests)
val interceptorsServices = setOf<String>(
"AWSCloudFrontKeyValueStore",
"AWSEC2",
"AWSECS",
"AWSEventBridge",
"AWSKinesis",
"AWSMediaConvert",
"AWSRoute53",
"AWSS3",
"AWSSQS",
"AWSTranscribeStreaming",
)

// Represents information needed to generate a smithy projection JSON stanza
data class AwsService(
val name: String,
Expand All @@ -97,7 +81,6 @@ fun generateSmithyBuild(services: List<AwsService>): String {
require(services.isNotEmpty()) {
"No services discovered. Verify aws.services and aws.protocols properties in local.build. Aborting."
}
val buildStandaloneSdk = getProperty("buildStandaloneSdk")?.toBoolean() ?: false
val projections = services.joinToString(",") { service ->
// escape windows paths for valid json
val absModelPath = service.modelFile.absolutePath.replace("\\", "\\\\")
Expand All @@ -119,9 +102,6 @@ fun generateSmithyBuild(services: List<AwsService>): String {
"author": "Amazon Web Services",
"gitRepo": "${service.gitRepo}",
"swiftVersion": "5.9.0",
"build": {
"rootProject": $buildStandaloneSdk
},
"mergeModels": true,
"copyrightNotice": "//\n// Copyright Amazon.com Inc. or its affiliates.\n// All Rights Reserved.\n//\n// SPDX-License-Identifier: Apache-2.0\n//\n\n// Code generated by smithy-swift-codegen. DO NOT EDIT!\n\n"
}
Expand Down Expand Up @@ -160,24 +140,22 @@ fun discoverServices(): List<AwsService> {

return filteredModels
.map { file ->
val model = Model.assembler().addImport(file.absolutePath).assemble().result.get()
val services: List<ServiceShape> = model.shapes(ServiceShape::class.java).sorted().toList()
require(services.size == 1) { "Expected one service per aws model, but found ${services.size} in ${file.absolutePath}: ${services.map { it.id }}" }
val service = services.first()
file to service
}.map{ (file, service) ->
val model = Model.assembler().addImport(file.absolutePath).assemble().result.get()
val services: List<ServiceShape> = model.shapes(ServiceShape::class.java).sorted().toList()
require(services.size == 1) { "Expected one service per aws model, but found ${services.size} in ${file.absolutePath}: ${services.map { it.id }}" }
val service = services.first()
file to service
}.map { (file, service) ->
val serviceApi = service.getTrait(software.amazon.smithy.aws.traits.ServiceTrait::class.java).orNull()
?: error { "Expected aws.api#service trait attached to model ${file.absolutePath}" }
val (name, version, _) = file.name.split(".")
val serviceClientVersions = Node.parse(rootProject.file("ServiceClientVersions.json").readText(Charset.forName("UTF-8")))
val packageVersion = serviceClientVersions.expectObjectNode().getStringMember(name).orNull()?.value ?:
serviceClientVersions.expectObjectNode().getStringMember("sdk").get().value
val packageName = "AWS${serviceApi.sdkId.filterNot { it.isWhitespace() }.capitalize()}"

logger.info("discovered service: ${serviceApi.sdkId}")

AwsService(
name = service.id.toString(),
packageName = "AWS${serviceApi.sdkId.filterNot { it.isWhitespace() }.capitalize()}",
packageName = packageName,
packageVersion = packageVersion,
modelFile = file,
projectionName = name + "." + version.toLowerCase(),
Expand All @@ -187,6 +165,8 @@ fun discoverServices(): List<AwsService> {
}
val discoveredServices: List<AwsService> by lazy { discoverServices() }

val packageVersion = rootProject.file("Package.version.next").readText(Charset.forName("UTF-8")).trim()

val AwsService.outputDir: String
get() = project.file("${project.buildDir}/smithyprojections/${project.name}/${projectionName}/swift-codegen").absolutePath

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,14 @@ class UserAgentMiddleware(val settings: SwiftSettings) : MiddlewareRenderable {
writer: SwiftWriter,
op: OperationShape
) {
val params = middlewareParamsString(writer)
val input = MiddlewareShapeUtils.inputSymbol(ctx.symbolProvider, ctx.model, op)
val output = MiddlewareShapeUtils.outputSymbol(ctx.symbolProvider, ctx.model, op)
writer.write(
"\$N<\$N, \$N>($params)",
"\$N<\$N, \$N>(serviceID: serviceName, version: \$L.version, config: config)",
AWSClientRuntimeTypes.Core.UserAgentMiddleware,
input,
output
)
}

private fun middlewareParamsString(writer: SwiftWriter): String {
return writer.format(
"serviceID: serviceName, version: \$S, config: config",
settings.moduleVersion,
output,
ctx.symbolProvider.toSymbol(ctx.service).name,
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,4 @@ software.amazon.smithy.aws.swift.codegen.model.AWSDeprecatedShapeRemover
software.amazon.smithy.aws.swift.codegen.AWSClientConfigurationIntegration
software.amazon.smithy.swift.codegen.swiftintegrations.InitialRequestIntegration
software.amazon.smithy.aws.swift.codegen.swiftintegrations.RegistryConfigIntegration
software.amazon.smithy.aws.swift.codegen.swiftintegrations.PackageVersionIntegration
software.amazon.smithy.aws.swift.codegen.swiftintegrations.AmzSdkRetryHeadersIntegration
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ extension GetFooInput {
builder.applySigner(ClientRuntime.SignerMiddleware<GetFooOutput>())
let endpointParams = EndpointParams()
builder.applyEndpoint(AWSClientRuntime.EndpointResolverMiddleware<GetFooOutput, EndpointParams>(endpointResolverBlock: { [config] in try config.endpointResolver.resolve(params: ${'$'}0) }, endpointParams: endpointParams))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<GetFooInput, GetFooOutput>(serviceID: serviceName, version: "1.0.0", config: config))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<GetFooInput, GetFooOutput>(serviceID: serviceName, version: ExampleClient.version, config: config))
builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware<GetFooOutput>())
var metricsAttributes = Smithy.Attributes()
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "Example")
Expand Down Expand Up @@ -127,7 +127,7 @@ extension PostFooInput {
builder.applySigner(ClientRuntime.SignerMiddleware<PostFooOutput>())
let endpointParams = EndpointParams()
builder.applyEndpoint(AWSClientRuntime.EndpointResolverMiddleware<PostFooOutput, EndpointParams>(endpointResolverBlock: { [config] in try config.endpointResolver.resolve(params: ${'$'}0) }, endpointParams: endpointParams))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<PostFooInput, PostFooOutput>(serviceID: serviceName, version: "1.0.0", config: config))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<PostFooInput, PostFooOutput>(serviceID: serviceName, version: ExampleClient.version, config: config))
builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware<PostFooOutput>())
var metricsAttributes = Smithy.Attributes()
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "Example")
Expand Down Expand Up @@ -199,7 +199,7 @@ extension PutFooInput {
builder.applySigner(ClientRuntime.SignerMiddleware<PutFooOutput>())
let endpointParams = EndpointParams()
builder.applyEndpoint(AWSClientRuntime.EndpointResolverMiddleware<PutFooOutput, EndpointParams>(endpointResolverBlock: { [config] in try config.endpointResolver.resolve(params: ${'$'}0) }, endpointParams: endpointParams))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<PutFooInput, PutFooOutput>(serviceID: serviceName, version: "1.0.0", config: config))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<PutFooInput, PutFooOutput>(serviceID: serviceName, version: ExampleClient.version, config: config))
builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware<PutFooOutput>())
var metricsAttributes = Smithy.Attributes()
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "Example")
Expand Down Expand Up @@ -272,7 +272,7 @@ extension PutObjectInput {
let endpointParams = EndpointParams()
context.attributes.set(key: Smithy.AttributeKey<EndpointParams>(name: "EndpointParams"), value: endpointParams)
builder.applyEndpoint(AWSClientRuntime.EndpointResolverMiddleware<PutObjectOutput, EndpointParams>(endpointResolverBlock: { [config] in try config.endpointResolver.resolve(params: ${'$'}0) }, endpointParams: endpointParams))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<PutObjectInput, PutObjectOutput>(serviceID: serviceName, version: "1.0.0", config: config))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<PutObjectInput, PutObjectOutput>(serviceID: serviceName, version: S3Client.version, config: config))
builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware<PutObjectOutput>())
var metricsAttributes = Smithy.Attributes()
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "S3")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,24 @@ class AWSQueryOperationStackTest {
builder.applySigner(ClientRuntime.SignerMiddleware<NoInputAndOutputOutput>())
let endpointParams = EndpointParams()
builder.applyEndpoint(AWSClientRuntime.EndpointResolverMiddleware<NoInputAndOutputOutput, EndpointParams>(endpointResolverBlock: { [config] in try config.endpointResolver.resolve(params: ${'$'}0) }, endpointParams: endpointParams))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<NoInputAndOutputInput, NoInputAndOutputOutput>(serviceID: serviceName, version: "1.0.0", config: config))
builder.interceptors.add(AWSClientRuntime.UserAgentMiddleware<NoInputAndOutputInput, NoInputAndOutputOutput>(serviceID: serviceName, version: QueryProtocolClient.version, config: config))
builder.serialize(ClientRuntime.BodyMiddleware<NoInputAndOutputInput, NoInputAndOutputOutput, SmithyFormURL.Writer>(rootNodeInfo: "", inputWritingClosure: NoInputAndOutputInput.write(value:to:)))
builder.interceptors.add(ClientRuntime.ContentTypeMiddleware<NoInputAndOutputInput, NoInputAndOutputOutput>(contentType: "application/x-www-form-urlencoded"))
builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware<NoInputAndOutputOutput>())
builder.interceptors.add(AWSClientRuntime.AmzSdkInvocationIdMiddleware<NoInputAndOutputInput, NoInputAndOutputOutput>())
builder.interceptors.add(AWSClientRuntime.AmzSdkRequestMiddleware<NoInputAndOutputInput, NoInputAndOutputOutput>(maxRetries: config.retryStrategyOptions.maxRetriesBase))
var metricsAttributes = Smithy.Attributes()
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "QueryProtocol")
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.method, value: "NoInputAndOutput")
let op = builder.attributes(context)
.telemetry(ClientRuntime.OrchestratorTelemetry(
telemetryProvider: config.telemetryProvider,
metricsAttributes: metricsAttributes,
meterScope: serviceName,
tracerScope: serviceName
))
.executeRequest(client)
.build()
"""
contents.shouldContainOnlyOnce(expectedContents)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ extension ExplicitBlobInput {
val expectedContents = """
public class ExampleClient: ClientRuntime.Client {
public static let clientName = "ExampleClient"
public static let version = "1.0.0"
let client: ClientRuntime.SdkHttpClient
let config: ExampleClient.ExampleClientConfiguration
let serviceName = "Example"
Expand Down

0 comments on commit 5540683

Please sign in to comment.