diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 05fa4cd30f391f6cfa3a77eb42ad6a388913ade9..69f79589ca7058f8d8261e9a9e4e1271cde143ed 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -37,3 +37,13 @@ message = "Fix RustWriter bugs for `rustTemplate` and `docs` utility methods" references = ["smithy-rs#1427", "smithy-rs#1465", "smithy-rs#1459"] meta = { "breaking" = false, "tada" = false, "bug" = true } author = "rcoh" + +[[smithy-rs]] +message = """ +Requests to Route53 that return `ResourceId`s often come with a prefix. When passing those IDs directly into another +request, the request would fail unless they manually stripped the prefix. Now, when making a request with a prefixed ID, +the prefix will be stripped automatically. +""" +references = ["aws-sdk-rust#554"] +meta = { "breaking" = false, "tada" = false, "bug" = true } +author = "Velfi" diff --git a/aws/rust-runtime/aws-inlineable/src/hosted_zone_preprocessor.rs b/aws/rust-runtime/aws-inlineable/src/hosted_zone_preprocessor.rs deleted file mode 100644 index 0bfd184e42226159ace6266e6739c6ba0385fdca..0000000000000000000000000000000000000000 --- a/aws/rust-runtime/aws-inlineable/src/hosted_zone_preprocessor.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -/// Strip the /hostedzone/ prefix from zone-id -pub fn trim_hosted_zone(zone: &mut Option) { - const PREFIXES: &[&str; 2] = &["/hostedzone/", "hostedzone/"]; - - for prefix in PREFIXES { - if let Some(core_zone) = zone.as_deref().unwrap_or_default().strip_prefix(prefix) { - *zone = Some(core_zone.to_string()); - return; - } - } -} - -#[cfg(test)] -mod test { - use crate::hosted_zone_preprocessor::trim_hosted_zone; - - struct OperationInput { - hosted_zone: Option, - } - - #[test] - fn does_not_change_regular_zones() { - let mut operation = OperationInput { - hosted_zone: Some("Z0441723226OZ66S5ZCNZ".to_string()), - }; - trim_hosted_zone(&mut operation.hosted_zone); - assert_eq!( - &operation.hosted_zone.unwrap_or_default(), - "Z0441723226OZ66S5ZCNZ" - ); - } - - #[test] - fn sanitizes_prefixed_zone() { - let mut operation = OperationInput { - hosted_zone: Some("/hostedzone/Z0441723226OZ66S5ZCNZ".to_string()), - }; - trim_hosted_zone(&mut operation.hosted_zone); - assert_eq!( - &operation.hosted_zone.unwrap_or_default(), - "Z0441723226OZ66S5ZCNZ" - ); - } - - #[test] - fn allow_no_leading_slash() { - let mut operation = OperationInput { - hosted_zone: Some("hostedzone/Z0441723226OZ66S5ZCNZ".to_string()), - }; - trim_hosted_zone(&mut operation.hosted_zone); - assert_eq!( - &operation.hosted_zone.unwrap_or_default(), - "Z0441723226OZ66S5ZCNZ" - ); - } -} diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs index 567722714068aa8eff2c42b1487887906ba616c4..76b285f7088d3af6f9f8accefcb661d62c59491a 100644 --- a/aws/rust-runtime/aws-inlineable/src/lib.rs +++ b/aws/rust-runtime/aws-inlineable/src/lib.rs @@ -33,5 +33,5 @@ pub mod glacier_checksums; /// Default middleware stack for AWS services pub mod middleware; -/// Strip `hostedzone/` from hosted zone ids -pub mod hosted_zone_preprocessor; +/// Strip prefixes from IDs returned by Route53 operations when those IDs are used to construct requests +pub mod route53_resource_id_preprocessor; diff --git a/aws/rust-runtime/aws-inlineable/src/route53_resource_id_preprocessor.rs b/aws/rust-runtime/aws-inlineable/src/route53_resource_id_preprocessor.rs new file mode 100644 index 0000000000000000000000000000000000000000..b1827f065acfebb56d048a80bf4fc5980ce944e3 --- /dev/null +++ b/aws/rust-runtime/aws-inlineable/src/route53_resource_id_preprocessor.rs @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +// This function is only used to strip prefixes from resource IDs at the time they're passed as +// input to a request. Resource IDs returned in responses may or may not include a prefix. +/// Strip the resource type prefix from resource ID return +pub fn trim_resource_id(resource_id: &mut Option) { + const PREFIXES: &[&str] = &[ + "/hostedzone/", + "hostedzone/", + "/change/", + "change/", + "/delegationset/", + "delegationset/", + ]; + + for prefix in PREFIXES { + if let Some(id) = resource_id + .as_deref() + .unwrap_or_default() + .strip_prefix(prefix) + { + *resource_id = Some(id.to_string()); + return; + } + } +} + +#[cfg(test)] +mod test { + use crate::route53_resource_id_preprocessor::trim_resource_id; + + #[test] + fn does_not_change_regular_zones() { + struct OperationInput { + resource: Option, + } + + let mut operation = OperationInput { + resource: Some("Z0441723226OZ66S5ZCNZ".to_string()), + }; + trim_resource_id(&mut operation.resource); + assert_eq!( + &operation.resource.unwrap_or_default(), + "Z0441723226OZ66S5ZCNZ" + ); + } + + #[test] + fn sanitizes_prefixed_zone() { + struct OperationInput { + change_id: Option, + } + + let mut operation = OperationInput { + change_id: Some("/change/Z0441723226OZ66S5ZCNZ".to_string()), + }; + trim_resource_id(&mut operation.change_id); + assert_eq!( + &operation.change_id.unwrap_or_default(), + "Z0441723226OZ66S5ZCNZ" + ); + } + + #[test] + fn allow_no_leading_slash() { + struct OperationInput { + hosted_zone: Option, + } + + let mut operation = OperationInput { + hosted_zone: Some("hostedzone/Z0441723226OZ66S5ZCNZ".to_string()), + }; + trim_resource_id(&mut operation.hosted_zone); + assert_eq!( + &operation.hosted_zone.unwrap_or_default(), + "Z0441723226OZ66S5ZCNZ" + ); + } +} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt index 7a0338fb4f29b0a1ab1c0117983328fdb40df257..ff8b617ae4ffa542e6903400e4616528e08b3ea0 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt @@ -37,9 +37,9 @@ class Route53Decorator : RustCodegenDecorator { override fun transformModel(service: ServiceShape, model: Model): Model { return model.letIf(applies(service)) { ModelTransformer.create().mapShapes(model) { shape -> - shape.letIf(isHostId(shape)) { - logger.info("Adding TrimHostedZone trait to $shape") - (shape as MemberShape).toBuilder().addTrait(TrimHostedZone()).build() + shape.letIf(isResourceId(shape)) { + logger.info("Adding TrimResourceId trait to $shape") + (shape as MemberShape).toBuilder().addTrait(TrimResourceId()).build() } } } @@ -50,29 +50,35 @@ class Route53Decorator : RustCodegenDecorator { operation: OperationShape, baseCustomizations: List ): List { - val hostedZoneMember = operation.inputShape(codegenContext.model).members().find { it.hasTrait() } + val hostedZoneMember = + operation.inputShape(codegenContext.model).members().find { it.hasTrait() } return if (hostedZoneMember != null) { - baseCustomizations + TrimHostedZoneCustomization(codegenContext.symbolProvider.toMemberName(hostedZoneMember)) + baseCustomizations + TrimResourceIdCustomization(codegenContext.symbolProvider.toMemberName(hostedZoneMember)) } else baseCustomizations } - private fun isHostId(shape: Shape): Boolean { + private fun isResourceId(shape: Shape): Boolean { return (shape is MemberShape && shape.target == ShapeId.from("com.amazonaws.route53#ResourceId")) && shape.hasTrait() } } -class TrimHostedZoneCustomization(private val fieldName: String) : OperationCustomization() { +class TrimResourceIdCustomization(private val fieldName: String) : OperationCustomization() { override fun mutSelf(): Boolean = true override fun consumesSelf(): Boolean = true - private val trimZone = - RuntimeType.forInlineDependency(InlineAwsDependency.forRustFile("hosted_zone_preprocessor")) - .member("trim_hosted_zone") + private val trimResourceId = + RuntimeType.forInlineDependency( + InlineAwsDependency.forRustFile("route53_resource_id_preprocessor") + ) + .member("trim_resource_id") override fun section(section: OperationSection): Writable { return when (section) { is OperationSection.MutateInput -> writable { - rustTemplate("#{trim_hosted_zone}(&mut ${section.input}.$fieldName);", "trim_hosted_zone" to trimZone) + rustTemplate( + "#{trim_resource_id}(&mut ${section.input}.$fieldName);", + "trim_resource_id" to trimResourceId + ) } else -> emptySection } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/TrimHostedZone.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/TrimResourceId.kt similarity index 63% rename from aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/TrimHostedZone.kt rename to aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/TrimResourceId.kt index 59a4bb6871a5cf162aa83ae6be2655bb2b54c15b..1c61667feae3076a488177e74ef9d95734c8de6f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/TrimHostedZone.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/TrimResourceId.kt @@ -10,10 +10,10 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.AnnotationTrait /** - * Indicates that a member should have the `hostedzone` prefix stripped + * Indicates that a member should have their resource ID prefix stripped */ -class TrimHostedZone() : AnnotationTrait(ID, Node.objectNode()) { +class TrimResourceId() : AnnotationTrait(ID, Node.objectNode()) { companion object { - val ID = ShapeId.from("aws.api.internal#trimHostedZone") + val ID: ShapeId = ShapeId.from("aws.api.internal#trimResourceId") } } diff --git a/aws/sdk/aws-models/route53-tests.smithy b/aws/sdk/aws-models/route53-tests.smithy index d55d67d0bb028d78367f08dab31b53f0ad7a7b30..36e3e234ef951d6c7f60a0c41bd3f1f8585ae8f9 100644 --- a/aws/sdk/aws-models/route53-tests.smithy +++ b/aws/sdk/aws-models/route53-tests.smithy @@ -7,8 +7,8 @@ use smithy.test#httpRequestTests apply ListResourceRecordSets @httpRequestTests([ { - id: "ListResourceRecordSetsTrimHostdZone", - documentation: "This test validates that that hosted zone is correctly trimmed", + id: "ListResourceRecordSetsTrimHostedZone", + documentation: "This test validates that hosted zone is correctly trimmed", method: "GET", protocol: "aws.protocols#restXml", uri: "/2013-04-01/hostedzone/IDOFMYHOSTEDZONE/rrset", @@ -18,3 +18,31 @@ apply ListResourceRecordSets @httpRequestTests([ } } ]) + +apply GetChange @httpRequestTests([ + { + id: "GetChangeTrimChangeId", + documentation: "This test validates that change id is correctly trimmed", + method: "GET", + protocol: "aws.protocols#restXml", + uri: "/2013-04-01/change/SOMECHANGEID", + bodyMediaType: "application/xml", + params: { + "Id": "/change/SOMECHANGEID" + } + }, +]) + +apply GetReusableDelegationSet @httpRequestTests([ + { + id: "GetReusableDelegationSetTrimDelegationSetId", + documentation: "This test validates that delegation set id is correctly trimmed", + method: "GET", + protocol: "aws.protocols#restXml", + uri: "/2013-04-01/delegationset/DELEGATIONSETID", + bodyMediaType: "application/xml", + params: { + "Id": "/delegationset/DELEGATIONSETID" + } + }, +]) diff --git a/aws/sdk/integration-tests/Cargo.toml b/aws/sdk/integration-tests/Cargo.toml index ae426a1fb8c25d63b8afed8b354ccad6ac0f07d7..06e119e43b67869873ee318d5d7add97413d23ae 100644 --- a/aws/sdk/integration-tests/Cargo.toml +++ b/aws/sdk/integration-tests/Cargo.toml @@ -4,6 +4,7 @@ members = [ "dynamodb", "ec2", + "glacier", "iam", "kms", "polly", @@ -12,5 +13,4 @@ members = [ "s3control", "sts", "transcribestreaming", - "glacier" ] diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt index 9189492aba00975ab8932a79f16320440ee90a64..a804112f997543ba4468e8b0e06238c4f4e63ae6 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/CargoDependency.kt @@ -83,7 +83,7 @@ class InlineDependency( vararg additionalDependencies: RustDependency ): InlineDependency { val module = RustModule.default(name, visibility) - val filename = "$name.rs" + val filename = if (name.endsWith(".rs")) { name } else { "$name.rs" } // The inline crate is loaded as a dependency on the runtime classpath val rustFile = this::class.java.getResource("/$baseDir/src/$filename") check(rustFile != null) { "Rust file /$baseDir/src/$filename was missing from the resource bundle!" }