From b92df2038b84f36ab60139f03ccb626ef29f2163 Mon Sep 17 00:00:00 2001 From: Ran Vaknin <50976344+RanVaknin@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:55:50 -0700 Subject: [PATCH] fix(codegen): preprocess AwsQuery error to shapeId in waiter errorType (#6501) Co-authored-by: Ran Vaknin --- .../src/waiters/waitForDBInstanceDeleted.ts | 2 +- .../waiters/waitForLoadBalancerAvailable.ts | 2 +- .../src/waiters/waitForLoadBalancerExists.ts | 2 +- .../waiters/waitForLoadBalancersDeleted.ts | 2 +- .../src/waiters/waitForTargetDeregistered.ts | 2 +- .../waiters/waitForInstanceDeregistered.ts | 2 +- .../src/waiters/waitForInstanceInService.ts | 2 +- .../src/waiters/waitForCacheClusterDeleted.ts | 2 +- .../src/waiters/waitForPolicyExists.ts | 2 +- .../src/waiters/waitForRoleExists.ts | 2 +- .../src/waiters/waitForUserExists.ts | 2 +- .../src/waiters/waitForDBInstanceDeleted.ts | 2 +- .../src/waiters/waitForDBInstanceDeleted.ts | 2 +- .../src/waiters/waitForDBSnapshotDeleted.ts | 2 +- .../src/waiters/waitForClusterAvailable.ts | 2 +- .../src/waiters/waitForClusterDeleted.ts | 2 +- .../codegen/ProcessAwsQueryWaiters.java | 96 +++++++++++++++++++ ....codegen.integration.TypeScriptIntegration | 1 + 18 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/ProcessAwsQueryWaiters.java diff --git a/clients/client-docdb/src/waiters/waitForDBInstanceDeleted.ts b/clients/client-docdb/src/waiters/waitForDBInstanceDeleted.ts index 7ae3ec0424a8..a35502d8b9f0 100644 --- a/clients/client-docdb/src/waiters/waitForDBInstanceDeleted.ts +++ b/clients/client-docdb/src/waiters/waitForDBInstanceDeleted.ts @@ -83,7 +83,7 @@ const checkState = async (client: DocDBClient, input: DescribeDBInstancesCommand } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "DBInstanceNotFound") { + if (exception.name && exception.name == "DBInstanceNotFoundFault") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerAvailable.ts b/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerAvailable.ts index 78e74c15de5a..5c1658dcaa9f 100644 --- a/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerAvailable.ts +++ b/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerAvailable.ts @@ -47,7 +47,7 @@ const checkState = async ( } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "LoadBalancerNotFound") { + if (exception.name && exception.name == "LoadBalancerNotFoundException") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerExists.ts b/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerExists.ts index 0a6bd555efa4..23d1a4f6e8de 100644 --- a/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerExists.ts +++ b/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancerExists.ts @@ -18,7 +18,7 @@ const checkState = async ( return { state: WaiterState.SUCCESS, reason }; } catch (exception) { reason = exception; - if (exception.name && exception.name == "LoadBalancerNotFound") { + if (exception.name && exception.name == "LoadBalancerNotFoundException") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancersDeleted.ts b/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancersDeleted.ts index 1266d742f87f..130a08eab9ab 100644 --- a/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancersDeleted.ts +++ b/clients/client-elastic-load-balancing-v2/src/waiters/waitForLoadBalancersDeleted.ts @@ -33,7 +33,7 @@ const checkState = async ( } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "LoadBalancerNotFound") { + if (exception.name && exception.name == "LoadBalancerNotFoundException") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-elastic-load-balancing-v2/src/waiters/waitForTargetDeregistered.ts b/clients/client-elastic-load-balancing-v2/src/waiters/waitForTargetDeregistered.ts index 8f2c54f02eae..7782622bfb4f 100644 --- a/clients/client-elastic-load-balancing-v2/src/waiters/waitForTargetDeregistered.ts +++ b/clients/client-elastic-load-balancing-v2/src/waiters/waitForTargetDeregistered.ts @@ -30,7 +30,7 @@ const checkState = async ( } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "InvalidTarget") { + if (exception.name && exception.name == "InvalidTargetException") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-elastic-load-balancing/src/waiters/waitForInstanceDeregistered.ts b/clients/client-elastic-load-balancing/src/waiters/waitForInstanceDeregistered.ts index dae5a6f864f6..c052bb87e66c 100644 --- a/clients/client-elastic-load-balancing/src/waiters/waitForInstanceDeregistered.ts +++ b/clients/client-elastic-load-balancing/src/waiters/waitForInstanceDeregistered.ts @@ -33,7 +33,7 @@ const checkState = async ( } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "InvalidInstance") { + if (exception.name && exception.name == "InvalidEndPointException") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-elastic-load-balancing/src/waiters/waitForInstanceInService.ts b/clients/client-elastic-load-balancing/src/waiters/waitForInstanceInService.ts index 5898257b0c0c..0fa6599a941b 100644 --- a/clients/client-elastic-load-balancing/src/waiters/waitForInstanceInService.ts +++ b/clients/client-elastic-load-balancing/src/waiters/waitForInstanceInService.ts @@ -33,7 +33,7 @@ const checkState = async ( } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "InvalidInstance") { + if (exception.name && exception.name == "InvalidEndPointException") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-elasticache/src/waiters/waitForCacheClusterDeleted.ts b/clients/client-elasticache/src/waiters/waitForCacheClusterDeleted.ts index 4ce3a28b2fc8..1be977922a10 100644 --- a/clients/client-elasticache/src/waiters/waitForCacheClusterDeleted.ts +++ b/clients/client-elasticache/src/waiters/waitForCacheClusterDeleted.ts @@ -117,7 +117,7 @@ const checkState = async ( } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "CacheClusterNotFound") { + if (exception.name && exception.name == "CacheClusterNotFoundFault") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-iam/src/waiters/waitForPolicyExists.ts b/clients/client-iam/src/waiters/waitForPolicyExists.ts index 6585d06ec529..50170bdfc20a 100644 --- a/clients/client-iam/src/waiters/waitForPolicyExists.ts +++ b/clients/client-iam/src/waiters/waitForPolicyExists.ts @@ -12,7 +12,7 @@ const checkState = async (client: IAMClient, input: GetPolicyCommandInput): Prom return { state: WaiterState.SUCCESS, reason }; } catch (exception) { reason = exception; - if (exception.name && exception.name == "NoSuchEntity") { + if (exception.name && exception.name == "NoSuchEntityException") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-iam/src/waiters/waitForRoleExists.ts b/clients/client-iam/src/waiters/waitForRoleExists.ts index b2cff6f3dfff..f197ffebee34 100644 --- a/clients/client-iam/src/waiters/waitForRoleExists.ts +++ b/clients/client-iam/src/waiters/waitForRoleExists.ts @@ -12,7 +12,7 @@ const checkState = async (client: IAMClient, input: GetRoleCommandInput): Promis return { state: WaiterState.SUCCESS, reason }; } catch (exception) { reason = exception; - if (exception.name && exception.name == "NoSuchEntity") { + if (exception.name && exception.name == "NoSuchEntityException") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-iam/src/waiters/waitForUserExists.ts b/clients/client-iam/src/waiters/waitForUserExists.ts index 915c409d529f..d559f1db7d3d 100644 --- a/clients/client-iam/src/waiters/waitForUserExists.ts +++ b/clients/client-iam/src/waiters/waitForUserExists.ts @@ -12,7 +12,7 @@ const checkState = async (client: IAMClient, input: GetUserCommandInput): Promis return { state: WaiterState.SUCCESS, reason }; } catch (exception) { reason = exception; - if (exception.name && exception.name == "NoSuchEntity") { + if (exception.name && exception.name == "NoSuchEntityException") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-neptune/src/waiters/waitForDBInstanceDeleted.ts b/clients/client-neptune/src/waiters/waitForDBInstanceDeleted.ts index 1b0287692184..3364b69bee26 100644 --- a/clients/client-neptune/src/waiters/waitForDBInstanceDeleted.ts +++ b/clients/client-neptune/src/waiters/waitForDBInstanceDeleted.ts @@ -83,7 +83,7 @@ const checkState = async (client: NeptuneClient, input: DescribeDBInstancesComma } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "DBInstanceNotFound") { + if (exception.name && exception.name == "DBInstanceNotFoundFault") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-rds/src/waiters/waitForDBInstanceDeleted.ts b/clients/client-rds/src/waiters/waitForDBInstanceDeleted.ts index 543689186495..0cb70d9ff45e 100644 --- a/clients/client-rds/src/waiters/waitForDBInstanceDeleted.ts +++ b/clients/client-rds/src/waiters/waitForDBInstanceDeleted.ts @@ -75,7 +75,7 @@ const checkState = async (client: RDSClient, input: DescribeDBInstancesCommandIn } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "DBInstanceNotFound") { + if (exception.name && exception.name == "DBInstanceNotFoundFault") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-rds/src/waiters/waitForDBSnapshotDeleted.ts b/clients/client-rds/src/waiters/waitForDBSnapshotDeleted.ts index 7c748db95e85..ff90b2d5a8ee 100644 --- a/clients/client-rds/src/waiters/waitForDBSnapshotDeleted.ts +++ b/clients/client-rds/src/waiters/waitForDBSnapshotDeleted.ts @@ -75,7 +75,7 @@ const checkState = async (client: RDSClient, input: DescribeDBSnapshotsCommandIn } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "DBSnapshotNotFound") { + if (exception.name && exception.name == "DBSnapshotNotFoundFault") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/clients/client-redshift/src/waiters/waitForClusterAvailable.ts b/clients/client-redshift/src/waiters/waitForClusterAvailable.ts index 28e36445c4c4..b1746bef5931 100644 --- a/clients/client-redshift/src/waiters/waitForClusterAvailable.ts +++ b/clients/client-redshift/src/waiters/waitForClusterAvailable.ts @@ -41,7 +41,7 @@ const checkState = async (client: RedshiftClient, input: DescribeClustersCommand } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "ClusterNotFound") { + if (exception.name && exception.name == "ClusterNotFoundFault") { return { state: WaiterState.RETRY, reason }; } } diff --git a/clients/client-redshift/src/waiters/waitForClusterDeleted.ts b/clients/client-redshift/src/waiters/waitForClusterDeleted.ts index 472d416311ac..a6416163d4f0 100644 --- a/clients/client-redshift/src/waiters/waitForClusterDeleted.ts +++ b/clients/client-redshift/src/waiters/waitForClusterDeleted.ts @@ -39,7 +39,7 @@ const checkState = async (client: RedshiftClient, input: DescribeClustersCommand } catch (e) {} } catch (exception) { reason = exception; - if (exception.name && exception.name == "ClusterNotFound") { + if (exception.name && exception.name == "ClusterNotFoundFault") { return { state: WaiterState.SUCCESS, reason }; } } diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/ProcessAwsQueryWaiters.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/ProcessAwsQueryWaiters.java new file mode 100644 index 000000000000..7acae8b9929d --- /dev/null +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/ProcessAwsQueryWaiters.java @@ -0,0 +1,96 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.aws.typescript.codegen; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import software.amazon.smithy.aws.traits.protocols.AwsQueryErrorTrait; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.knowledge.TopDownIndex; +import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ServiceShape; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.ErrorTrait; +import software.amazon.smithy.model.transform.ModelTransformer; +import software.amazon.smithy.typescript.codegen.TypeScriptSettings; +import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration; +import software.amazon.smithy.utils.SmithyInternalApi; +import software.amazon.smithy.waiters.Acceptor; +import software.amazon.smithy.waiters.Matcher; +import software.amazon.smithy.waiters.WaitableTrait; +import software.amazon.smithy.waiters.Waiter; + + +@SmithyInternalApi +public final class ProcessAwsQueryWaiters implements TypeScriptIntegration { + + @Override + public Model preprocessModel(Model model, TypeScriptSettings settings) { + Map errorCodeToShapeId = new HashMap<>(); + + ServiceShape serviceShape = settings.getService(model); + TopDownIndex topDownIndex = TopDownIndex.of(model); + for (OperationShape operationShape : topDownIndex.getContainedOperations(serviceShape)) { + for (ShapeId errorShapeId : operationShape.getErrors()) { + Shape errorShape = model.expectShape(errorShapeId); + if (errorShape.hasTrait(ErrorTrait.class) && errorShape.hasTrait(AwsQueryErrorTrait.class)) { + AwsQueryErrorTrait awsQueryTrait = errorShape.expectTrait(AwsQueryErrorTrait.class); + errorCodeToShapeId.put(awsQueryTrait.getCode(), errorShape.getId().getName()); + } + } + } + + List modifiedShapes = new ArrayList<>(); + + for (OperationShape operationShape : topDownIndex.getContainedOperations(serviceShape)) { + OperationShape.Builder operationBuilder = operationShape.toBuilder(); + if (operationShape.hasTrait(WaitableTrait.class)) { + operationBuilder.removeTrait(WaitableTrait.ID); + WaitableTrait waiterTrait = operationShape.expectTrait(WaitableTrait.class); + WaitableTrait.Builder waitableTraitBuilder = (WaitableTrait.Builder) waiterTrait.toBuilder(); + for (Map.Entry entry : waiterTrait.getWaiters().entrySet()) { + String name = entry.getKey(); + Waiter waiter = entry.getValue(); + Waiter.Builder waiterBuilder = (Waiter.Builder) waiter.toBuilder(); + waiterBuilder.clearAcceptors(); + for (Acceptor acceptor : waiter.getAcceptors()) { + ObjectNode acceptorNode = acceptor.toNode().expectObjectNode(); + Matcher matcher = acceptor.getMatcher(); + if (matcher instanceof Matcher.ErrorTypeMember) { + ObjectNode matcherNode = matcher.toNode().expectObjectNode(); + + String errorCode = matcherNode.expectStringMember("errorType").getValue(); + if (errorCodeToShapeId.containsKey(errorCode)) { + matcherNode = matcherNode.toBuilder() + .withMember("errorType", errorCodeToShapeId.get(errorCode)) + .build(); + + acceptorNode = acceptorNode.toBuilder() + .withMember("matcher", matcherNode) + .build(); + } + } + waiterBuilder.addAcceptor(Acceptor.fromNode(acceptorNode)); + } + waitableTraitBuilder.put(name, waiterBuilder.build()); + } + operationBuilder.addTrait(waitableTraitBuilder.build()); + } + modifiedShapes.add(operationBuilder.build()); + } + + if (!modifiedShapes.isEmpty()) { + ModelTransformer transformer = ModelTransformer.create(); + model = transformer.replaceShapes(model, modifiedShapes); + } + + return model; + } +} diff --git a/codegen/smithy-aws-typescript-codegen/src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration b/codegen/smithy-aws-typescript-codegen/src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration index 9eca961da6eb..bbd08fcd1b31 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration +++ b/codegen/smithy-aws-typescript-codegen/src/main/resources/META-INF/services/software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration @@ -27,6 +27,7 @@ software.amazon.smithy.aws.typescript.codegen.AddDocumentClientPlugin software.amazon.smithy.aws.typescript.codegen.AddEndpointDiscoveryPlugin software.amazon.smithy.aws.typescript.codegen.AddHttpChecksumDependency software.amazon.smithy.aws.typescript.codegen.AddSigv4aPlugin +software.amazon.smithy.aws.typescript.codegen.ProcessAwsQueryWaiters software.amazon.smithy.aws.typescript.codegen.auth.http.integration.AwsSdkCustomizeHttpBearerTokenAuth software.amazon.smithy.aws.typescript.codegen.auth.http.integration.SupportSigV4Auth software.amazon.smithy.aws.typescript.codegen.auth.http.integration.AwsSdkCustomizeSigV4Auth