From a2be16cadab741de53a2c46b76288bb675010c35 Mon Sep 17 00:00:00 2001 From: David Souther Date: Tue, 24 Oct 2023 10:31:11 -0700 Subject: [PATCH] Rust: Aurora Scenario (#5476) * WIP scenario outline * Finished fleshing out scenario structure. * 80% impl and need to do more research on Aurora DB Engines, Engine Families, etc * Use secrecy for the password and refactor the bin. Types check * Use constant DB_ENGINE * Better handle existing parameter group. Refactor: extracted rds caller Tests for set_engine Added get_engines test Finished non-waiter tests Added waiting test * Split scenario mod and tests. * Add snapshot * Moved Aurora, bump the clap version, and add Aurora metadata. * README update * Fix snippet_files bad file path * Fix metadata * Fix rename * Format * Editorial updates --- .doc_gen/metadata/aurora_metadata.yaml | 169 ++- .../cross_service/detect_faces/Cargo.toml | 2 +- .../cross_service/detect_labels/Cargo.toml | 2 +- .../cross_service/telephone/Cargo.toml | 2 +- rust_dev_preview/examples/Cargo.toml | 1 + .../examples/apigateway/Cargo.toml | 2 +- .../examples/apigatewaymanagement/Cargo.toml | 2 +- .../applicationautoscaling/Cargo.toml | 2 +- rust_dev_preview/examples/aurora/Cargo.toml | 25 + rust_dev_preview/examples/aurora/README.md | 119 ++ .../aurora/src/aurora_scenario/mod.rs | 658 +++++++++++ .../aurora/src/aurora_scenario/tests.rs | 1028 +++++++++++++++++ .../aurora/src/bin/aurora-scenario.rs | 277 +++++ rust_dev_preview/examples/aurora/src/lib.rs | 2 + rust_dev_preview/examples/aurora/src/rds.rs | 285 +++++ .../examples/auto-scaling/Cargo.toml | 2 +- .../examples/autoscalingplans/Cargo.toml | 2 +- rust_dev_preview/examples/batch/Cargo.toml | 2 +- .../examples/cloudformation/Cargo.toml | 2 +- .../examples/cloudwatch/Cargo.toml | 2 +- .../examples/cloudwatchlogs/Cargo.toml | 2 +- .../examples/cognitoidentity/Cargo.toml | 2 +- .../cognitoidentityprovider/Cargo.toml | 2 +- .../examples/cognitosync/Cargo.toml | 2 +- .../examples/concurrency/Cargo.toml | 2 +- rust_dev_preview/examples/config/Cargo.toml | 2 +- rust_dev_preview/examples/dynamodb/Cargo.toml | 2 +- rust_dev_preview/examples/ebs/Cargo.toml | 2 +- rust_dev_preview/examples/ec2/Cargo.toml | 2 +- rust_dev_preview/examples/ecr/Cargo.toml | 2 +- rust_dev_preview/examples/ecs/Cargo.toml | 2 +- rust_dev_preview/examples/eks/Cargo.toml | 2 +- rust_dev_preview/examples/firehose/Cargo.toml | 2 +- .../examples/globalaccelerator/Cargo.toml | 2 +- rust_dev_preview/examples/glue/Cargo.toml | 2 +- .../examples/greengrassv2/Cargo.toml | 2 +- rust_dev_preview/examples/iam/Cargo.toml | 2 +- rust_dev_preview/examples/iot/Cargo.toml | 2 +- rust_dev_preview/examples/kinesis/Cargo.toml | 2 +- rust_dev_preview/examples/kms/Cargo.toml | 2 +- rust_dev_preview/examples/lambda/Cargo.toml | 2 +- .../examples/logging/logger/Cargo.toml | 2 +- .../examples/logging/tracing/Cargo.toml | 2 +- .../examples/medialive/Cargo.toml | 2 +- .../examples/mediapackage/Cargo.toml | 2 +- rust_dev_preview/examples/polly/Cargo.toml | 2 +- rust_dev_preview/examples/qldb/Cargo.toml | 2 +- rust_dev_preview/examples/rds/Cargo.toml | 16 +- rust_dev_preview/examples/rds/README.md | 26 +- rust_dev_preview/examples/rdsdata/Cargo.toml | 2 +- rust_dev_preview/examples/route53/Cargo.toml | 2 +- rust_dev_preview/examples/s3/Cargo.toml | 2 +- .../examples/sagemaker/Cargo.toml | 2 +- .../examples/sdk-config/Cargo.toml | 2 +- .../examples/secretsmanager/Cargo.toml | 2 +- .../sending-presigned-requests/Cargo.toml | 2 +- rust_dev_preview/examples/ses/Cargo.toml | 2 +- rust_dev_preview/examples/sitewise/Cargo.toml | 2 +- rust_dev_preview/examples/snowball/Cargo.toml | 2 +- rust_dev_preview/examples/sns/Cargo.toml | 2 +- rust_dev_preview/examples/sqs/Cargo.toml | 2 +- rust_dev_preview/examples/ssm/Cargo.toml | 2 +- .../examples/stepfunction/Cargo.toml | 2 +- rust_dev_preview/examples/sts/Cargo.toml | 2 +- rust_dev_preview/examples/testing/Cargo.toml | 2 +- .../examples/transcribestreaming/Cargo.toml | 2 +- rust_dev_preview/lambda/calculator/Cargo.toml | 2 +- rust_dev_preview/test-utils/Cargo.toml | 3 +- rust_dev_preview/test-utils/src/mod.rs | 1 + rust_dev_preview/test-utils/src/waiter.rs | 90 ++ 70 files changed, 2732 insertions(+), 80 deletions(-) create mode 100644 rust_dev_preview/examples/aurora/Cargo.toml create mode 100644 rust_dev_preview/examples/aurora/README.md create mode 100644 rust_dev_preview/examples/aurora/src/aurora_scenario/mod.rs create mode 100644 rust_dev_preview/examples/aurora/src/aurora_scenario/tests.rs create mode 100644 rust_dev_preview/examples/aurora/src/bin/aurora-scenario.rs create mode 100644 rust_dev_preview/examples/aurora/src/lib.rs create mode 100644 rust_dev_preview/examples/aurora/src/rds.rs create mode 100644 rust_dev_preview/test-utils/src/waiter.rs diff --git a/.doc_gen/metadata/aurora_metadata.yaml b/.doc_gen/metadata/aurora_metadata.yaml index bd7bb4948bd..62a8e0facb8 100644 --- a/.doc_gen/metadata/aurora_metadata.yaml +++ b/.doc_gen/metadata/aurora_metadata.yaml @@ -34,6 +34,15 @@ aurora_Hello: - description: Code for the hello_aurora.cpp source file. snippet_tags: - cpp.example_code.aurora.hello_aurora + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.get_cluster.usage + - rust.aurora.describe_db_clusters.wrapper + - rust.aurora.get_cluster.test services: aurora: {DescribeDBClusters} aurora_DescribeDBClusterParameterGroups: @@ -165,6 +174,15 @@ aurora_CreateDBClusterParameterGroup: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.CreateDBClusterParameterGroup + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.set_engine.usage + - rust.aurora.create_db_cluster_parameter_group.wrapper + - rust.aurora.set_engine.test services: aurora: {CreateDBClusterParameterGroup} aurora_DeleteDBClusterParameterGroup: @@ -230,6 +248,15 @@ aurora_DeleteDBClusterParameterGroup: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DeleteDBClusterParameterGroup + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.clean_up.usage + - rust.aurora.delete_db_cluster_parameter_group.wrapper + - rust.aurora.clean_up.test services: aurora: {DeleteDBClusterParameterGroup} aurora_DescribeDBClusterParameters: @@ -295,6 +322,15 @@ aurora_DescribeDBClusterParameters: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DescribeDBClusterParameters + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.cluster_parameters.usage + - rust.aurora.describe_db_cluster_parameters.wrapper + - rust.aurora.cluster_parameters.test services: aurora: {DescribeDBClusterParameters} aurora_ModifyDBClusterParameterGroup: @@ -360,6 +396,15 @@ aurora_ModifyDBClusterParameterGroup: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.ModifyDBClusterParameterGroup + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.update_auto_increment.usage + - rust.aurora.modify_db_cluster_parameter_group.wrapper + - rust.aurora.update_auto_increment.test services: aurora: {ModifyDBClusterParameterGroup} aurora_DescribeDBClusters: @@ -425,6 +470,15 @@ aurora_DescribeDBClusters: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DescribeDBClusters + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.start_cluster_and_instance.usage + - rust.aurora.describe_db_clusters.wrapper + - rust.aurora.start_cluster_and_instance.test services: aurora: {DescribeDBClusters} aurora_CreateDBCluster: @@ -490,6 +544,15 @@ aurora_CreateDBCluster: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.CreateDBCluster + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.start_cluster_and_instance.usage + - rust.aurora.create_db_cluster.wrapper + - rust.aurora.start_cluster_and_instance.test services: aurora: {CreateDBCluster} aurora_DeleteDBCluster: @@ -555,6 +618,15 @@ aurora_DeleteDBCluster: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DeleteDBCluster + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.clean_up.usage + - rust.aurora.delete_db_cluster.wrapper + - rust.aurora.clean_up.test services: aurora: {DeleteDBCluster} aurora_CreateDBClusterSnapshot: @@ -620,6 +692,15 @@ aurora_CreateDBClusterSnapshot: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.CreateDBClusterSnapshot + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.start_cluster_and_instance.usage + - rust.aurora.create_db_cluster_snapshot.wrapper + - rust.aurora.start_cluster_and_instance.test services: aurora: {CreateDBClusterSnapshot} aurora_DescribeDBClusterSnapshots: @@ -750,6 +831,15 @@ aurora_CreateDBInstance: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.CreateDBInstance + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.start_cluster_and_instance.usage + - rust.aurora.create_db_instance.wrapper + - rust.aurora.start_cluster_and_instance.test services: aurora: {CreateDBInstance} aurora_DescribeDBEngineVersions: @@ -815,6 +905,15 @@ aurora_DescribeDBEngineVersions: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DescribeDBEngineVersions + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.get_engines.usage + - rust.aurora.describe_db_engine_versions.wrapper + - rust.aurora.get_engines.test services: aurora: {DescribeDBEngineVersions} aurora_DescribeOrderableDBInstanceOptions: @@ -871,6 +970,15 @@ aurora_DescribeOrderableDBInstanceOptions: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DescribeOrderableDBInstanceOptions + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.get_instance_classes.usage + - rust.aurora.describe_orderable_db_instance_options.wrapper + - rust.aurora.get_instance_classes.test services: aurora: {DescribeOrderableDBInstanceOptions} aurora_DescribeDBInstances: @@ -936,6 +1044,15 @@ aurora_DescribeDBInstances: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DescribeDBInstances + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.clean_up.usage + - rust.aurora.describe_db_instances.wrapper + - rust.aurora.clean_up.test services: aurora: {DescribeDBInstances} aurora_DeleteDBInstance: @@ -1001,6 +1118,15 @@ aurora_DeleteDBInstance: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.client - cpp.example_code.aurora.DeleteDBInstance + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - snippet_tags: + - rust.aurora.clean_up.usage + - rust.aurora.delete_db_instance.wrapper + - rust.aurora.clean_up.test services: aurora: {DeleteDBInstance} aurora_Scenario_GetStartedClusters: @@ -1079,9 +1205,42 @@ aurora_Scenario_GetStartedClusters: snippet_tags: - cpp.example_code.aurora.client_configuration - cpp.example_code.aurora.get_started_clusters + Rust: + versions: + - sdk_version: 1 + github: rust_dev_preview/examples/aurora + excerpts: + - description: A library containing the scenario-specific functions for the Aurora scenario. + snippet_files: + - rust_dev_preview/examples/aurora/src/aurora_scenario/mod.rs + - description: Tests for the library using automocks around the RDS Client wrapper. + snippet_files: + - rust_dev_preview/examples/aurora/src/aurora_scenario/tests.rs + - description: A binary to run the scenario from front to end, using inquirer so that the user can make some decisions. + snippet_files: + - rust_dev_preview/examples/aurora/src/bin/aurora-scenario.rs + - description: A wrapper around the Amazon RDS service that allows automocking for tests. + snippet_files: + - rust_dev_preview/examples/aurora/src/rds.rs + - description: The Cargo.toml with dependencies used in this scenario. + snippet_files: + - rust_dev_preview/examples/aurora/Cargo.toml services: - aurora: {CreateDBCluster, CreateDBClusterParameterGroup, CreateDBClusterSnapshot, - CreateDBInstance, DeleteDBCluster, DeleteDBClusterParameterGroup, DeleteDBInstance, - DescribeDBClusterParameterGroups, DescribeDBClusterSnapshots, DescribeDBClusters, - DescribeDBEngineVersions, DescribeDBInstances, DescribeOrderableDBInstanceOptions, - DescribeDBClusterParameters, ModifyDBClusterParameterGroup} + aurora: + { + CreateDBCluster, + CreateDBClusterParameterGroup, + CreateDBClusterSnapshot, + CreateDBInstance, + DeleteDBCluster, + DeleteDBClusterParameterGroup, + DeleteDBInstance, + DescribeDBClusterParameterGroups, + DescribeDBClusterSnapshots, + DescribeDBClusters, + DescribeDBEngineVersions, + DescribeDBInstances, + DescribeOrderableDBInstanceOptions, + DescribeDBClusterParameters, + ModifyDBClusterParameterGroup, + } diff --git a/rust_dev_preview/cross_service/detect_faces/Cargo.toml b/rust_dev_preview/cross_service/detect_faces/Cargo.toml index 0627676b889..c64afe985e7 100644 --- a/rust_dev_preview/cross_service/detect_faces/Cargo.toml +++ b/rust_dev_preview/cross_service/detect_faces/Cargo.toml @@ -14,5 +14,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-rekognition = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-s3 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/cross_service/detect_labels/Cargo.toml b/rust_dev_preview/cross_service/detect_labels/Cargo.toml index f883392eb83..19aeb35bad8 100644 --- a/rust_dev_preview/cross_service/detect_labels/Cargo.toml +++ b/rust_dev_preview/cross_service/detect_labels/Cargo.toml @@ -16,6 +16,6 @@ aws-sdk-rekognition = { git = "https://github.com/awslabs/aws-sdk-rust", branch aws-sdk-s3 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } kamadak-exif = "0.5.4" diff --git a/rust_dev_preview/cross_service/telephone/Cargo.toml b/rust_dev_preview/cross_service/telephone/Cargo.toml index 00c5404d588..f4597665bde 100644 --- a/rust_dev_preview/cross_service/telephone/Cargo.toml +++ b/rust_dev_preview/cross_service/telephone/Cargo.toml @@ -16,5 +16,5 @@ tokio = { version = "1.20.1", features = ["full"] } bytes = "1" reqwest = "0.11.4" serde_json = "1.0" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/Cargo.toml b/rust_dev_preview/examples/Cargo.toml index ee214b256cd..bab032a57bf 100644 --- a/rust_dev_preview/examples/Cargo.toml +++ b/rust_dev_preview/examples/Cargo.toml @@ -6,6 +6,7 @@ members = [ "apigateway", "apigatewaymanagement", "applicationautoscaling", + "aurora", "auto-scaling", "autoscalingplans", "batch", diff --git a/rust_dev_preview/examples/apigateway/Cargo.toml b/rust_dev_preview/examples/apigateway/Cargo.toml index 7a919451adf..ee8ead63b19 100644 --- a/rust_dev_preview/examples/apigateway/Cargo.toml +++ b/rust_dev_preview/examples/apigateway/Cargo.toml @@ -11,7 +11,7 @@ aws-sdk-apigateway = { git = "https://github.com/awslabs/aws-sdk-rust", branch = aws-smithy-types-convert = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = [ "convert-chrono", ] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } \ No newline at end of file diff --git a/rust_dev_preview/examples/apigatewaymanagement/Cargo.toml b/rust_dev_preview/examples/apigatewaymanagement/Cargo.toml index cb4885eac17..0aacb7f2a26 100644 --- a/rust_dev_preview/examples/apigatewaymanagement/Cargo.toml +++ b/rust_dev_preview/examples/apigatewaymanagement/Cargo.toml @@ -14,5 +14,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-apigatewaymanagement = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } http = "0.2.5" tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/applicationautoscaling/Cargo.toml b/rust_dev_preview/examples/applicationautoscaling/Cargo.toml index 0c5eaefa239..51e4c21f90a 100644 --- a/rust_dev_preview/examples/applicationautoscaling/Cargo.toml +++ b/rust_dev_preview/examples/applicationautoscaling/Cargo.toml @@ -12,5 +12,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-applicationautoscaling = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/aurora/Cargo.toml b/rust_dev_preview/examples/aurora/Cargo.toml new file mode 100644 index 00000000000..fc563f8996c --- /dev/null +++ b/rust_dev_preview/examples/aurora/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "aurora-code-examples" +authors = [ + "David Souther ", +] +edition = "2021" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.75" +assert_matches = "1.5.0" +aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } +aws-smithy-http = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } +aws-smithy-runtime-api = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } +aws-sdk-rds = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } +inquire = "0.6.2" +mockall = "0.11.4" +phf = { version = "0.11.2", features = ["std", "macros"] } +sdk-examples-test-utils = { path = "../../test-utils" } +secrecy = "0.8.0" +tokio = { version = "1.20.1", features = ["full", "test-util"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/aurora/README.md b/rust_dev_preview/examples/aurora/README.md new file mode 100644 index 00000000000..247486ddf3b --- /dev/null +++ b/rust_dev_preview/examples/aurora/README.md @@ -0,0 +1,119 @@ + +# Aurora code examples for the SDK for Rust + +## Overview + +Shows how to use the AWS SDK for Rust to work with Amazon Aurora. + + + + +*Aurora is a fully managed relational database engine that's built for the cloud and compatible with MySQL and PostgreSQL. Amazon Aurora is part of Amazon Relational Database Service (Amazon RDS).* + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/?aws-products-pricing.sort-by=item.additionalFields.productNameLowercase&aws-products-pricing.sort-order=asc&awsf.Free%20Tier%20Type=*all&awsf.tech-category=*all) and [Free Tier](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../../README.md#Prerequisites) in the `rust_dev_preview` folder. + + + + + + +### Get started + +* [Hello Aurora](src/aurora_scenario/mod.rs#L264) (`DescribeDBClusters`) + +### Single actions + +Code excerpts that show you how to call individual service functions. + +* [Create a DB cluster](src/aurora_scenario/mod.rs#L354) (`CreateDBCluster`) +* [Create a DB cluster parameter group](src/aurora_scenario/mod.rs#L205) (`CreateDBClusterParameterGroup`) +* [Create a DB cluster snapshot](src/aurora_scenario/mod.rs#L354) (`CreateDBClusterSnapshot`) +* [Create a DB instance in a DB cluster](src/aurora_scenario/mod.rs#L354) (`CreateDBInstance`) +* [Delete a DB cluster](src/aurora_scenario/mod.rs#L514) (`DeleteDBCluster`) +* [Delete a DB cluster parameter group](src/aurora_scenario/mod.rs#L514) (`DeleteDBClusterParameterGroup`) +* [Delete a DB instance](src/aurora_scenario/mod.rs#L514) (`DeleteDBInstance`) +* [Describe DB clusters](src/aurora_scenario/mod.rs#L354) (`DescribeDBClusters`) +* [Describe DB instances](src/aurora_scenario/mod.rs#L514) (`DescribeDBInstances`) +* [Describe database engine versions](src/aurora_scenario/mod.rs#L144) (`DescribeDBEngineVersions`) +* [Describe options for DB instances](src/aurora_scenario/mod.rs#L181) (`DescribeOrderableDBInstanceOptions`) +* [Describe parameters from a DB cluster parameter group](None) (`DescribeDBClusterParameters`) +* [Update parameters in a DB cluster parameter group](src/aurora_scenario/mod.rs#L317) (`ModifyDBClusterParameterGroup`) + +### Scenarios + +Code examples that show you how to accomplish a specific task by calling multiple +functions within the same service. + +* [Get started with DB clusters](rust_dev_preview/examples/aurora/src/aurora_scenario/mod.rs) + +## Run the examples + +### Instructions + + + + + +#### Hello Aurora + +This example shows you how to get started using Aurora. + + + +#### Get started with DB clusters + +This example shows you how to do the following: + +* Create a custom Aurora DB cluster parameter group and set parameter values. +* Create a DB cluster that uses the parameter group. +* Create a DB instance that contains a database. +* Take a snapshot of the DB cluster, then clean up resources. + + + + + + + + +### Tests + +⚠ Running tests might result in charges to your AWS account. + + +To find instructions for running these tests, see the [README](../../README.md#Tests) +in the `rust_dev_preview` folder. + + + + + + +## Additional resources + +* [Aurora User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html) +* [Aurora API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/Welcome.html) +* [SDK for Rust Aurora reference](https://docs.rs/aws-sdk-rds/latest/aws_sdk_rds/) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/rust_dev_preview/examples/aurora/src/aurora_scenario/mod.rs b/rust_dev_preview/examples/aurora/src/aurora_scenario/mod.rs new file mode 100644 index 00000000000..a681f9756ca --- /dev/null +++ b/rust_dev_preview/examples/aurora/src/aurora_scenario/mod.rs @@ -0,0 +1,658 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use phf::{phf_set, Set}; +use secrecy::SecretString; +use std::{collections::HashMap, fmt::Display, time::Duration}; + +use aws_sdk_rds::{ + error::ProvideErrorMetadata, + operation::create_db_cluster_parameter_group::CreateDbClusterParameterGroupOutput, + types::{DbCluster, DbClusterParameterGroup, DbClusterSnapshot, DbInstance, Parameter}, +}; +use sdk_examples_test_utils::waiter::Waiter; +use tracing::{info, trace, warn}; + +const DB_ENGINE: &str = "aurora-mysql"; +const DB_CLUSTER_PARAMETER_GROUP_NAME: &str = "RustSDKCodeExamplesDBParameterGroup"; +const DB_CLUSTER_PARAMETER_GROUP_DESCRIPTION: &str = + "Parameter Group created by Rust SDK Code Example"; +const DB_CLUSTER_IDENTIFIER: &str = "RustSDKCodeExamplesDBCluster"; +const DB_INSTANCE_IDENTIFIER: &str = "RustSDKCodeExamplesDBInstance"; + +static FILTER_PARAMETER_NAMES: Set<&'static str> = phf_set! { + "auto_increment_offset", + "auto_increment_increment", +}; + +#[derive(Debug, PartialEq, Eq)] +struct MetadataError { + message: Option, + code: Option, +} + +impl MetadataError { + fn from(err: &dyn ProvideErrorMetadata) -> Self { + MetadataError { + message: err.message().map(String::from), + code: err.code().map(String::from), + } + } +} + +impl Display for MetadataError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let display = match (&self.message, &self.code) { + (None, None) => "Unknown".to_string(), + (None, Some(code)) => format!("({code})"), + (Some(message), None) => message.to_string(), + (Some(message), Some(code)) => format!("{message} ({code})"), + }; + write!(f, "{display}") + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct ScenarioError { + message: String, + context: Option, +} + +impl ScenarioError { + pub fn with(message: impl Into) -> Self { + ScenarioError { + message: message.into(), + context: None, + } + } + + pub fn new(message: impl Into, err: &dyn ProvideErrorMetadata) -> Self { + ScenarioError { + message: message.into(), + context: Some(MetadataError::from(err)), + } + } +} + +impl std::error::Error for ScenarioError {} +impl Display for ScenarioError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.context { + Some(c) => write!(f, "{}: {}", self.message, c), + None => write!(f, "{}", self.message), + } + } +} + +// Parse the ParameterName, Description, and AllowedValues values and display them. +#[derive(Debug)] +pub struct AuroraScenarioParameter { + name: String, + allowed_values: String, + current_value: String, +} + +impl Display for AuroraScenarioParameter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}: {} (allowed: {})", + self.name, self.current_value, self.allowed_values + ) + } +} + +impl From for AuroraScenarioParameter { + fn from(value: aws_sdk_rds::types::Parameter) -> Self { + AuroraScenarioParameter { + name: value.parameter_name.unwrap_or_default(), + allowed_values: value.allowed_values.unwrap_or_default(), + current_value: value.parameter_value.unwrap_or_default(), + } + } +} + +pub struct AuroraScenario { + rds: crate::rds::Rds, + engine_family: Option, + engine_version: Option, + instance_class: Option, + db_cluster_parameter_group: Option, + db_cluster_identifier: Option, + db_instance_identifier: Option, + username: Option, + password: Option, +} + +impl AuroraScenario { + pub fn new(client: crate::rds::Rds) -> Self { + AuroraScenario { + rds: client, + engine_family: None, + engine_version: None, + instance_class: None, + db_cluster_parameter_group: None, + db_cluster_identifier: None, + db_instance_identifier: None, + username: None, + password: None, + } + } + + // snippet-start:[rust.aurora.get_engines.usage] + // Get available engine families for Aurora MySql. rds.DescribeDbEngineVersions(Engine='aurora-mysql') and build a set of the 'DBParameterGroupFamily' field values. I get {aurora-mysql8.0, aurora-mysql5.7}. + pub async fn get_engines(&self) -> Result>, ScenarioError> { + let describe_db_engine_versions = self.rds.describe_db_engine_versions(DB_ENGINE).await; + trace!(versions=?describe_db_engine_versions, "full list of versions"); + + if let Err(err) = describe_db_engine_versions { + return Err(ScenarioError::new( + "Failed to retrieve DB Engine Versions", + &err, + )); + }; + + let version_count = describe_db_engine_versions + .as_ref() + .map(|o| o.db_engine_versions().len()) + .unwrap_or_default(); + info!(version_count, "got list of versions"); + + // Create a map of engine families to their available versions. + let mut versions = HashMap::>::new(); + describe_db_engine_versions + .unwrap() + .db_engine_versions() + .iter() + .filter_map( + |v| match (&v.db_parameter_group_family, &v.engine_version) { + (Some(family), Some(version)) => Some((family.clone(), version.clone())), + _ => None, + }, + ) + .for_each(|(family, version)| versions.entry(family).or_default().push(version)); + + Ok(versions) + } + // snippet-end:[rust.aurora.get_engines.usage] + + // snippet-start:[rust.aurora.get_instance_classes.usage] + pub async fn get_instance_classes(&self) -> Result, ScenarioError> { + let describe_orderable_db_instance_options_items = self + .rds + .describe_orderable_db_instance_options( + DB_ENGINE, + self.engine_version + .as_ref() + .expect("engine version for db instance options") + .as_str(), + ) + .await; + + describe_orderable_db_instance_options_items + .map(|options| { + options + .iter() + .map(|o| o.db_instance_class().unwrap_or_default().to_string()) + .collect::>() + }) + .map_err(|err| ScenarioError::new("Could not get available instance classes", &err)) + } + // snippet-end:[rust.aurora.get_instance_classes.usage] + + // snippet-start:[rust.aurora.set_engine.usage] + // Select an engine family and create a custom DB cluster parameter group. rds.CreateDbClusterParameterGroup(DBParameterGroupFamily='aurora-mysql8.0') + pub async fn set_engine(&mut self, engine: &str, version: &str) -> Result<(), ScenarioError> { + self.engine_family = Some(engine.to_string()); + self.engine_version = Some(version.to_string()); + let create_db_cluster_parameter_group = self + .rds + .create_db_cluster_parameter_group( + DB_CLUSTER_PARAMETER_GROUP_NAME, + DB_CLUSTER_PARAMETER_GROUP_DESCRIPTION, + engine, + ) + .await; + + match create_db_cluster_parameter_group { + Ok(CreateDbClusterParameterGroupOutput { + db_cluster_parameter_group: None, + .. + }) => { + return Err(ScenarioError::with( + "CreateDBClusterParameterGroup had empty response", + )); + } + Err(error) => { + if error.code() == Some("DBParameterGroupAlreadyExists") { + info!("Cluster Parameter Group already exists, nothing to do"); + } else { + return Err(ScenarioError::new( + "Could not create Cluster Parameter Group", + &error, + )); + } + } + _ => { + info!("Created Cluster Parameter Group"); + } + } + + Ok(()) + } + // snippet-end:[rust.aurora.set_engine.usage] + + pub fn set_instance_class(&mut self, instance_class: Option) { + self.instance_class = instance_class; + } + + pub fn set_login(&mut self, username: Option, password: Option) { + self.username = username; + self.password = password; + } + + pub async fn connection_string(&self) -> Result { + let cluster = self.get_cluster().await?; + let endpoint = cluster.endpoint().unwrap_or_default(); + let port = cluster.port().unwrap_or_default(); + let username = cluster.master_username().unwrap_or_default(); + Ok(format!("mysql -h {endpoint} -P {port} -u {username} -p")) + } + + // snippet-start:[rust.aurora.get_cluster.usage] + pub async fn get_cluster(&self) -> Result { + let describe_db_clusters_output = self + .rds + .describe_db_clusters( + self.db_cluster_identifier + .as_ref() + .expect("cluster identifier") + .as_str(), + ) + .await; + if let Err(err) = describe_db_clusters_output { + return Err(ScenarioError::new("Failed to get cluster", &err)); + } + + let db_cluster = describe_db_clusters_output + .unwrap() + .db_clusters + .and_then(|output| output.first().cloned()); + + db_cluster.ok_or_else(|| ScenarioError::with("Did not find the cluster")) + } + // snippet-end:[rust.aurora.get_cluster.usage] + + // snippet-start:[rust.aurora.cluster_parameters.usage] + // Get the parameter group. rds.DescribeDbClusterParameterGroups + // Get parameters in the group. This is a long list so you will have to paginate. Find the auto_increment_offset and auto_increment_increment parameters (by ParameterName). rds.DescribeDbClusterParameters + // Parse the ParameterName, Description, and AllowedValues values and display them. + pub async fn cluster_parameters(&self) -> Result, ScenarioError> { + let parameters_output = self + .rds + .describe_db_cluster_parameters(DB_CLUSTER_PARAMETER_GROUP_NAME) + .await; + + if let Err(err) = parameters_output { + return Err(ScenarioError::new( + format!("Failed to retrieve parameters for {DB_CLUSTER_PARAMETER_GROUP_NAME}"), + &err, + )); + } + + let parameters = parameters_output + .unwrap() + .into_iter() + .flat_map(|p| p.parameters.unwrap_or_default().into_iter()) + .filter(|p| FILTER_PARAMETER_NAMES.contains(p.parameter_name().unwrap_or_default())) + .map(AuroraScenarioParameter::from) + .collect::>(); + + Ok(parameters) + } + // snippet-end:[rust.aurora.cluster_parameters.usage] + + // snippet-start:[rust.aurora.update_auto_increment.usage] + // Modify both the auto_increment_offset and auto_increment_increment parameters in one call in the custom parameter group. Set their ParameterValue fields to a new allowable value. rds.ModifyDbClusterParameterGroup. + pub async fn update_auto_increment( + &self, + offset: u8, + increment: u8, + ) -> Result<(), ScenarioError> { + let modify_db_cluster_parameter_group = self + .rds + .modify_db_cluster_parameter_group( + DB_CLUSTER_PARAMETER_GROUP_NAME, + vec![ + Parameter::builder() + .parameter_name("auto_increment_offset") + .parameter_value(format!("{offset}")) + .apply_method(aws_sdk_rds::types::ApplyMethod::Immediate) + .build(), + Parameter::builder() + .parameter_name("auto_increment_increment") + .parameter_value(format!("{increment}")) + .apply_method(aws_sdk_rds::types::ApplyMethod::Immediate) + .build(), + ], + ) + .await; + + if let Err(error) = modify_db_cluster_parameter_group { + return Err(ScenarioError::new( + "Failed to modify cluster parameter group", + &error, + )); + } + + Ok(()) + } + // snippet-end:[rust.aurora.update_auto_increment.usage] + + // snippet-start:[rust.aurora.start_cluster_and_instance.usage] + // Get a list of allowed engine versions. rds.DescribeDbEngineVersions(Engine='aurora-mysql', DBParameterGroupFamily=) + // Create an Aurora DB cluster database cluster that contains a MySql database and uses the parameter group you created. + // Wait for DB cluster to be ready. Call rds.DescribeDBClusters and check for Status == 'available'. + // Get a list of instance classes available for the selected engine and engine version. rds.DescribeOrderableDbInstanceOptions(Engine='mysql', EngineVersion=). + + // Create a database instance in the cluster. + // Wait for DB instance to be ready. Call rds.DescribeDbInstances and check for DBInstanceStatus == 'available'. + pub async fn start_cluster_and_instance(&mut self) -> Result<(), ScenarioError> { + if self.password.is_none() { + return Err(ScenarioError::with( + "Must set Secret Password before starting a cluster", + )); + } + let create_db_cluster = self + .rds + .create_db_cluster( + DB_CLUSTER_IDENTIFIER, + DB_CLUSTER_PARAMETER_GROUP_NAME, + DB_ENGINE, + self.engine_version.as_deref().expect("engine version"), + self.username.as_deref().expect("username"), + self.password + .replace(SecretString::new("".to_string())) + .expect("password"), + ) + .await; + if let Err(err) = create_db_cluster { + return Err(ScenarioError::new( + "Failed to create DB Cluster with cluster group", + &err, + )); + } + + self.db_cluster_identifier = create_db_cluster + .unwrap() + .db_cluster + .and_then(|c| c.db_cluster_identifier); + + if self.db_cluster_identifier.is_none() { + return Err(ScenarioError::with("Created DB Cluster missing Identifier")); + } + + info!( + "Started a db cluster: {}", + self.db_cluster_identifier + .as_deref() + .unwrap_or("Missing ARN") + ); + + let create_db_instance = self + .rds + .create_db_instance( + self.db_cluster_identifier.as_deref().expect("cluster name"), + DB_INSTANCE_IDENTIFIER, + self.instance_class.as_deref().expect("instance class"), + DB_ENGINE, + ) + .await; + if let Err(err) = create_db_instance { + return Err(ScenarioError::new( + "Failed to create Instance in DB Cluster", + &err, + )); + } + + self.db_instance_identifier = create_db_instance + .unwrap() + .db_instance + .and_then(|i| i.db_instance_identifier); + + // Cluster creation can take up to 20 minutes to become available + let cluster_max_wait = Duration::from_secs(20 * 60); + let waiter = Waiter::builder().max(cluster_max_wait).build(); + while waiter.sleep().await.is_ok() { + let cluster = self + .rds + .describe_db_clusters( + self.db_cluster_identifier + .as_deref() + .expect("cluster identifier"), + ) + .await; + + if let Err(err) = cluster { + warn!(?err, "Failed to describe cluster while waiting for ready"); + continue; + } + + let instance = self + .rds + .describe_db_instance( + self.db_instance_identifier + .as_deref() + .expect("instance identifier"), + ) + .await; + if let Err(err) = instance { + return Err(ScenarioError::new( + "Failed to find instance for cluster", + &err, + )); + } + + let instances_available = instance + .unwrap() + .db_instances() + .iter() + .all(|instance| instance.db_instance_status() == Some("Available")); + + let endpoints = self + .rds + .describe_db_cluster_endpoints( + self.db_cluster_identifier + .as_deref() + .expect("cluster identifier"), + ) + .await; + + if let Err(err) = endpoints { + return Err(ScenarioError::new( + "Failed to find endpoint for cluster", + &err, + )); + } + + let endpoints_available = endpoints + .unwrap() + .db_cluster_endpoints() + .iter() + .all(|endpoint| endpoint.status() == Some("available")); + + if instances_available && endpoints_available { + return Ok(()); + } + } + + Err(ScenarioError::with("timed out waiting for cluster")) + } + // snippet-end:[rust.aurora.start_cluster_and_instance.usage] + + // snippet-start:[rust.aurora.snapshot.usage] + // Create a snapshot of the DB cluster. rds.CreateDbClusterSnapshot. + // Wait for the snapshot to create. rds.DescribeDbClusterSnapshots until Status == 'available'. + pub async fn snapshot(&self, name: &str) -> Result { + let id = self.db_cluster_identifier.as_deref().unwrap_or_default(); + let snapshot = self + .rds + .snapshot_cluster(id, format!("{id}_{name}").as_str()) + .await; + match snapshot { + Ok(output) => match output.db_cluster_snapshot { + Some(snapshot) => Ok(snapshot), + None => Err(ScenarioError::with("Missing Snapshot")), + }, + Err(err) => Err(ScenarioError::new("Failed to create snapshot", &err)), + } + } + // snippet-end:[rust.aurora.snapshot.usage] + + // snippet-start:[rust.aurora.clean_up.usage] + pub async fn clean_up(self) -> Result<(), Vec> { + let mut clean_up_errors: Vec = vec![]; + + // Delete the instance. rds.DeleteDbInstance. + let delete_db_instance = self + .rds + .delete_db_instance( + self.db_instance_identifier + .as_deref() + .expect("instance identifier"), + ) + .await; + if let Err(err) = delete_db_instance { + let identifier = self + .db_instance_identifier + .as_deref() + .unwrap_or("Missing Instance Identifier"); + let message = format!("failed to delete db instance {identifier}"); + clean_up_errors.push(ScenarioError::new(message, &err)); + } else { + // Wait for the instance to delete + let waiter = Waiter::default(); + while waiter.sleep().await.is_ok() { + let describe_db_instances = self.rds.describe_db_instances().await; + if let Err(err) = describe_db_instances { + clean_up_errors.push(ScenarioError::new( + "Failed to check instance state during deletion", + &err, + )); + break; + } + let db_instances = describe_db_instances + .unwrap() + .db_instances() + .iter() + .filter(|instance| instance.db_cluster_identifier == self.db_cluster_identifier) + .cloned() + .collect::>(); + + if db_instances.is_empty() { + trace!("Delete Instance waited and no instances were found"); + break; + } + match db_instances.first().unwrap().db_instance_status() { + Some("Deleting") => continue, + Some(status) => { + info!("Attempting to delete but instances is in {status}"); + continue; + } + None => { + warn!("No status for DB instance"); + break; + } + } + } + } + + // Delete the DB cluster. rds.DeleteDbCluster. + let delete_db_cluster = self + .rds + .delete_db_cluster( + self.db_cluster_identifier + .as_deref() + .expect("cluster identifier"), + ) + .await; + + if let Err(err) = delete_db_cluster { + let identifier = self + .db_cluster_identifier + .as_deref() + .unwrap_or("Missing DB Cluster Identifier"); + let message = format!("failed to delete db cluster {identifier}"); + clean_up_errors.push(ScenarioError::new(message, &err)); + } else { + // Wait for the instance and cluster to fully delete. rds.DescribeDbInstances and rds.DescribeDbClusters until both are not found. + let waiter = Waiter::default(); + while waiter.sleep().await.is_ok() { + let describe_db_clusters = self + .rds + .describe_db_clusters( + self.db_cluster_identifier + .as_deref() + .expect("cluster identifier"), + ) + .await; + if let Err(err) = describe_db_clusters { + clean_up_errors.push(ScenarioError::new( + "Failed to check cluster state during deletion", + &err, + )); + break; + } + let describe_db_clusters = describe_db_clusters.unwrap(); + let db_clusters = describe_db_clusters.db_clusters(); + if db_clusters.is_empty() { + trace!("Delete cluster waited and no clusters were found"); + break; + } + match db_clusters.first().unwrap().status() { + Some("Deleting") => continue, + Some(status) => { + info!("Attempting to delete but clusters is in {status}"); + continue; + } + None => { + warn!("No status for DB cluster"); + break; + } + } + } + } + + // Delete the DB cluster parameter group. rds.DeleteDbClusterParameterGroup. + let delete_db_cluster_parameter_group = self + .rds + .delete_db_cluster_parameter_group( + self.db_cluster_parameter_group + .map(|g| { + g.db_cluster_parameter_group_name + .unwrap_or_else(|| DB_CLUSTER_PARAMETER_GROUP_NAME.to_string()) + }) + .as_deref() + .expect("cluster parameter group name"), + ) + .await; + if let Err(error) = delete_db_cluster_parameter_group { + clean_up_errors.push(ScenarioError::new( + "Failed to delete the db cluster parameter group", + &error, + )) + } + + if clean_up_errors.is_empty() { + Ok(()) + } else { + Err(clean_up_errors) + } + } + // snippet-end:[rust.aurora.clean_up.usage] +} + +#[cfg(test)] +pub mod tests; diff --git a/rust_dev_preview/examples/aurora/src/aurora_scenario/tests.rs b/rust_dev_preview/examples/aurora/src/aurora_scenario/tests.rs new file mode 100644 index 00000000000..c2a4f09e532 --- /dev/null +++ b/rust_dev_preview/examples/aurora/src/aurora_scenario/tests.rs @@ -0,0 +1,1028 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use crate::rds::MockRdsImpl; + +use super::*; + +use std::io::{Error, ErrorKind}; + +use assert_matches::assert_matches; +use aws_sdk_rds::{ + error::SdkError, + operation::{ + create_db_cluster::{CreateDBClusterError, CreateDbClusterOutput}, + create_db_cluster_parameter_group::CreateDBClusterParameterGroupError, + create_db_cluster_snapshot::{CreateDBClusterSnapshotError, CreateDbClusterSnapshotOutput}, + create_db_instance::{CreateDBInstanceError, CreateDbInstanceOutput}, + delete_db_cluster::DeleteDbClusterOutput, + delete_db_cluster_parameter_group::DeleteDbClusterParameterGroupOutput, + delete_db_instance::DeleteDbInstanceOutput, + describe_db_cluster_endpoints::DescribeDbClusterEndpointsOutput, + describe_db_cluster_parameters::{ + DescribeDBClusterParametersError, DescribeDbClusterParametersOutput, + }, + describe_db_clusters::{DescribeDBClustersError, DescribeDbClustersOutput}, + describe_db_engine_versions::{ + DescribeDBEngineVersionsError, DescribeDbEngineVersionsOutput, + }, + describe_db_instances::{DescribeDBInstancesError, DescribeDbInstancesOutput}, + describe_orderable_db_instance_options::DescribeOrderableDBInstanceOptionsError, + modify_db_cluster_parameter_group::{ + ModifyDBClusterParameterGroupError, ModifyDbClusterParameterGroupOutput, + }, + }, + types::{ + error::DbParameterGroupAlreadyExistsFault, DbClusterEndpoint, DbEngineVersion, + OrderableDbInstanceOption, + }, +}; +use aws_smithy_http::body::SdkBody; +use aws_smithy_runtime_api::client::orchestrator::HttpResponse; +use mockall::predicate::eq; +use secrecy::ExposeSecret; + +// snippet-start:[rust.aurora.set_engine.test] +#[tokio::test] +async fn test_scenario_set_engine() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster_parameter_group() + .with( + eq("RustSDKCodeExamplesDBParameterGroup"), + eq("Parameter Group created by Rust SDK Code Example"), + eq("aurora-mysql"), + ) + .return_once(|_, _, _| { + Ok(CreateDbClusterParameterGroupOutput::builder() + .db_cluster_parameter_group(DbClusterParameterGroup::builder().build()) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + + let set_engine = scenario.set_engine("aurora-mysql", "aurora-mysql8.0").await; + + assert_eq!(set_engine, Ok(())); + assert_eq!(Some("aurora-mysql"), scenario.engine_family.as_deref()); + assert_eq!(Some("aurora-mysql8.0"), scenario.engine_version.as_deref()); +} + +#[tokio::test] +async fn test_scenario_set_engine_not_create() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster_parameter_group() + .with( + eq("RustSDKCodeExamplesDBParameterGroup"), + eq("Parameter Group created by Rust SDK Code Example"), + eq("aurora-mysql"), + ) + .return_once(|_, _, _| Ok(CreateDbClusterParameterGroupOutput::builder().build())); + + let mut scenario = AuroraScenario::new(mock_rds); + + let set_engine = scenario.set_engine("aurora-mysql", "aurora-mysql8.0").await; + + assert!(set_engine.is_err()); +} + +#[tokio::test] +async fn test_scenario_set_engine_param_group_exists() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster_parameter_group() + .withf(|_, _, _| true) + .return_once(|_, _, _| { + Err(SdkError::service_error( + CreateDBClusterParameterGroupError::DbParameterGroupAlreadyExistsFault( + DbParameterGroupAlreadyExistsFault::builder().build(), + ), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + + let set_engine = scenario.set_engine("aurora-mysql", "aurora-mysql8.0").await; + + assert!(set_engine.is_err()); +} +// snippet-end:[rust.aurora.set_engine.test] + +// snippet-start:[rust.aurora.get_engines.test] +#[tokio::test] +async fn test_scenario_get_engines() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_db_engine_versions() + .with(eq("aurora-mysql")) + .return_once(|_| { + Ok(DescribeDbEngineVersionsOutput::builder() + .db_engine_versions( + DbEngineVersion::builder() + .db_parameter_group_family("f1") + .engine_version("f1a") + .build(), + ) + .db_engine_versions( + DbEngineVersion::builder() + .db_parameter_group_family("f1") + .engine_version("f1b") + .build(), + ) + .db_engine_versions( + DbEngineVersion::builder() + .db_parameter_group_family("f2") + .engine_version("f2a") + .build(), + ) + .db_engine_versions(DbEngineVersion::builder().build()) + .build()) + }); + + let scenario = AuroraScenario::new(mock_rds); + + let versions_map = scenario.get_engines().await; + + assert_eq!( + versions_map, + Ok(HashMap::from([ + ("f1".into(), vec!["f1a".into(), "f1b".into()]), + ("f2".into(), vec!["f2a".into()]) + ])) + ); +} + +#[tokio::test] +async fn test_scenario_get_engines_failed() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_db_engine_versions() + .with(eq("aurora-mysql")) + .return_once(|_| { + Err(SdkError::service_error( + DescribeDBEngineVersionsError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe_db_engine_versions error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let scenario = AuroraScenario::new(mock_rds); + + let versions_map = scenario.get_engines().await; + assert_matches!( + versions_map, + Err(ScenarioError { message, context: _ }) if message == "Failed to retrieve DB Engine Versions" + ); +} +// snippet-end:[rust.aurora.get_engines.test] + +// snippet-start:[rust.aurora.get_instance_classes.test] +#[tokio::test] +async fn test_scenario_get_instance_classes() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster_parameter_group() + .return_once(|_, _, _| { + Ok(CreateDbClusterParameterGroupOutput::builder() + .db_cluster_parameter_group(DbClusterParameterGroup::builder().build()) + .build()) + }); + + mock_rds + .expect_describe_orderable_db_instance_options() + .with(eq("aurora-mysql"), eq("aurora-mysql8.0")) + .return_once(|_, _| { + Ok(vec![ + OrderableDbInstanceOption::builder() + .db_instance_class("t1") + .build(), + OrderableDbInstanceOption::builder() + .db_instance_class("t2") + .build(), + OrderableDbInstanceOption::builder() + .db_instance_class("t3") + .build(), + ]) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario + .set_engine("aurora-mysql", "aurora-mysql8.0") + .await + .expect("set engine"); + + let instance_classes = scenario.get_instance_classes().await; + + assert_eq!( + instance_classes, + Ok(vec!["t1".into(), "t2".into(), "t3".into()]) + ); +} + +#[tokio::test] +async fn test_scenario_get_instance_classes_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_orderable_db_instance_options() + .with(eq("aurora-mysql"), eq("aurora-mysql8.0")) + .return_once(|_, _| { + Err(SdkError::service_error( + DescribeOrderableDBInstanceOptionsError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe_orderable_db_instance_options_error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.engine_family = Some("aurora-mysql".into()); + scenario.engine_version = Some("aurora-mysql8.0".into()); + + let instance_classes = scenario.get_instance_classes().await; + + assert_matches!( + instance_classes, + Err(ScenarioError {message, context: _}) if message == "Could not get available instance classes" + ); +} +// snippet-end:[rust.aurora.get_instance_classes.test] + +// snippet-start:[rust.aurora.get_cluster.test] +#[tokio::test] +async fn test_scenario_get_cluster() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_db_clusters() + .with(eq("RustSDKCodeExamplesDBCluster")) + .return_once(|_| { + Ok(DescribeDbClustersOutput::builder() + .db_clusters(DbCluster::builder().build()) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("RustSDKCodeExamplesDBCluster".into()); + let cluster = scenario.get_cluster().await; + + assert!(cluster.is_ok()); +} + +#[tokio::test] +async fn test_scenario_get_cluster_missing_cluster() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster_parameter_group() + .return_once(|_, _, _| { + Ok(CreateDbClusterParameterGroupOutput::builder() + .db_cluster_parameter_group(DbClusterParameterGroup::builder().build()) + .build()) + }); + + mock_rds + .expect_describe_db_clusters() + .with(eq("RustSDKCodeExamplesDBCluster")) + .return_once(|_| Ok(DescribeDbClustersOutput::builder().build())); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("RustSDKCodeExamplesDBCluster".into()); + let cluster = scenario.get_cluster().await; + + assert_matches!(cluster, Err(ScenarioError { message, context: _ }) if message == "Did not find the cluster"); +} + +#[tokio::test] +async fn test_scenario_get_cluster_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster_parameter_group() + .return_once(|_, _, _| { + Ok(CreateDbClusterParameterGroupOutput::builder() + .db_cluster_parameter_group(DbClusterParameterGroup::builder().build()) + .build()) + }); + + mock_rds + .expect_describe_db_clusters() + .with(eq("RustSDKCodeExamplesDBCluster")) + .return_once(|_| { + Err(SdkError::service_error( + DescribeDBClustersError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe_db_clusters_error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("RustSDKCodeExamplesDBCluster".into()); + let cluster = scenario.get_cluster().await; + + assert_matches!(cluster, Err(ScenarioError { message, context: _ }) if message == "Failed to get cluster"); +} +// snippet-end:[rust.aurora.get_cluster.test] + +#[tokio::test] +async fn test_scenario_connection_string() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_db_clusters() + .with(eq("RustSDKCodeExamplesDBCluster")) + .return_once(|_| { + Ok(DescribeDbClustersOutput::builder() + .db_clusters( + DbCluster::builder() + .endpoint("test_endpoint") + .port(3306) + .master_username("test_username") + .build(), + ) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("RustSDKCodeExamplesDBCluster".into()); + let connection_string = scenario.connection_string().await; + + assert_eq!( + connection_string, + Ok("mysql -h test_endpoint -P 3306 -u test_username -p".into()) + ); +} + +// snippet-start:[rust.aurora.cluster_parameters.test] +#[tokio::test] +async fn test_scenario_cluster_parameters() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_db_cluster_parameters() + .with(eq("RustSDKCodeExamplesDBParameterGroup")) + .return_once(|_| { + Ok(vec![DescribeDbClusterParametersOutput::builder() + .parameters(Parameter::builder().parameter_name("a").build()) + .parameters(Parameter::builder().parameter_name("b").build()) + .parameters( + Parameter::builder() + .parameter_name("auto_increment_offset") + .build(), + ) + .parameters(Parameter::builder().parameter_name("c").build()) + .parameters( + Parameter::builder() + .parameter_name("auto_increment_increment") + .build(), + ) + .parameters(Parameter::builder().parameter_name("d").build()) + .build()]) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("RustSDKCodeExamplesDBCluster".into()); + + let params = scenario.cluster_parameters().await.expect("cluster params"); + let names: Vec = params.into_iter().map(|p| p.name).collect(); + assert_eq!( + names, + vec!["auto_increment_offset", "auto_increment_increment"] + ); +} + +#[tokio::test] +async fn test_scenario_cluster_parameters_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_describe_db_cluster_parameters() + .with(eq("RustSDKCodeExamplesDBParameterGroup")) + .return_once(|_| { + Err(SdkError::service_error( + DescribeDBClusterParametersError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe_db_cluster_parameters_error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("RustSDKCodeExamplesDBCluster".into()); + let params = scenario.cluster_parameters().await; + assert_matches!(params, Err(ScenarioError { message, context: _ }) if message == "Failed to retrieve parameters for RustSDKCodeExamplesDBParameterGroup"); +} +// snippet-end:[rust.aurora.cluster_parameters.test] + +// snippet-start:[rust.aurora.update_auto_increment.test] +#[tokio::test] +async fn test_scenario_update_auto_increment() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_modify_db_cluster_parameter_group() + .withf(|name, params| { + assert_eq!(name, "RustSDKCodeExamplesDBParameterGroup"); + assert_eq!( + params, + &vec![ + Parameter::builder() + .parameter_name("auto_increment_offset") + .parameter_value("10") + .apply_method(aws_sdk_rds::types::ApplyMethod::Immediate) + .build(), + Parameter::builder() + .parameter_name("auto_increment_increment") + .parameter_value("20") + .apply_method(aws_sdk_rds::types::ApplyMethod::Immediate) + .build(), + ] + ); + true + }) + .return_once(|_, _| Ok(ModifyDbClusterParameterGroupOutput::builder().build())); + + let scenario = AuroraScenario::new(mock_rds); + + scenario + .update_auto_increment(10, 20) + .await + .expect("update auto increment"); +} + +#[tokio::test] +async fn test_scenario_update_auto_increment_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_modify_db_cluster_parameter_group() + .return_once(|_, _| { + Err(SdkError::service_error( + ModifyDBClusterParameterGroupError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "modify_db_cluster_parameter_group_error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let scenario = AuroraScenario::new(mock_rds); + + let update = scenario.update_auto_increment(10, 20).await; + assert_matches!(update, Err(ScenarioError { message, context: _}) if message == "Failed to modify cluster parameter group"); +} +// snippet-end:[rust.aurora.update_auto_increment.test] + +// snippet-start:[rust.aurora.start_cluster_and_instance.test] +#[tokio::test] +async fn test_start_cluster_and_instance() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster() + .withf(|id, params, engine, version, username, password| { + assert_eq!(id, "RustSDKCodeExamplesDBCluster"); + assert_eq!(params, "RustSDKCodeExamplesDBParameterGroup"); + assert_eq!(engine, "aurora-mysql"); + assert_eq!(version, "aurora-mysql8.0"); + assert_eq!(username, "test username"); + assert_eq!(password.expose_secret(), "test password"); + true + }) + .return_once(|id, _, _, _, _, _| { + Ok(CreateDbClusterOutput::builder() + .db_cluster(DbCluster::builder().db_cluster_identifier(id).build()) + .build()) + }); + + mock_rds + .expect_create_db_instance() + .withf(|cluster, name, class, engine| { + assert_eq!(cluster, "RustSDKCodeExamplesDBCluster"); + assert_eq!(name, "RustSDKCodeExamplesDBInstance"); + assert_eq!(class, "m5.large"); + assert_eq!(engine, "aurora-mysql"); + true + }) + .return_once(|cluster, name, class, _| { + Ok(CreateDbInstanceOutput::builder() + .db_instance( + DbInstance::builder() + .db_cluster_identifier(cluster) + .db_instance_identifier(name) + .db_instance_class(class) + .build(), + ) + .build()) + }); + + mock_rds + .expect_describe_db_clusters() + .with(eq("RustSDKCodeExamplesDBCluster")) + .return_once(|id| { + Ok(DescribeDbClustersOutput::builder() + .db_clusters(DbCluster::builder().db_cluster_identifier(id).build()) + .build()) + }); + + mock_rds + .expect_describe_db_instance() + .with(eq("RustSDKCodeExamplesDBInstance")) + .return_once(|name| { + Ok(DescribeDbInstancesOutput::builder() + .db_instances( + DbInstance::builder() + .db_instance_identifier(name) + .db_instance_status("Available") + .build(), + ) + .build()) + }); + + mock_rds + .expect_describe_db_cluster_endpoints() + .with(eq("RustSDKCodeExamplesDBCluster")) + .return_once(|_| { + Ok(DescribeDbClusterEndpointsOutput::builder() + .db_cluster_endpoints(DbClusterEndpoint::builder().status("available").build()) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.engine_version = Some("aurora-mysql8.0".into()); + scenario.instance_class = Some("m5.large".into()); + scenario.username = Some("test username".into()); + scenario.password = Some(SecretString::new("test password".into())); + + tokio::time::pause(); + let assertions = tokio::spawn(async move { + let create = scenario.start_cluster_and_instance().await; + assert!(create.is_ok()); + assert!(scenario + .password + .replace(SecretString::new("BAD SECRET".into())) + .unwrap() + .expose_secret() + .is_empty()); + assert_eq!( + scenario.db_cluster_identifier, + Some("RustSDKCodeExamplesDBCluster".into()) + ); + }); + tokio::time::advance(Duration::from_secs(1)).await; + tokio::time::resume(); + let _ = assertions.await; +} + +#[tokio::test] +async fn test_start_cluster_and_instance_cluster_create_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster() + .return_once(|_, _, _, _, _, _| { + Err(SdkError::service_error( + CreateDBClusterError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "create db cluster error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.engine_version = Some("aurora-mysql8.0".into()); + scenario.instance_class = Some("m5.large".into()); + scenario.username = Some("test username".into()); + scenario.password = Some(SecretString::new("test password".into())); + + let create = scenario.start_cluster_and_instance().await; + assert_matches!(create, Err(ScenarioError { message, context: _}) if message == "Failed to create DB Cluster with cluster group") +} + +#[tokio::test] +async fn test_start_cluster_and_instance_cluster_create_missing_id() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster() + .return_once(|_, _, _, _, _, _| { + Ok(CreateDbClusterOutput::builder() + .db_cluster(DbCluster::builder().build()) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.engine_version = Some("aurora-mysql8.0".into()); + scenario.instance_class = Some("m5.large".into()); + scenario.username = Some("test username".into()); + scenario.password = Some(SecretString::new("test password".into())); + + let create = scenario.start_cluster_and_instance().await; + assert_matches!(create, Err(ScenarioError { message, context:_ }) if message == "Created DB Cluster missing Identifier"); +} + +#[tokio::test] +async fn test_start_cluster_and_instance_instance_create_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster() + .withf(|id, params, engine, version, username, password| { + assert_eq!(id, "RustSDKCodeExamplesDBCluster"); + assert_eq!(params, "RustSDKCodeExamplesDBParameterGroup"); + assert_eq!(engine, "aurora-mysql"); + assert_eq!(version, "aurora-mysql8.0"); + assert_eq!(username, "test username"); + assert_eq!(password.expose_secret(), "test password"); + true + }) + .return_once(|id, _, _, _, _, _| { + Ok(CreateDbClusterOutput::builder() + .db_cluster(DbCluster::builder().db_cluster_identifier(id).build()) + .build()) + }); + + mock_rds + .expect_create_db_instance() + .return_once(|_, _, _, _| { + Err(SdkError::service_error( + CreateDBInstanceError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "create db instance error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.engine_version = Some("aurora-mysql8.0".into()); + scenario.instance_class = Some("m5.large".into()); + scenario.username = Some("test username".into()); + scenario.password = Some(SecretString::new("test password".into())); + + let create = scenario.start_cluster_and_instance().await; + assert_matches!(create, Err(ScenarioError { message, context: _ }) if message == "Failed to create Instance in DB Cluster") +} + +#[tokio::test] +async fn test_start_cluster_and_instance_wait_hiccup() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_create_db_cluster() + .withf(|id, params, engine, version, username, password| { + assert_eq!(id, "RustSDKCodeExamplesDBCluster"); + assert_eq!(params, "RustSDKCodeExamplesDBParameterGroup"); + assert_eq!(engine, "aurora-mysql"); + assert_eq!(version, "aurora-mysql8.0"); + assert_eq!(username, "test username"); + assert_eq!(password.expose_secret(), "test password"); + true + }) + .return_once(|id, _, _, _, _, _| { + Ok(CreateDbClusterOutput::builder() + .db_cluster(DbCluster::builder().db_cluster_identifier(id).build()) + .build()) + }); + + mock_rds + .expect_create_db_instance() + .withf(|cluster, name, class, engine| { + assert_eq!(cluster, "RustSDKCodeExamplesDBCluster"); + assert_eq!(name, "RustSDKCodeExamplesDBInstance"); + assert_eq!(class, "m5.large"); + assert_eq!(engine, "aurora-mysql"); + true + }) + .return_once(|cluster, name, class, _| { + Ok(CreateDbInstanceOutput::builder() + .db_instance( + DbInstance::builder() + .db_cluster_identifier(cluster) + .db_instance_identifier(name) + .db_instance_class(class) + .build(), + ) + .build()) + }); + + mock_rds + .expect_describe_db_clusters() + .with(eq("RustSDKCodeExamplesDBCluster")) + .times(1) + .returning(|_| { + Err(SdkError::service_error( + DescribeDBClustersError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe cluster error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }) + .with(eq("RustSDKCodeExamplesDBCluster")) + .times(1) + .returning(|id| { + Ok(DescribeDbClustersOutput::builder() + .db_clusters(DbCluster::builder().db_cluster_identifier(id).build()) + .build()) + }); + + mock_rds.expect_describe_db_instance().return_once(|name| { + Ok(DescribeDbInstancesOutput::builder() + .db_instances( + DbInstance::builder() + .db_instance_identifier(name) + .db_instance_status("Available") + .build(), + ) + .build()) + }); + + mock_rds + .expect_describe_db_cluster_endpoints() + .return_once(|_| { + Ok(DescribeDbClusterEndpointsOutput::builder() + .db_cluster_endpoints(DbClusterEndpoint::builder().status("available").build()) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.engine_version = Some("aurora-mysql8.0".into()); + scenario.instance_class = Some("m5.large".into()); + scenario.username = Some("test username".into()); + scenario.password = Some(SecretString::new("test password".into())); + + tokio::time::pause(); + let assertions = tokio::spawn(async move { + let create = scenario.start_cluster_and_instance().await; + assert!(create.is_ok()); + }); + + tokio::time::advance(Duration::from_secs(1)).await; + tokio::time::advance(Duration::from_secs(1)).await; + tokio::time::resume(); + let _ = assertions.await; +} +// snippet-end:[rust.aurora.start_cluster_and_instance.test] + +// snippet-start:[rust.aurora.clean_up.test] +#[tokio::test] +async fn test_scenario_clean_up() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_delete_db_instance() + .with(eq("MockInstance")) + .return_once(|_| Ok(DeleteDbInstanceOutput::builder().build())); + + mock_rds + .expect_describe_db_instances() + .with() + .times(1) + .returning(|| { + Ok(DescribeDbInstancesOutput::builder() + .db_instances( + DbInstance::builder() + .db_cluster_identifier("MockCluster") + .db_instance_status("Deleting") + .build(), + ) + .build()) + }) + .with() + .times(1) + .returning(|| Ok(DescribeDbInstancesOutput::builder().build())); + + mock_rds + .expect_delete_db_cluster() + .with(eq("MockCluster")) + .return_once(|_| Ok(DeleteDbClusterOutput::builder().build())); + + mock_rds + .expect_describe_db_clusters() + .with(eq("MockCluster")) + .times(1) + .returning(|id| { + Ok(DescribeDbClustersOutput::builder() + .db_clusters( + DbCluster::builder() + .db_cluster_identifier(id) + .status("Deleting") + .build(), + ) + .build()) + }) + .with(eq("MockCluster")) + .times(1) + .returning(|_| Ok(DescribeDbClustersOutput::builder().build())); + + mock_rds + .expect_delete_db_cluster_parameter_group() + .with(eq("MockParamGroup")) + .return_once(|_| Ok(DeleteDbClusterParameterGroupOutput::builder().build())); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some(String::from("MockCluster")); + scenario.db_instance_identifier = Some(String::from("MockInstance")); + scenario.db_cluster_parameter_group = Some( + DbClusterParameterGroup::builder() + .db_cluster_parameter_group_name("MockParamGroup") + .build(), + ); + + tokio::time::pause(); + let assertions = tokio::spawn(async move { + let clean_up = scenario.clean_up().await; + assert!(clean_up.is_ok()); + }); + + tokio::time::advance(Duration::from_secs(1)).await; // Wait for first Describe Instances + tokio::time::advance(Duration::from_secs(1)).await; // Wait for second Describe Instances + tokio::time::advance(Duration::from_secs(1)).await; // Wait for first Describe Cluster + tokio::time::advance(Duration::from_secs(1)).await; // Wait for second Describe Cluster + tokio::time::resume(); + let _ = assertions.await; +} + +#[tokio::test] +async fn test_scenario_clean_up_errors() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_delete_db_instance() + .with(eq("MockInstance")) + .return_once(|_| Ok(DeleteDbInstanceOutput::builder().build())); + + mock_rds + .expect_describe_db_instances() + .with() + .times(1) + .returning(|| { + Ok(DescribeDbInstancesOutput::builder() + .db_instances( + DbInstance::builder() + .db_cluster_identifier("MockCluster") + .db_instance_status("Deleting") + .build(), + ) + .build()) + }) + .with() + .times(1) + .returning(|| { + Err(SdkError::service_error( + DescribeDBInstancesError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe db instances error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + mock_rds + .expect_delete_db_cluster() + .with(eq("MockCluster")) + .return_once(|_| Ok(DeleteDbClusterOutput::builder().build())); + + mock_rds + .expect_describe_db_clusters() + .with(eq("MockCluster")) + .times(1) + .returning(|id| { + Ok(DescribeDbClustersOutput::builder() + .db_clusters( + DbCluster::builder() + .db_cluster_identifier(id) + .status("Deleting") + .build(), + ) + .build()) + }) + .with(eq("MockCluster")) + .times(1) + .returning(|_| { + Err(SdkError::service_error( + DescribeDBClustersError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "describe db clusters error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + mock_rds + .expect_delete_db_cluster_parameter_group() + .with(eq("MockParamGroup")) + .return_once(|_| Ok(DeleteDbClusterParameterGroupOutput::builder().build())); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some(String::from("MockCluster")); + scenario.db_instance_identifier = Some(String::from("MockInstance")); + scenario.db_cluster_parameter_group = Some( + DbClusterParameterGroup::builder() + .db_cluster_parameter_group_name("MockParamGroup") + .build(), + ); + + tokio::time::pause(); + let assertions = tokio::spawn(async move { + let clean_up = scenario.clean_up().await; + assert!(clean_up.is_err()); + let errs = clean_up.unwrap_err(); + assert_eq!(errs.len(), 2); + assert_matches!(errs.get(0), Some(ScenarioError {message, context: _}) if message == "Failed to check instance state during deletion"); + assert_matches!(errs.get(1), Some(ScenarioError {message, context: _}) if message == "Failed to check cluster state during deletion"); + }); + + tokio::time::advance(Duration::from_secs(1)).await; // Wait for first Describe Instances + tokio::time::advance(Duration::from_secs(1)).await; // Wait for second Describe Instances + tokio::time::advance(Duration::from_secs(1)).await; // Wait for first Describe Cluster + tokio::time::advance(Duration::from_secs(1)).await; // Wait for second Describe Cluster + tokio::time::resume(); + let _ = assertions.await; +} +// snippet-end:[rust.aurora.clean_up.test] + +// snippet-start:[rust.aurora.snapshot.test] +#[tokio::test] +async fn test_scenario_snapshot() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_snapshot_cluster() + .with(eq("MockCluster"), eq("MockCluster_MockSnapshot")) + .times(1) + .return_once(|_, _| { + Ok(CreateDbClusterSnapshotOutput::builder() + .db_cluster_snapshot( + DbClusterSnapshot::builder() + .db_cluster_identifier("MockCluster") + .db_cluster_snapshot_identifier("MockCluster_MockSnapshot") + .build(), + ) + .build()) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("MockCluster".into()); + let create_snapshot = scenario.snapshot("MockSnapshot").await; + assert!(create_snapshot.is_ok()); +} + +#[tokio::test] +async fn test_scenario_snapshot_error() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_snapshot_cluster() + .with(eq("MockCluster"), eq("MockCluster_MockSnapshot")) + .times(1) + .return_once(|_, _| { + Err(SdkError::service_error( + CreateDBClusterSnapshotError::unhandled(Box::new(Error::new( + ErrorKind::Other, + "create snapshot error", + ))), + HttpResponse::new(SdkBody::empty()), + )) + }); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("MockCluster".into()); + let create_snapshot = scenario.snapshot("MockSnapshot").await; + assert_matches!(create_snapshot, Err(ScenarioError { message, context: _}) if message == "Failed to create snapshot"); +} + +#[tokio::test] +async fn test_scenario_snapshot_invalid() { + let mut mock_rds = MockRdsImpl::default(); + + mock_rds + .expect_snapshot_cluster() + .with(eq("MockCluster"), eq("MockCluster_MockSnapshot")) + .times(1) + .return_once(|_, _| Ok(CreateDbClusterSnapshotOutput::builder().build())); + + let mut scenario = AuroraScenario::new(mock_rds); + scenario.db_cluster_identifier = Some("MockCluster".into()); + let create_snapshot = scenario.snapshot("MockSnapshot").await; + assert_matches!(create_snapshot, Err(ScenarioError { message, context: _}) if message == "Missing Snapshot"); +} +// snippet-end:[rust.aurora.snapshot.test] diff --git a/rust_dev_preview/examples/aurora/src/bin/aurora-scenario.rs b/rust_dev_preview/examples/aurora/src/bin/aurora-scenario.rs new file mode 100644 index 00000000000..afdbfc63273 --- /dev/null +++ b/rust_dev_preview/examples/aurora/src/bin/aurora-scenario.rs @@ -0,0 +1,277 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use std::fmt::Display; + +use anyhow::anyhow; +use aurora_code_examples::{ + aurora_scenario::{AuroraScenario, ScenarioError}, + rds::Rds as RdsClient, +}; +use aws_sdk_rds::Client; +use inquire::{validator::StringValidator, CustomUserError}; +use secrecy::SecretString; +use tracing::warn; + +#[derive(Default, Debug)] +struct Warnings(Vec); + +impl Warnings { + fn new() -> Self { + Warnings(Vec::with_capacity(5)) + } + + fn push(&mut self, warning: &str, error: ScenarioError) { + let formatted = format!("{warning}: {error}"); + warn!("{formatted}"); + self.0.push(formatted); + } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl Display for Warnings { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Warnings:")?; + for warning in &self.0 { + writeln!(f, "{: >4}- {warning}", "")?; + } + Ok(()) + } +} + +fn select( + prompt: &str, + choices: Vec, + error_message: &str, +) -> Result { + inquire::Select::new(prompt, choices) + .prompt() + .map_err(|error| anyhow!("{error_message}: {error}")) +} + +// Prepare the Aurora Scenario. Prompt for several settings that are optional to the Scenario, but that the user should choose for the demo. +// This includes the engine, engine version, and instance class. +async fn prepare_scenario(rds: RdsClient) -> Result { + let mut scenario = AuroraScenario::new(rds); + + // Get available engine families for Aurora MySql. rds.DescribeDbEngineVersions(Engine='aurora-mysql') and build a set of the 'DBParameterGroupFamily' field values. I get {aurora-mysql8.0, aurora-mysql5.7}. + let available_engines = scenario.get_engines().await; + if let Err(error) = available_engines { + return Err(anyhow!("Failed to get available engines: {}", error)); + } + let available_engines = available_engines.unwrap(); + + // Select an engine family and create a custom DB cluster parameter group. rds.CreateDbClusterParameterGroup(DBParameterGroupFamily='aurora-mysql8.0') + let engine = select( + "Select an Aurora engine family", + available_engines.keys().cloned().collect::>(), + "Invalid engine selection", + )?; + + let version = select( + format!("Select an Aurora engine version for {engine}").as_str(), + available_engines.get(&engine).cloned().unwrap_or_default(), + "Invalid engine version selection", + )?; + + let set_engine = scenario.set_engine(engine.as_str(), version.as_str()).await; + if let Err(error) = set_engine { + return Err(anyhow!("Could not set engine: {}", error)); + } + + let instance_classes = scenario.get_instance_classes().await; + match instance_classes { + Ok(classes) => { + let instance_class = select( + format!("Select an Aurora instance class for {engine}").as_str(), + classes, + "Invalid instance class selection", + )?; + scenario.set_instance_class(Some(instance_class)) + } + Err(err) => return Err(anyhow!("Failed to get instance classes for engine: {err}")), + } + + Ok(scenario) +} + +// Prepare the cluster, creating a custom parameter group overriding some group parameters based on user input. +async fn prepare_cluster(scenario: &mut AuroraScenario, warnings: &mut Warnings) -> Result<(), ()> { + show_parameters(scenario, warnings).await; + + let offset = prompt_number_or_default(warnings, "auto_increment_offset", 5); + let increment = prompt_number_or_default(warnings, "auto_increment_increment", 3); + + // Modify both the auto_increment_offset and auto_increment_increment parameters in one call in the custom parameter group. Set their ParameterValue fields to a new allowable value. rds.ModifyDbClusterParameterGroup. + let update_auto_increment = scenario.update_auto_increment(offset, increment).await; + + if let Err(error) = update_auto_increment { + warnings.push("Failed to update auto increment", error); + return Err(()); + } + + // Get and display the updated parameters. Specify Source of 'user' to get just the modified parameters. rds.DescribeDbClusterParameters(Source='user') + show_parameters(scenario, warnings).await; + + let username = inquire::Text::new("Username for the database (default 'testuser')") + .with_default("testuser") + .with_initial_value("testuser") + .prompt(); + + if let Err(error) = username { + warnings.push( + "Failed to get username, using default", + ScenarioError::with(format!("Error from inquirer: {error}")), + ); + return Err(()); + } + let username = username.unwrap(); + + let password = inquire::Text::new("Password for the database (minimum 8 characters)") + .with_validator(|i: &str| { + if i.len() >= 8 { + Ok(inquire::validator::Validation::Valid) + } else { + Ok(inquire::validator::Validation::Invalid( + "Password must be at least 8 characters".into(), + )) + } + }) + .prompt(); + + let password: Option = match password { + Ok(password) => Some(SecretString::from(password)), + Err(error) => { + warnings.push( + "Failed to get password, using none (and not starting a DB)", + ScenarioError::with(format!("Error from inquirer: {error}")), + ); + return Err(()); + } + }; + + scenario.set_login(Some(username), password); + + Ok(()) +} + +// Start a single instance in the cluster, +async fn run_instance(scenario: &mut AuroraScenario) -> Result<(), ScenarioError> { + // Create an Aurora DB cluster database cluster that contains a MySql database and uses the parameter group you created. + // Create a database instance in the cluster. + // Wait for DB instance to be ready. Call rds.DescribeDbInstances and check for DBInstanceStatus == 'available'. + scenario.start_cluster_and_instance().await?; + + let connection_string = scenario.connection_string().await?; + + println!("Database ready: {connection_string}",); + + let _ = inquire::Text::new("Use the database with the connection string. When you're finished, press enter key to continue.").prompt(); + + // Create a snapshot of the DB cluster. rds.CreateDbClusterSnapshot. + // Wait for the snapshot to create. rds.DescribeDbClusterSnapshots until Status == 'available'. + let snapshot_name = inquire::Text::new("Provide a name for the snapshot") + .prompt() + .unwrap_or(String::from("ScenarioRun")); + let snapshot = scenario.snapshot(snapshot_name.as_str()).await?; + println!( + "Snapshot is available: {}", + snapshot.db_cluster_snapshot_arn().unwrap_or("Missing ARN") + ); + + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<(), anyhow::Error> { + tracing_subscriber::fmt::init(); + let sdk_config = aws_config::from_env().load().await; + let client = Client::new(&sdk_config); + let rds = RdsClient::new(client); + let mut scenario = prepare_scenario(rds).await?; + + // At this point, the scenario has things in AWS and needs to get cleaned up. + let mut warnings = Warnings::new(); + + if prepare_cluster(&mut scenario, &mut warnings).await.is_ok() { + println!("Configured database cluster, starting an instance."); + if let Err(err) = run_instance(&mut scenario).await { + warnings.push("Problem running instance", err); + } + } + + // Clean up the instance, cluster, and parameter group, waiting for the instance and cluster to delete before moving on. + let clean_up = scenario.clean_up().await; + if let Err(errors) = clean_up { + for error in errors { + warnings.push("Problem cleaning up scenario", error); + } + } + + if warnings.is_empty() { + Ok(()) + } else { + println!("There were problems running the scenario:"); + println!("{warnings}"); + Err(anyhow!("There were problems running the scenario")) + } +} + +#[derive(Clone)] +struct U8Validator {} +impl StringValidator for U8Validator { + fn validate(&self, input: &str) -> Result { + if input.parse::().is_err() { + Ok(inquire::validator::Validation::Invalid( + "Can't parse input as number".into(), + )) + } else { + Ok(inquire::validator::Validation::Valid) + } + } +} + +async fn show_parameters(scenario: &AuroraScenario, warnings: &mut Warnings) { + let parameters = scenario.cluster_parameters().await; + + match parameters { + Ok(parameters) => { + println!("Current parameters"); + for parameter in parameters { + println!("\t{parameter}"); + } + } + Err(error) => warnings.push("Could not find cluster parameters", error), + } +} + +fn prompt_number_or_default(warnings: &mut Warnings, name: &str, default: u8) -> u8 { + let input = inquire::Text::new(format!("Updated {name}:").as_str()) + .with_validator(U8Validator {}) + .prompt(); + + match input { + Ok(increment) => match increment.parse::() { + Ok(increment) => increment, + Err(error) => { + warnings.push( + format!("Invalid updated {name} (using {default} instead)").as_str(), + ScenarioError::with(format!("{error}")), + ); + default + } + }, + Err(error) => { + warnings.push( + format!("Invalid updated {name} (using {default} instead)").as_str(), + ScenarioError::with(format!("{error}")), + ); + default + } + } +} diff --git a/rust_dev_preview/examples/aurora/src/lib.rs b/rust_dev_preview/examples/aurora/src/lib.rs new file mode 100644 index 00000000000..b499f7f79c3 --- /dev/null +++ b/rust_dev_preview/examples/aurora/src/lib.rs @@ -0,0 +1,2 @@ +pub mod aurora_scenario; +pub mod rds; diff --git a/rust_dev_preview/examples/aurora/src/rds.rs b/rust_dev_preview/examples/aurora/src/rds.rs new file mode 100644 index 00000000000..ab0979db396 --- /dev/null +++ b/rust_dev_preview/examples/aurora/src/rds.rs @@ -0,0 +1,285 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use aws_sdk_rds::{ + error::SdkError, + operation::{ + create_db_cluster::{CreateDBClusterError, CreateDbClusterOutput}, + create_db_cluster_parameter_group::CreateDBClusterParameterGroupError, + create_db_cluster_parameter_group::CreateDbClusterParameterGroupOutput, + create_db_cluster_snapshot::{CreateDBClusterSnapshotError, CreateDbClusterSnapshotOutput}, + create_db_instance::{CreateDBInstanceError, CreateDbInstanceOutput}, + delete_db_cluster::{DeleteDBClusterError, DeleteDbClusterOutput}, + delete_db_cluster_parameter_group::{ + DeleteDBClusterParameterGroupError, DeleteDbClusterParameterGroupOutput, + }, + delete_db_instance::{DeleteDBInstanceError, DeleteDbInstanceOutput}, + describe_db_cluster_endpoints::{ + DescribeDBClusterEndpointsError, DescribeDbClusterEndpointsOutput, + }, + describe_db_cluster_parameters::{ + DescribeDBClusterParametersError, DescribeDbClusterParametersOutput, + }, + describe_db_clusters::{DescribeDBClustersError, DescribeDbClustersOutput}, + describe_db_engine_versions::{ + DescribeDBEngineVersionsError, DescribeDbEngineVersionsOutput, + }, + describe_db_instances::{DescribeDBInstancesError, DescribeDbInstancesOutput}, + describe_orderable_db_instance_options::DescribeOrderableDBInstanceOptionsError, + modify_db_cluster_parameter_group::{ + ModifyDBClusterParameterGroupError, ModifyDbClusterParameterGroupOutput, + }, + }, + types::{OrderableDbInstanceOption, Parameter}, + Client as RdsClient, +}; +use secrecy::{ExposeSecret, SecretString}; + +#[cfg(test)] +use mockall::automock; + +#[cfg(test)] +pub use MockRdsImpl as Rds; +#[cfg(not(test))] +pub use RdsImpl as Rds; + +pub struct RdsImpl { + pub inner: RdsClient, +} + +#[cfg_attr(test, automock)] +impl RdsImpl { + pub fn new(inner: RdsClient) -> Self { + RdsImpl { inner } + } + + // snippet-start:[rust.aurora.describe_db_engine_versions.wrapper] + pub async fn describe_db_engine_versions( + &self, + engine: &str, + ) -> Result> { + self.inner + .describe_db_engine_versions() + .engine(engine) + .send() + .await + } + // snippet-end:[rust.aurora.describe_db_engine_versions.wrapper] + + // snippet-start:[rust.aurora.describe_orderable_db_instance_options.wrapper] + pub async fn describe_orderable_db_instance_options( + &self, + engine: &str, + engine_version: &str, + ) -> Result, SdkError> + { + self.inner + .describe_orderable_db_instance_options() + .engine(engine) + .engine_version(engine_version) + .into_paginator() + .items() + .send() + .try_collect() + .await + } + // snippet-end:[rust.aurora.describe_orderable_db_instance_options.wrapper] + + // snippet-start:[rust.aurora.create_db_cluster_parameter_group.wrapper] + pub async fn create_db_cluster_parameter_group( + &self, + name: &str, + description: &str, + family: &str, + ) -> Result> + { + self.inner + .create_db_cluster_parameter_group() + .db_cluster_parameter_group_name(name) + .description(description) + .db_parameter_group_family(family) + .send() + .await + } + // snippet-end:[rust.aurora.create_db_cluster_parameter_group.wrapper] + + // snippet-start:[rust.aurora.describe_db_clusters.wrapper] + pub async fn describe_db_clusters( + &self, + id: &str, + ) -> Result> { + self.inner + .describe_db_clusters() + .db_cluster_identifier(id) + .send() + .await + } + // snippet-end:[rust.aurora.describe_db_clusters.wrapper] + + // snippet-start:[rust.aurora.describe_db_cluster_parameters.wrapper] + pub async fn describe_db_cluster_parameters( + &self, + name: &str, + ) -> Result, SdkError> + { + self.inner + .describe_db_cluster_parameters() + .db_cluster_parameter_group_name(name) + .into_paginator() + .send() + .try_collect() + .await + } + // snippet-end:[rust.aurora.describe_db_cluster_parameters.wrapper] + + // snippet-start:[rust.aurora.modify_db_cluster_parameter_group.wrapper] + pub async fn modify_db_cluster_parameter_group( + &self, + name: &str, + parameters: Vec, + ) -> Result> + { + self.inner + .modify_db_cluster_parameter_group() + .db_cluster_parameter_group_name(name) + .set_parameters(Some(parameters)) + .send() + .await + } + // snippet-end:[rust.aurora.modify_db_cluster_parameter_group.wrapper] + + // snippet-start:[rust.aurora.create_db_cluster.wrapper] + pub async fn create_db_cluster( + &self, + name: &str, + parameter_group: &str, + engine: &str, + version: &str, + username: &str, + password: SecretString, + ) -> Result> { + self.inner + .create_db_cluster() + .db_cluster_identifier(name) + .db_cluster_parameter_group_name(parameter_group) + .engine(engine) + .engine_version(version) + .master_username(username) + .master_user_password(password.expose_secret()) + .send() + .await + } + // snippet-end:[rust.aurora.create_db_cluster.wrapper] + + // snippet-start:[rust.aurora.create_db_instance.wrapper] + pub async fn create_db_instance( + &self, + cluster_name: &str, + instance_name: &str, + instance_class: &str, + engine: &str, + ) -> Result> { + self.inner + .create_db_instance() + .db_cluster_identifier(cluster_name) + .db_instance_identifier(instance_name) + .db_instance_class(instance_class) + .engine(engine) + .send() + .await + } + // snippet-end:[rust.aurora.create_db_instance.wrapper] + + // snippet-start:[rust.aurora.describe_db_instance.wrapper] + pub async fn describe_db_instance( + &self, + instance_identifier: &str, + ) -> Result> { + self.inner + .describe_db_instances() + .db_instance_identifier(instance_identifier) + .send() + .await + } + // snippet-end:[rust.aurora.describe_db_instance.wrapper] + + // snippet-start:[rust.aurora.create_db_cluster_snapshot.wrapper] + pub async fn snapshot_cluster( + &self, + db_cluster_identifier: &str, + snapshot_name: &str, + ) -> Result> { + self.inner + .create_db_cluster_snapshot() + .db_cluster_identifier(db_cluster_identifier) + .db_cluster_snapshot_identifier(snapshot_name) + .send() + .await + } + // snippet-end:[rust.aurora.create_db_cluster_snapshot.wrapper] + + // snippet-start:[rust.aurora.describe_db_instances.wrapper] + pub async fn describe_db_instances( + &self, + ) -> Result> { + self.inner.describe_db_instances().send().await + } + // snippet-end:[rust.aurora.describe_db_instances.wrapper] + + // snippet-start:[rust.aurora.describe_db_cluster_endpoints.wrapper] + pub async fn describe_db_cluster_endpoints( + &self, + cluster_identifier: &str, + ) -> Result> { + self.inner + .describe_db_cluster_endpoints() + .db_cluster_identifier(cluster_identifier) + .send() + .await + } + // snippet-end:[rust.aurora.describe_db_cluster_endpoints.wrapper] + + // snippet-start:[rust.aurora.delete_db_instance.wrapper] + pub async fn delete_db_instance( + &self, + instance_identifier: &str, + ) -> Result> { + self.inner + .delete_db_instance() + .db_instance_identifier(instance_identifier) + .skip_final_snapshot(true) + .send() + .await + } + // snippet-end:[rust.aurora.delete_db_instance.wrapper] + + // snippet-start:[rust.aurora.delete_db_cluster.wrapper] + pub async fn delete_db_cluster( + &self, + cluster_identifier: &str, + ) -> Result> { + self.inner + .delete_db_cluster() + .db_cluster_identifier(cluster_identifier) + .skip_final_snapshot(true) + .send() + .await + } + // snippet-end:[rust.aurora.delete_db_cluster.wrapper] + + // snippet-start:[rust.aurora.delete_db_cluster_parameter_group.wrapper] + pub async fn delete_db_cluster_parameter_group( + &self, + name: &str, + ) -> Result> + { + self.inner + .delete_db_cluster_parameter_group() + .db_cluster_parameter_group_name(name) + .send() + .await + } + // snippet-end:[rust.aurora.delete_db_cluster_parameter_group.wrapper] +} diff --git a/rust_dev_preview/examples/auto-scaling/Cargo.toml b/rust_dev_preview/examples/auto-scaling/Cargo.toml index 60514e18223..e24873e947d 100644 --- a/rust_dev_preview/examples/auto-scaling/Cargo.toml +++ b/rust_dev_preview/examples/auto-scaling/Cargo.toml @@ -12,7 +12,7 @@ aws-sdk-autoscaling = { git = "https://github.com/awslabs/aws-sdk-rust", branch aws-sdk-ec2 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } anyhow = "1.0.75" tracing = "0.1.37" diff --git a/rust_dev_preview/examples/autoscalingplans/Cargo.toml b/rust_dev_preview/examples/autoscalingplans/Cargo.toml index c8a69e21991..29cbf65ecde 100644 --- a/rust_dev_preview/examples/autoscalingplans/Cargo.toml +++ b/rust_dev_preview/examples/autoscalingplans/Cargo.toml @@ -14,5 +14,5 @@ aws-sdk-autoscalingplans = { git = "https://github.com/awslabs/aws-sdk-rust", br aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/batch/Cargo.toml b/rust_dev_preview/examples/batch/Cargo.toml index 37b22f127f4..68079b586ba 100644 --- a/rust_dev_preview/examples/batch/Cargo.toml +++ b/rust_dev_preview/examples/batch/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-batch = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/cloudformation/Cargo.toml b/rust_dev_preview/examples/cloudformation/Cargo.toml index b41424e399e..de701d2ba24 100644 --- a/rust_dev_preview/examples/cloudformation/Cargo.toml +++ b/rust_dev_preview/examples/cloudformation/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-cloudformation = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/cloudwatch/Cargo.toml b/rust_dev_preview/examples/cloudwatch/Cargo.toml index bfcdcb058d2..71df748c7b4 100644 --- a/rust_dev_preview/examples/cloudwatch/Cargo.toml +++ b/rust_dev_preview/examples/cloudwatch/Cargo.toml @@ -14,5 +14,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-cloudwatch = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/cloudwatchlogs/Cargo.toml b/rust_dev_preview/examples/cloudwatchlogs/Cargo.toml index 18e86dfc62b..deeb2e6a5da 100644 --- a/rust_dev_preview/examples/cloudwatchlogs/Cargo.toml +++ b/rust_dev_preview/examples/cloudwatchlogs/Cargo.toml @@ -15,5 +15,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-cloudwatchlogs = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/cognitoidentity/Cargo.toml b/rust_dev_preview/examples/cognitoidentity/Cargo.toml index 3b9a0c66fc1..612a15f9592 100644 --- a/rust_dev_preview/examples/cognitoidentity/Cargo.toml +++ b/rust_dev_preview/examples/cognitoidentity/Cargo.toml @@ -16,7 +16,7 @@ aws-smithy-types-convert = { git = "https://github.com/awslabs/aws-sdk-rust", br "convert-chrono", ] } chrono = "0.4" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/cognitoidentityprovider/Cargo.toml b/rust_dev_preview/examples/cognitoidentityprovider/Cargo.toml index 91b52cc9f9e..884083a312b 100644 --- a/rust_dev_preview/examples/cognitoidentityprovider/Cargo.toml +++ b/rust_dev_preview/examples/cognitoidentityprovider/Cargo.toml @@ -15,7 +15,7 @@ aws-sdk-cognitoidentityprovider = { git = "https://github.com/awslabs/aws-sdk-ru aws-smithy-types-convert = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = [ "convert-chrono", ] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } \ No newline at end of file diff --git a/rust_dev_preview/examples/cognitosync/Cargo.toml b/rust_dev_preview/examples/cognitosync/Cargo.toml index 1bed3c346e0..75ff49f5131 100644 --- a/rust_dev_preview/examples/cognitosync/Cargo.toml +++ b/rust_dev_preview/examples/cognitosync/Cargo.toml @@ -15,7 +15,7 @@ aws-sdk-cognitosync = { git = "https://github.com/awslabs/aws-sdk-rust", branch aws-smithy-types-convert = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = [ "convert-chrono", ] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } \ No newline at end of file diff --git a/rust_dev_preview/examples/concurrency/Cargo.toml b/rust_dev_preview/examples/concurrency/Cargo.toml index 1b78945833c..4f7f7c8f524 100644 --- a/rust_dev_preview/examples/concurrency/Cargo.toml +++ b/rust_dev_preview/examples/concurrency/Cargo.toml @@ -14,7 +14,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } futures = "0.3.25" tokio = { version = "1.20.1", features = ["full"] } tracing = "0.1.37" diff --git a/rust_dev_preview/examples/config/Cargo.toml b/rust_dev_preview/examples/config/Cargo.toml index a02f0d64d01..da03a3ccb5a 100644 --- a/rust_dev_preview/examples/config/Cargo.toml +++ b/rust_dev_preview/examples/config/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/dynamodb/Cargo.toml b/rust_dev_preview/examples/dynamodb/Cargo.toml index eadc56e11a9..63a8aff9ef2 100644 --- a/rust_dev_preview/examples/dynamodb/Cargo.toml +++ b/rust_dev_preview/examples/dynamodb/Cargo.toml @@ -18,7 +18,7 @@ aws-smithy-http = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "n aws-smithy-runtime = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = ["test-util"] } aws-smithy-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } axum = "0.5.16" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } futures = "0.3" http = "0.2.5" log = "0.4.17" diff --git a/rust_dev_preview/examples/ebs/Cargo.toml b/rust_dev_preview/examples/ebs/Cargo.toml index 2d511673e84..40f689bde8e 100644 --- a/rust_dev_preview/examples/ebs/Cargo.toml +++ b/rust_dev_preview/examples/ebs/Cargo.toml @@ -16,5 +16,5 @@ aws-sdk-ec2 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" tokio = { version = "1.20.1", features = ["full"] } base64 = "0.13.0" sha2 = "0.9.5" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/ec2/Cargo.toml b/rust_dev_preview/examples/ec2/Cargo.toml index 400eb63a003..d8bafb16102 100644 --- a/rust_dev_preview/examples/ec2/Cargo.toml +++ b/rust_dev_preview/examples/ec2/Cargo.toml @@ -15,5 +15,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-ec2 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/ecr/Cargo.toml b/rust_dev_preview/examples/ecr/Cargo.toml index b39cf19ed24..02a30cbe237 100644 --- a/rust_dev_preview/examples/ecr/Cargo.toml +++ b/rust_dev_preview/examples/ecr/Cargo.toml @@ -12,5 +12,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-ecr = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/ecs/Cargo.toml b/rust_dev_preview/examples/ecs/Cargo.toml index a0d4291f43a..d4f167ad6a5 100644 --- a/rust_dev_preview/examples/ecs/Cargo.toml +++ b/rust_dev_preview/examples/ecs/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-ecs = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/eks/Cargo.toml b/rust_dev_preview/examples/eks/Cargo.toml index e0e9dc6d1e3..2b52c925b5b 100644 --- a/rust_dev_preview/examples/eks/Cargo.toml +++ b/rust_dev_preview/examples/eks/Cargo.toml @@ -12,5 +12,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-eks = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/firehose/Cargo.toml b/rust_dev_preview/examples/firehose/Cargo.toml index 43eebf0acf8..17355aca34e 100644 --- a/rust_dev_preview/examples/firehose/Cargo.toml +++ b/rust_dev_preview/examples/firehose/Cargo.toml @@ -12,6 +12,6 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-firehose = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/globalaccelerator/Cargo.toml b/rust_dev_preview/examples/globalaccelerator/Cargo.toml index 7f8dd7a01c1..bbfc8931f23 100644 --- a/rust_dev_preview/examples/globalaccelerator/Cargo.toml +++ b/rust_dev_preview/examples/globalaccelerator/Cargo.toml @@ -11,5 +11,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-globalaccelerator = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } tokio-stream = "0.1.8" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/glue/Cargo.toml b/rust_dev_preview/examples/glue/Cargo.toml index 5b6e0daa005..5cd8e2a768b 100644 --- a/rust_dev_preview/examples/glue/Cargo.toml +++ b/rust_dev_preview/examples/glue/Cargo.toml @@ -27,7 +27,7 @@ tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } tracing = "0.1.37" async_once = "0.2.6" lazy_static = "1.4.0" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0.37" secrecy = "0.8.0" uuid = { version = "1.2.1", features = ["v4"] } diff --git a/rust_dev_preview/examples/greengrassv2/Cargo.toml b/rust_dev_preview/examples/greengrassv2/Cargo.toml index 99fbd085b9b..bd42e8c7fa5 100644 --- a/rust_dev_preview/examples/greengrassv2/Cargo.toml +++ b/rust_dev_preview/examples/greengrassv2/Cargo.toml @@ -9,5 +9,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-greengrassv2 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.5", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/iam/Cargo.toml b/rust_dev_preview/examples/iam/Cargo.toml index 1ae201bd600..3a764467e29 100644 --- a/rust_dev_preview/examples/iam/Cargo.toml +++ b/rust_dev_preview/examples/iam/Cargo.toml @@ -24,7 +24,7 @@ aws-sdk-s3 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-sts = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } sdk-examples-test-utils = { path = "../../test-utils" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } uuid = { version = "0.8", features = ["serde", "v4"] } tower-service = "0.3.2" diff --git a/rust_dev_preview/examples/iot/Cargo.toml b/rust_dev_preview/examples/iot/Cargo.toml index bfb822f2bc4..14baa96e34e 100644 --- a/rust_dev_preview/examples/iot/Cargo.toml +++ b/rust_dev_preview/examples/iot/Cargo.toml @@ -11,5 +11,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-iot = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/kinesis/Cargo.toml b/rust_dev_preview/examples/kinesis/Cargo.toml index 58c0b5b9007..8770ea46185 100644 --- a/rust_dev_preview/examples/kinesis/Cargo.toml +++ b/rust_dev_preview/examples/kinesis/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-kinesis = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/kms/Cargo.toml b/rust_dev_preview/examples/kms/Cargo.toml index 4cd0f82d5d3..ba1ebaf9e52 100644 --- a/rust_dev_preview/examples/kms/Cargo.toml +++ b/rust_dev_preview/examples/kms/Cargo.toml @@ -13,5 +13,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-kms = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } base64 = "0.13.0" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/lambda/Cargo.toml b/rust_dev_preview/examples/lambda/Cargo.toml index 654cce1517b..2352f4c5b35 100644 --- a/rust_dev_preview/examples/lambda/Cargo.toml +++ b/rust_dev_preview/examples/lambda/Cargo.toml @@ -13,7 +13,7 @@ aws-sdk-lambda = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "ne aws-sdk-s3 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-smithy-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } tracing = "0.1.37" diff --git a/rust_dev_preview/examples/logging/logger/Cargo.toml b/rust_dev_preview/examples/logging/logger/Cargo.toml index b74c10122c7..90b72ceb937 100644 --- a/rust_dev_preview/examples/logging/logger/Cargo.toml +++ b/rust_dev_preview/examples/logging/logger/Cargo.toml @@ -16,6 +16,6 @@ aws-sdk-dynamodb = { git = "https://github.com/awslabs/aws-sdk-rust", branch = " # snippet-start:[logging.rust.logger-cargo.toml-env_logger] env_logger = "0.9.0" # snippet-end:[logging.rust.logger-cargo.toml-env_logger] -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tokio = { version = "1.20.1", features = ["full"] } # snippet-end:[logging.rust.logger-cargo.toml] diff --git a/rust_dev_preview/examples/logging/tracing/Cargo.toml b/rust_dev_preview/examples/logging/tracing/Cargo.toml index e5ff64e0393..ace0828c4e1 100644 --- a/rust_dev_preview/examples/logging/tracing/Cargo.toml +++ b/rust_dev_preview/examples/logging/tracing/Cargo.toml @@ -13,7 +13,7 @@ version = "0.1.0" [dependencies] aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-dynamodb = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tokio = { version = "1.20.1", features = ["full"] } # snippet-start:[logging.rust.tracing-cargo.toml-tracing_subscriber] tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/medialive/Cargo.toml b/rust_dev_preview/examples/medialive/Cargo.toml index d426fb0abc8..b662e554659 100644 --- a/rust_dev_preview/examples/medialive/Cargo.toml +++ b/rust_dev_preview/examples/medialive/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-medialive = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/mediapackage/Cargo.toml b/rust_dev_preview/examples/mediapackage/Cargo.toml index e2b20a595ff..c91c4f34f5e 100644 --- a/rust_dev_preview/examples/mediapackage/Cargo.toml +++ b/rust_dev_preview/examples/mediapackage/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-mediapackage = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/polly/Cargo.toml b/rust_dev_preview/examples/polly/Cargo.toml index 47e9923a230..b8d63f71a64 100644 --- a/rust_dev_preview/examples/polly/Cargo.toml +++ b/rust_dev_preview/examples/polly/Cargo.toml @@ -14,5 +14,5 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-polly = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } bytes = "1" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/qldb/Cargo.toml b/rust_dev_preview/examples/qldb/Cargo.toml index eec1e220767..e1c64525f17 100644 --- a/rust_dev_preview/examples/qldb/Cargo.toml +++ b/rust_dev_preview/examples/qldb/Cargo.toml @@ -15,5 +15,5 @@ aws-sdk-qldb = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next aws-sdk-qldbsession = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } tokio-stream = { version = "0.1.9", features = ["default"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/rds/Cargo.toml b/rust_dev_preview/examples/rds/Cargo.toml index eb9673d580a..5c8be6e452c 100644 --- a/rust_dev_preview/examples/rds/Cargo.toml +++ b/rust_dev_preview/examples/rds/Cargo.toml @@ -3,6 +3,7 @@ name = "rds-code-examples" authors = [ "LMJW ", "Doug Schwartz ", + "David Souther ", ] edition = "2021" version = "0.1.0" @@ -10,8 +11,19 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.75" +assert_matches = "1.5.0" +async-trait = "0.1.73" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } +aws-smithy-http = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } +aws-smithy-runtime-api = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-rds = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } -tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } +inquire = "0.6.2" +mockall = "0.11.4" +phf = { version = "0.11.2", features = ["std", "macros"] } +sdk-examples-test-utils = { path = "../../test-utils" } +secrecy = "0.8.0" +tokio = { version = "1.20.1", features = ["full", "test-util"] } +tracing = "0.1.37" tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/rds/README.md b/rust_dev_preview/examples/rds/README.md index 64d156cc19c..4c08dbd97f1 100644 --- a/rust_dev_preview/examples/rds/README.md +++ b/rust_dev_preview/examples/rds/README.md @@ -1,4 +1,5 @@ + # Amazon RDS code examples for the SDK for Rust ## Overview @@ -8,14 +9,14 @@ Shows how to use the AWS SDK for Rust to work with Amazon Relational Database Se -*Amazon RDS is a web service that makes it easier to set up, operate, and scale a relational database in the cloud.* +_Amazon RDS is a web service that makes it easier to set up, operate, and scale a relational database in the cloud._ ## ⚠ Important -* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/?aws-products-pricing.sort-by=item.additionalFields.productNameLowercase&aws-products-pricing.sort-order=asc&awsf.Free%20Tier%20Type=*all&awsf.tech-category=*all) and [Free Tier](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all). -* Running the tests might result in charges to your AWS account. -* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). -* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). +- Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/?aws-products-pricing.sort-by=item.additionalFields.productNameLowercase&aws-products-pricing.sort-order=asc&awsf.Free%20Tier%20Type=*all&awsf.tech-category=*all) and [Free Tier](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all). +- Running the tests might result in charges to your AWS account. +- We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +- This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). @@ -26,7 +27,6 @@ Shows how to use the AWS SDK for Rust to work with Amazon Relational Database Se For prerequisites, see the [README](../../README.md#Prerequisites) in the `rust_dev_preview` folder. - @@ -34,30 +34,24 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `rust_ ### Instructions - - - ### Tests ⚠ Running tests might result in charges to your AWS account. - To find instructions for running these tests, see the [README](../../README.md#Tests) in the `rust_dev_preview` folder. - - ## Additional resources -* [Amazon RDS User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) -* [Amazon RDS API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/Welcome.html) -* [SDK for Rust Amazon RDS reference](https://docs.rs/aws-sdk-rds/latest/aws_sdk_rds/) +- [Amazon RDS User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) +- [Amazon RDS API Reference](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/Welcome.html) +- [SDK for Rust Amazon RDS reference](https://docs.rs/aws-sdk-rds/latest/aws_sdk_rds/) @@ -66,4 +60,4 @@ in the `rust_dev_preview` folder. Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -SPDX-License-Identifier: Apache-2.0 \ No newline at end of file +SPDX-License-Identifier: Apache-2.0 diff --git a/rust_dev_preview/examples/rdsdata/Cargo.toml b/rust_dev_preview/examples/rdsdata/Cargo.toml index 42fede9ceea..6591e3ee8f9 100644 --- a/rust_dev_preview/examples/rdsdata/Cargo.toml +++ b/rust_dev_preview/examples/rdsdata/Cargo.toml @@ -13,5 +13,5 @@ version = "0.1.0" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-rdsdata = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/route53/Cargo.toml b/rust_dev_preview/examples/route53/Cargo.toml index bd1e4354712..7ac833d7e3c 100644 --- a/rust_dev_preview/examples/route53/Cargo.toml +++ b/rust_dev_preview/examples/route53/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-route53 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/s3/Cargo.toml b/rust_dev_preview/examples/s3/Cargo.toml index 432d66defa8..462e865e7f8 100644 --- a/rust_dev_preview/examples/s3/Cargo.toml +++ b/rust_dev_preview/examples/s3/Cargo.toml @@ -37,7 +37,7 @@ http = "0.2.8" http-body = "0.4.5" md-5 = "0.10.1" rand = "0.8.5" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tokio-stream = "0.1.8" diff --git a/rust_dev_preview/examples/sagemaker/Cargo.toml b/rust_dev_preview/examples/sagemaker/Cargo.toml index a4f67959b1b..8904a80d4e6 100644 --- a/rust_dev_preview/examples/sagemaker/Cargo.toml +++ b/rust_dev_preview/examples/sagemaker/Cargo.toml @@ -15,7 +15,7 @@ aws-sdk-sagemaker = { git = "https://github.com/awslabs/aws-sdk-rust", branch = aws-smithy-types-convert = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = [ "convert-chrono", ] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/sdk-config/Cargo.toml b/rust_dev_preview/examples/sdk-config/Cargo.toml index 9f9901b72b3..70c56c1fc1c 100644 --- a/rust_dev_preview/examples/sdk-config/Cargo.toml +++ b/rust_dev_preview/examples/sdk-config/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-s3 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } lazy_static = "1.4.0" async_once = "0.2.6" diff --git a/rust_dev_preview/examples/secretsmanager/Cargo.toml b/rust_dev_preview/examples/secretsmanager/Cargo.toml index 0a99c81805a..889f1f74318 100644 --- a/rust_dev_preview/examples/secretsmanager/Cargo.toml +++ b/rust_dev_preview/examples/secretsmanager/Cargo.toml @@ -12,5 +12,5 @@ description = "Example usage of the SecretManager service" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-secretsmanager = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/sending-presigned-requests/Cargo.toml b/rust_dev_preview/examples/sending-presigned-requests/Cargo.toml index 7c3718c1621..7d326721311 100644 --- a/rust_dev_preview/examples/sending-presigned-requests/Cargo.toml +++ b/rust_dev_preview/examples/sending-presigned-requests/Cargo.toml @@ -13,7 +13,7 @@ aws-smithy-client = { git = "https://github.com/awslabs/aws-sdk-rust", branch = http = "0.2.6" hyper = "0.14" reqwest = "0.11" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } hyper-tls = "0.5.0" diff --git a/rust_dev_preview/examples/ses/Cargo.toml b/rust_dev_preview/examples/ses/Cargo.toml index 71af726db33..b9ef5b5c0d8 100644 --- a/rust_dev_preview/examples/ses/Cargo.toml +++ b/rust_dev_preview/examples/ses/Cargo.toml @@ -11,5 +11,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-sesv2 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/sitewise/Cargo.toml b/rust_dev_preview/examples/sitewise/Cargo.toml index c5f2cbc48dc..be1f3aaec1c 100644 --- a/rust_dev_preview/examples/sitewise/Cargo.toml +++ b/rust_dev_preview/examples/sitewise/Cargo.toml @@ -12,7 +12,7 @@ aws-sdk-iotsitewise = { git = "https://github.com/awslabs/aws-sdk-rust", branch aws-smithy-types-convert = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = [ "convert-chrono", ] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } \ No newline at end of file diff --git a/rust_dev_preview/examples/snowball/Cargo.toml b/rust_dev_preview/examples/snowball/Cargo.toml index 9ced58e12f7..97f9f5e487e 100644 --- a/rust_dev_preview/examples/snowball/Cargo.toml +++ b/rust_dev_preview/examples/snowball/Cargo.toml @@ -10,5 +10,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-snowball = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/sns/Cargo.toml b/rust_dev_preview/examples/sns/Cargo.toml index 12f3ef05fb2..57b95ba165d 100644 --- a/rust_dev_preview/examples/sns/Cargo.toml +++ b/rust_dev_preview/examples/sns/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-sns = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/sqs/Cargo.toml b/rust_dev_preview/examples/sqs/Cargo.toml index b89cad6e580..19d8b3d738f 100644 --- a/rust_dev_preview/examples/sqs/Cargo.toml +++ b/rust_dev_preview/examples/sqs/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-sqs = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/ssm/Cargo.toml b/rust_dev_preview/examples/ssm/Cargo.toml index 41d13d31cab..b97f44573fd 100644 --- a/rust_dev_preview/examples/ssm/Cargo.toml +++ b/rust_dev_preview/examples/ssm/Cargo.toml @@ -13,5 +13,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-ssm = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/stepfunction/Cargo.toml b/rust_dev_preview/examples/stepfunction/Cargo.toml index 73d59a27ec2..5925a62ca60 100644 --- a/rust_dev_preview/examples/stepfunction/Cargo.toml +++ b/rust_dev_preview/examples/stepfunction/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-sfn = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/sts/Cargo.toml b/rust_dev_preview/examples/sts/Cargo.toml index 4905d26a212..1b92f2a1c52 100644 --- a/rust_dev_preview/examples/sts/Cargo.toml +++ b/rust_dev_preview/examples/sts/Cargo.toml @@ -13,6 +13,6 @@ aws-config = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-sts = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-types = {git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } tokio = { version = "1.20.1", features = ["full"] } -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/examples/testing/Cargo.toml b/rust_dev_preview/examples/testing/Cargo.toml index 59f75ba26f3..3512027350f 100644 --- a/rust_dev_preview/examples/testing/Cargo.toml +++ b/rust_dev_preview/examples/testing/Cargo.toml @@ -20,7 +20,7 @@ aws-credential-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch ] } tokio = { version = "1.20.1", features = ["full"] } serde_json = "1" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } [[bin]] diff --git a/rust_dev_preview/examples/transcribestreaming/Cargo.toml b/rust_dev_preview/examples/transcribestreaming/Cargo.toml index 8d5b8358626..9a6492580f6 100644 --- a/rust_dev_preview/examples/transcribestreaming/Cargo.toml +++ b/rust_dev_preview/examples/transcribestreaming/Cargo.toml @@ -15,6 +15,6 @@ aws-sdk-transcribestreaming = { git = "https://github.com/awslabs/aws-sdk-rust", async-stream = "0.3" bytes = "1" hound = "3.4" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } diff --git a/rust_dev_preview/lambda/calculator/Cargo.toml b/rust_dev_preview/lambda/calculator/Cargo.toml index 120ed2fe232..8a3e9c617f2 100644 --- a/rust_dev_preview/lambda/calculator/Cargo.toml +++ b/rust_dev_preview/lambda/calculator/Cargo.toml @@ -14,7 +14,7 @@ aws-sdk-ec2 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" aws-sdk-lambda = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } aws-sdk-s3 = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next" } lambda_runtime = "0.8.0" -clap = { version = "~4.2", features = ["derive"] } +clap = { version = "~4.4", features = ["derive"] } tokio = { version = "1.20.1", features = ["full"] } tracing-subscriber = { version = "0.3.15", features = ["env-filter", "json"] } time = "0.3" diff --git a/rust_dev_preview/test-utils/Cargo.toml b/rust_dev_preview/test-utils/Cargo.toml index 2cc5b68ec19..8763c006f46 100644 --- a/rust_dev_preview/test-utils/Cargo.toml +++ b/rust_dev_preview/test-utils/Cargo.toml @@ -14,6 +14,7 @@ aws-smithy-http = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "n aws-smithy-runtime = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next", features = ["test-util"] } aws-types = { git = "https://github.com/awslabs/aws-sdk-rust", branch = "next"} http = "0.2" +tokio = "1.33.0" [lib] -path="src/mod.rs" \ No newline at end of file +path="src/mod.rs" diff --git a/rust_dev_preview/test-utils/src/mod.rs b/rust_dev_preview/test-utils/src/mod.rs index a8a97c6733e..f84fe202418 100644 --- a/rust_dev_preview/test-utils/src/mod.rs +++ b/rust_dev_preview/test-utils/src/mod.rs @@ -1,6 +1,7 @@ use aws_smithy_http::body::SdkBody; pub mod macros; +pub mod waiter; /// Create a single-shot test connection. The arguments are the same as test_event, /// but the expanded macro creates a TestConnection. The `TestConnection` can be diff --git a/rust_dev_preview/test-utils/src/waiter.rs b/rust_dev_preview/test-utils/src/waiter.rs new file mode 100644 index 00000000000..81ab19898d5 --- /dev/null +++ b/rust_dev_preview/test-utils/src/waiter.rs @@ -0,0 +1,90 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +use std::{ + error::Error, + fmt::Display, + time::{Duration, SystemTime}, +}; +use tokio; + +// Wait at most 25 seconds. +const MAX_WAIT: Duration = Duration::from_secs(5 * 60); +// Wait half a second at a time. +const POLL_TIME: Duration = Duration::from_millis(500); + +#[derive(Debug)] +pub struct WaitError(Duration); +impl Error for WaitError {} +impl Display for WaitError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Waiter expired while sleeping for {:.3}s", + self.0.as_secs_f32() + ) + } +} + +pub struct Waiter { + start: SystemTime, + max: Duration, + poll: Duration, +} + +impl Waiter { + pub fn builder() -> WaiterBuilder { + WaiterBuilder::default() + } + + fn new(max: Duration, poll: Duration) -> Self { + Waiter { + start: SystemTime::now(), + max, + poll, + } + } + + pub async fn sleep(&self) -> Result<(), WaitError> { + if SystemTime::now() + .duration_since(self.start) + .unwrap_or(Duration::MAX) + > self.max + { + Err(WaitError(self.max)) + } else { + tokio::time::sleep(self.poll).await; + Ok(()) + } + } +} + +impl Default for Waiter { + fn default() -> Self { + Waiter::new(MAX_WAIT, POLL_TIME) + } +} + +#[derive(Default)] +pub struct WaiterBuilder { + max: Option, + poll: Option, +} + +impl WaiterBuilder { + pub fn poll(mut self, poll: Duration) -> Self { + self.poll = Some(poll); + self + } + + pub fn max(mut self, max: Duration) -> Self { + self.max = Some(max); + self + } + + pub fn build(self) -> Waiter { + Waiter::new(self.max.unwrap_or(MAX_WAIT), self.poll.unwrap_or(POLL_TIME)) + } +}