Unverified Commit 2f2db5a6 authored by Zelda Hessler's avatar Zelda Hessler Committed by GitHub
Browse files

rename: hosted_zone_preprocessor.rs to route53_resource_id_preprocess… (#1472)

* rename: hosted_zone_preprocessor.rs to route53_resource_id_preprocessor.rs
update: trim_hosted_zone to work for more resource ids
add: new Route53 protocol test for GetChange resource id trimming
update: InlineDependency.forRustFile to accept filenames with a ".rs" extension
add: CHANGELOG.next.toml entry
parent 40f22207
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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"
+2 −2
Original line number Diff line number Diff line
@@ -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;
+82 −0
Original line number Diff line number Diff line
@@ -3,13 +3,26 @@
 * SPDX-License-Identifier: Apache-2.0
 */

/// Strip the /hostedzone/ prefix from zone-id
pub fn trim_hosted_zone(zone: &mut Option<String>) {
    const PREFIXES: &[&str; 2] = &["/hostedzone/", "hostedzone/"];
// 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<String>) {
    const PREFIXES: &[&str] = &[
        "/hostedzone/",
        "hostedzone/",
        "/change/",
        "change/",
        "/delegationset/",
        "delegationset/",
    ];

    for prefix in PREFIXES {
        if let Some(core_zone) = zone.as_deref().unwrap_or_default().strip_prefix(prefix) {
            *zone = Some(core_zone.to_string());
        if let Some(id) = resource_id
            .as_deref()
            .unwrap_or_default()
            .strip_prefix(prefix)
        {
            *resource_id = Some(id.to_string());
            return;
        }
    }
@@ -17,42 +30,50 @@ pub fn trim_hosted_zone(zone: &mut Option<String>) {

#[cfg(test)]
mod test {
    use crate::hosted_zone_preprocessor::trim_hosted_zone;
    use crate::route53_resource_id_preprocessor::trim_resource_id;

    #[test]
    fn does_not_change_regular_zones() {
        struct OperationInput {
        hosted_zone: Option<String>,
            resource: Option<String>,
        }

    #[test]
    fn does_not_change_regular_zones() {
        let mut operation = OperationInput {
            hosted_zone: Some("Z0441723226OZ66S5ZCNZ".to_string()),
            resource: Some("Z0441723226OZ66S5ZCNZ".to_string()),
        };
        trim_hosted_zone(&mut operation.hosted_zone);
        trim_resource_id(&mut operation.resource);
        assert_eq!(
            &operation.hosted_zone.unwrap_or_default(),
            &operation.resource.unwrap_or_default(),
            "Z0441723226OZ66S5ZCNZ"
        );
    }

    #[test]
    fn sanitizes_prefixed_zone() {
        struct OperationInput {
            change_id: Option<String>,
        }

        let mut operation = OperationInput {
            hosted_zone: Some("/hostedzone/Z0441723226OZ66S5ZCNZ".to_string()),
            change_id: Some("/change/Z0441723226OZ66S5ZCNZ".to_string()),
        };
        trim_hosted_zone(&mut operation.hosted_zone);
        trim_resource_id(&mut operation.change_id);
        assert_eq!(
            &operation.hosted_zone.unwrap_or_default(),
            &operation.change_id.unwrap_or_default(),
            "Z0441723226OZ66S5ZCNZ"
        );
    }

    #[test]
    fn allow_no_leading_slash() {
        struct OperationInput {
            hosted_zone: Option<String>,
        }

        let mut operation = OperationInput {
            hosted_zone: Some("hostedzone/Z0441723226OZ66S5ZCNZ".to_string()),
        };
        trim_hosted_zone(&mut operation.hosted_zone);
        trim_resource_id(&mut operation.hosted_zone);
        assert_eq!(
            &operation.hosted_zone.unwrap_or_default(),
            "Z0441723226OZ66S5ZCNZ"
+17 −11
Original line number Diff line number Diff line
@@ -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<OperationCustomization>
    ): List<OperationCustomization> {
        val hostedZoneMember = operation.inputShape(codegenContext.model).members().find { it.hasTrait<TrimHostedZone>() }
        val hostedZoneMember =
            operation.inputShape(codegenContext.model).members().find { it.hasTrait<TrimResourceId>() }
        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<HttpLabelTrait>()
    }
}

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
        }
+3 −3
Original line number Diff line number Diff line
@@ -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")
    }
}
Loading