diff --git a/package-lock.json b/package-lock.json index 61e810bc..87ce5207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "MIT", "dependencies": { "@pulumi/aws": "^7.23.0", - "@pulumi/aws-native": "^1.57.0", "@pulumi/awsx": "^3.3.0", "@pulumi/pulumi": "^3.226.0", "@pulumi/random": "^4.19.1", @@ -3168,7 +3167,6 @@ "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -3325,7 +3323,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -3977,16 +3974,6 @@ "mime": "^2.0.0" } }, - "node_modules/@pulumi/aws-native": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/@pulumi/aws-native/-/aws-native-1.57.0.tgz", - "integrity": "sha512-T9rzxRSQo5xNvjdxbCQZZ+n4CwwdQgMZlzioHH9BQEJxEM30kX+vQGL5B49JEKh9S0ufY1hPUFZSyZAyrXP8XQ==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@pulumi/pulumi": "^3.142.0" - } - }, "node_modules/@pulumi/aws/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -5111,7 +5098,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8923,7 +8909,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 2f199be2..1a2cecd1 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "prettier": "@studion/prettier-config", "dependencies": { "@pulumi/aws": "^7.23.0", - "@pulumi/aws-native": "^1.57.0", "@pulumi/awsx": "^3.3.0", "@pulumi/pulumi": "^3.226.0", "@pulumi/random": "^4.19.1", diff --git a/src/components/database/database-replica.ts b/src/components/database/database-replica.ts index 2395214b..bb09ed14 100644 --- a/src/components/database/database-replica.ts +++ b/src/components/database/database-replica.ts @@ -102,6 +102,7 @@ export class DatabaseReplica extends pulumi.ComponentResource { applyImmediately: argsWithDefaults.applyImmediately, allowMajorVersionUpgrade: argsWithDefaults.allowMajorVersionUpgrade, autoMinorVersionUpgrade: argsWithDefaults.autoMinorVersionUpgrade, + maintenanceWindow: 'Mon:07:00-Mon:07:30', replicateSourceDb: argsWithDefaults.replicateSourceDb, parameterGroupName: argsWithDefaults.parameterGroupName, storageEncrypted: true, diff --git a/src/components/database/index.ts b/src/components/database/index.ts index b539d1fc..8dd6f571 100644 --- a/src/components/database/index.ts +++ b/src/components/database/index.ts @@ -1,5 +1,4 @@ import * as aws from '@pulumi/aws'; -import * as awsNative from '@pulumi/aws-native'; import * as awsx from '@pulumi/awsx'; import * as pulumi from '@pulumi/pulumi'; import { commonTags } from '../../shared/common-tags'; @@ -17,6 +16,7 @@ export namespace Database { allowMajorVersionUpgrade?: pulumi.Input; autoMinorVersionUpgrade?: pulumi.Input; applyImmediately?: pulumi.Input; + skipFinalSnapshot?: pulumi.Input; }; export type Credentials = { @@ -66,6 +66,7 @@ export namespace Database { const defaults = { multiAz: false, applyImmediately: false, + skipFinalSnapshot: false, allocatedStorage: 20, maxAllocatedStorage: 100, instanceClass: 'db.t4g.micro', @@ -77,7 +78,7 @@ const defaults = { export class Database extends pulumi.ComponentResource { name: string; - instance: awsNative.rds.DbInstance; + instance: aws.rds.Instance; vpc: pulumi.Output; dbSubnetGroup: aws.rds.SubnetGroup; dbSecurityGroup: aws.ec2.SecurityGroup; @@ -262,7 +263,7 @@ export class Database extends pulumi.ComponentResource { const replica = new DatabaseReplica( `${this.name}-replica`, { - replicateSourceDb: this.instance.dbInstanceIdentifier.apply(id => id!), + replicateSourceDb: this.instance.identifier.apply(id => id!), dbSecurityGroup: this.dbSecurityGroup, monitoringRole, ...config, @@ -285,29 +286,31 @@ export class Database extends pulumi.ComponentResource { } private createDatabaseInstance(args: Database.Args) { + const stack = pulumi.getStack(); + const monitoringOptions = args.enableMonitoring && this.monitoringRole ? { monitoringInterval: 60, monitoringRoleArn: this.monitoringRole.arn, - enablePerformanceInsights: true, + performanceInsightsEnabled: true, performanceInsightsRetentionPeriod: 7, } : {}; - const instance = new awsNative.rds.DbInstance( + const instance = new aws.rds.Instance( `${this.name}-rds`, { - dbInstanceIdentifier: `${this.name}-db-instance`, + identifierPrefix: `${this.name}-`, engine: 'postgres', engineVersion: args.engineVersion, - dbInstanceClass: args.instanceClass, + instanceClass: args.instanceClass!, dbName: args.dbName, - masterUsername: args.username, - masterUserPassword: this.password.value, + username: args.username, + password: this.password.value, dbSubnetGroupName: this.dbSubnetGroup.name, - vpcSecurityGroups: [this.dbSecurityGroup.id], - allocatedStorage: args.allocatedStorage?.toString(), + vpcSecurityGroupIds: [this.dbSecurityGroup.id], + allocatedStorage: args.allocatedStorage, maxAllocatedStorage: args.maxAllocatedStorage, multiAz: args.multiAz, applyImmediately: args.applyImmediately, @@ -316,21 +319,17 @@ export class Database extends pulumi.ComponentResource { kmsKeyId: this.kmsKeyId, storageEncrypted: true, publiclyAccessible: false, - preferredMaintenanceWindow: 'Mon:07:00-Mon:07:30', - preferredBackupWindow: '06:00-06:30', + skipFinalSnapshot: args.skipFinalSnapshot, + maintenanceWindow: 'Mon:07:00-Mon:07:30', + finalSnapshotIdentifier: `${this.name}-final-snapshot-${stack}`, + backupWindow: '06:00-06:30', backupRetentionPeriod: 14, - caCertificateIdentifier: 'rds-ca-rsa2048-g1', - dbParameterGroupName: args.parameterGroupName, - dbSnapshotIdentifier: + caCertIdentifier: 'rds-ca-rsa2048-g1', + parameterGroupName: args.parameterGroupName, + snapshotIdentifier: this.encryptedSnapshotCopy?.targetDbSnapshotIdentifier, ...monitoringOptions, - tags: pulumi - .output(args.tags) - .apply(tags => [ - ...Object.entries({ ...commonTags, ...tags }).map( - ([key, value]) => ({ key, value }), - ), - ]), + tags: { ...commonTags, ...args.tags }, }, { parent: this, dependsOn: [this.password] }, ); diff --git a/tests/database/configurable-db.test.ts b/tests/database/configurable-db.test.ts index b21bd3e6..32cd774b 100644 --- a/tests/database/configurable-db.test.ts +++ b/tests/database/configurable-db.test.ts @@ -23,7 +23,7 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { assert.ok(configurableDb.instance, 'Database instance should be defined'); const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: configurableDb.instance.dbInstanceIdentifier, + DBInstanceIdentifier: configurableDb.instance.identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); @@ -34,7 +34,7 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { const [DBInstance] = DBInstances; assert.strictEqual( DBInstance.DBInstanceIdentifier, - configurableDb.instance.dbInstanceIdentifier, + configurableDb.instance.identifier, 'Database instance identifier should match', ); }); @@ -57,6 +57,11 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { ctx.config.autoMinorVersionUpgrade, 'Auto minor version upgrade argument should be set correctly', ); + assert.strictEqual( + configurableDb.instance.skipFinalSnapshot, + ctx.config.skipFinalSnapshot, + 'Skip final snapshot argument should be set correctly', + ); }); it('should properly configure password', () => { @@ -64,9 +69,9 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { assert.ok(configurableDb.password, 'Password should exist'); assert.strictEqual( - configurableDb.instance.masterUserPassword, + configurableDb.instance.password, ctx.config.dbPassword, - 'Master user password should be set correctly', + 'Password should be set correctly', ); }); @@ -75,7 +80,7 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { assert.strictEqual( configurableDb.instance.allocatedStorage, - ctx.config.allocatedStorage.toString(), + ctx.config.allocatedStorage, 'Allocated storage argument should be set correctly', ); assert.strictEqual( @@ -89,7 +94,7 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { const configurableDb = ctx.outputs.configurableDb.value; assert.strictEqual( - configurableDb.instance.enablePerformanceInsights, + configurableDb.instance.performanceInsightsEnabled, true, 'Performance insights should be enabled', ); @@ -152,7 +157,7 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { const paramGroup = ctx.outputs.paramGroup.value; assert.strictEqual( - configurableDb.instance.dbParameterGroupName, + configurableDb.instance.parameterGroupName, paramGroup.name, 'Parameter group name should be set correctly', ); @@ -162,7 +167,7 @@ export function testConfigurableDb(ctx: DatabaseTestContext) { const configurableDb = ctx.outputs.configurableDb.value; const command = new ListTagsForResourceCommand({ - ResourceName: configurableDb.instance.dbInstanceArn, + ResourceName: configurableDb.instance.arn, }); const { TagList } = await ctx.clients.rds.send(command); assert.ok(TagList && TagList.length > 0, 'Tags should exist'); diff --git a/tests/database/configurable-replica-db.test.ts b/tests/database/configurable-replica-db.test.ts index 78b8cf12..e8aea512 100644 --- a/tests/database/configurable-replica-db.test.ts +++ b/tests/database/configurable-replica-db.test.ts @@ -9,17 +9,17 @@ import { it } from 'node:test'; export function testConfigurableReplica(ctx: DatabaseTestContext) { it('should create a primary instance with a configurable replica', async () => { const configurableReplicaDb = ctx.outputs.configurableReplicaDb.value; - const { dbInstanceIdentifier } = configurableReplicaDb.instance; + const { identifier } = configurableReplicaDb.instance; const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: dbInstanceIdentifier, + DBInstanceIdentifier: identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); assert.ok( DBInstances && DBInstances.length === 1 && - DBInstances[0].DBInstanceIdentifier === dbInstanceIdentifier, + DBInstances[0].DBInstanceIdentifier === identifier, 'Primary database instance should be created', ); }); diff --git a/tests/database/index.test.ts b/tests/database/index.test.ts index f688ac0e..8e141ff0 100644 --- a/tests/database/index.test.ts +++ b/tests/database/index.test.ts @@ -1,4 +1,3 @@ -import { cleanupReplicas, cleanupSnapshots } from './util'; import { describe, before, after } from 'node:test'; import { DescribeDBInstancesCommand, @@ -54,11 +53,7 @@ describe('Database component deployment', () => { ctx.outputs = await automation.deploy(programArgs); }); - after(async () => { - await cleanupReplicas(ctx); - await automation.destroy(programArgs); - await cleanupSnapshots(ctx); - }); + after(() => automation.destroy(programArgs)); it('should create a database', async () => { const database = ctx.outputs.defaultDb.value; @@ -72,7 +67,7 @@ describe('Database component deployment', () => { assert.ok(database.instance, 'Database instance should be defined'); const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: database.instance.dbInstanceIdentifier, + DBInstanceIdentifier: database.instance.identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); @@ -83,7 +78,7 @@ describe('Database component deployment', () => { const [DBInstance] = DBInstances; assert.strictEqual( DBInstance.DBInstanceIdentifier, - database.instance.dbInstanceIdentifier, + database.instance.identifier, 'Database instance identifier should match', ); }); @@ -104,13 +99,13 @@ describe('Database component deployment', () => { instance, { dbName: ctx.config.dbName, - masterUsername: ctx.config.dbUsername, + username: ctx.config.dbUsername, multiAz: false, applyImmediately: false, - allocatedStorage: '20', + allocatedStorage: 20, maxAllocatedStorage: 100, - dbInstanceClass: 'db.t4g.micro', - enablePerformanceInsights: false, + instanceClass: 'db.t4g.micro', + performanceInsightsEnabled: false, allowMajorVersionUpgrade: false, autoMinorVersionUpgrade: true, engineVersion: '17.2', diff --git a/tests/database/infrastructure/config.ts b/tests/database/infrastructure/config.ts index d43d12ba..78f7324e 100644 --- a/tests/database/infrastructure/config.ts +++ b/tests/database/infrastructure/config.ts @@ -12,5 +12,6 @@ export const dbPassword = 'dbpassword'; export const applyImmediately = true; export const allowMajorVersionUpgrade = true; export const autoMinorVersionUpgrade = false; +export const skipFinalSnapshot = true; export const allocatedStorage = 10; export const maxAllocatedStorage = 50; diff --git a/tests/database/infrastructure/index.ts b/tests/database/infrastructure/index.ts index 87d7ca49..15a97086 100644 --- a/tests/database/infrastructure/index.ts +++ b/tests/database/infrastructure/index.ts @@ -14,6 +14,7 @@ const vpc = util.getCommonVpc(); const defaultDb = new studion.DatabaseBuilder(`${config.appName}-default-db`) .withInstance({ dbName: config.dbName, + skipFinalSnapshot: true, }) .withCredentials({ username: config.dbUsername, @@ -52,6 +53,7 @@ const configurableDb = new studion.DatabaseBuilder( applyImmediately: config.applyImmediately, allowMajorVersionUpgrade: config.allowMajorVersionUpgrade, autoMinorVersionUpgrade: config.autoMinorVersionUpgrade, + skipFinalSnapshot: config.skipFinalSnapshot, }) .withCredentials({ username: config.dbUsername, @@ -68,24 +70,22 @@ const configurableDb = new studion.DatabaseBuilder( .withTags(config.tags) .build({ parent }); -const snapshot = defaultDb.instance.dbInstanceIdentifier.apply( - dbInstanceIdentifier => { - return new aws.rds.Snapshot( - `${config.appName}-snapshot`, - { - dbInstanceIdentifier: dbInstanceIdentifier!, - dbSnapshotIdentifier: `${config.appName}-snapshot-id`, - tags: config.tags, - }, - { parent }, - ); - }, -); +const snapshot = defaultDb.instance.identifier.apply(identifier => { + return new aws.rds.Snapshot( + `${config.appName}-snapshot`, + { + dbInstanceIdentifier: identifier!, + dbSnapshotIdentifier: `${config.appName}-snapshot-id`, + tags: config.tags, + }, + { parent }, + ); +}); const snapshotDb = snapshot.apply(snapshot => { return new studion.DatabaseBuilder(`${config.appName}-snapshot-db`) .withInstance({ - applyImmediately: true, + skipFinalSnapshot: true, }) .withVpc(vpc.vpc) .withTags(config.tags) @@ -96,6 +96,7 @@ const snapshotDb = snapshot.apply(snapshot => { const replicaDb = new studion.DatabaseBuilder(`${config.appName}-replica-db`) .withInstance({ dbName: config.dbName, + skipFinalSnapshot: true, }) .withCredentials({ username: config.dbUsername, @@ -109,6 +110,7 @@ const configurableReplicaDb = new studion.DatabaseBuilder( ) .withInstance({ dbName: config.dbName, + skipFinalSnapshot: true, }) .withCredentials({ username: config.dbUsername, @@ -132,6 +134,7 @@ const ssmConnectDb = new studion.DatabaseBuilder( ) .withInstance({ dbName: config.dbName, + skipFinalSnapshot: true, }) .withCredentials({ username: config.dbUsername, diff --git a/tests/database/replica-db.test.ts b/tests/database/replica-db.test.ts index bc73ea91..f3db6373 100644 --- a/tests/database/replica-db.test.ts +++ b/tests/database/replica-db.test.ts @@ -6,17 +6,17 @@ import { it } from 'node:test'; export function testReplicaDb(ctx: DatabaseTestContext) { it('should create a primary instance with a replica', async () => { const replicaDb = ctx.outputs.replicaDb.value; - const { dbInstanceIdentifier } = replicaDb.instance; + const { identifier } = replicaDb.instance; const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: dbInstanceIdentifier, + DBInstanceIdentifier: identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); assert.ok( DBInstances && DBInstances.length === 1 && - DBInstances[0].DBInstanceIdentifier === dbInstanceIdentifier, + DBInstances[0].DBInstanceIdentifier === identifier, 'Primary database instance should be created', ); }); @@ -47,12 +47,12 @@ export function testReplicaDb(ctx: DatabaseTestContext) { assert.strictEqual( replicaInstance.replicateSourceDb, - dbInstance.dbInstanceIdentifier, + dbInstance.identifier, 'Replica instance should have correct source db instance identifier', ); const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: dbInstance.dbInstanceIdentifier, + DBInstanceIdentifier: dbInstance.identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); @@ -97,9 +97,9 @@ export function testReplicaDb(ctx: DatabaseTestContext) { storageEncrypted: true, publiclyAccessible: false, skipFinalSnapshot: true, - vpcSecurityGroupIds: primaryInstance.vpcSecurityGroups, + vpcSecurityGroupIds: primaryInstance.vpcSecurityGroupIds, dbSubnetGroupName: primaryInstance.dbSubnetGroupName, - parameterGroupName: primaryInstance.dbParameterGroupName, + parameterGroupName: primaryInstance.parameterGroupName, }, 'Replica instance should be configured correctly', ); diff --git a/tests/database/snapshot-db.test.ts b/tests/database/snapshot-db.test.ts index c7131470..f5ff43ee 100644 --- a/tests/database/snapshot-db.test.ts +++ b/tests/database/snapshot-db.test.ts @@ -16,7 +16,7 @@ export function testSnapshotDb(ctx: DatabaseTestContext) { assert.ok(snapshotDb.instance, 'Database instance should be defined'); const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: snapshotDb.instance.dbInstanceIdentifier, + DBInstanceIdentifier: snapshotDb.instance.identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); @@ -27,7 +27,7 @@ export function testSnapshotDb(ctx: DatabaseTestContext) { const [DBInstance] = DBInstances; assert.strictEqual( DBInstance.DBInstanceIdentifier, - snapshotDb.instance.dbInstanceIdentifier, + snapshotDb.instance.identifier, 'Database instance identifier should match', ); }); @@ -66,9 +66,9 @@ export function testSnapshotDb(ctx: DatabaseTestContext) { const snapshotDb = ctx.outputs.snapshotDb.value; assert.strictEqual( - snapshotDb.instance.dbSnapshotIdentifier, + snapshotDb.instance.snapshotIdentifier, snapshotDb.encryptedSnapshotCopy.targetDbSnapshotIdentifier, - 'Db snapshot identifier should be set correctly', + 'Snapshot identifier should be set correctly', ); }); } diff --git a/tests/database/ssm-connect.test.ts b/tests/database/ssm-connect.test.ts index dcfa4d7e..289be552 100644 --- a/tests/database/ssm-connect.test.ts +++ b/tests/database/ssm-connect.test.ts @@ -25,17 +25,17 @@ export function testSSMConnectDb(ctx: DatabaseTestContext) { it('should create a db instance', async () => { const ssmConnectDb = ctx.outputs.ssmConnectDb.value; - const { dbInstanceIdentifier } = ssmConnectDb.instance; + const { identifier } = ssmConnectDb.instance; const command = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: dbInstanceIdentifier, + DBInstanceIdentifier: identifier, }); const { DBInstances } = await ctx.clients.rds.send(command); assert.ok( DBInstances && DBInstances.length === 1 && - DBInstances[0].DBInstanceIdentifier === dbInstanceIdentifier, + DBInstances[0].DBInstanceIdentifier === identifier, 'Database instance should be created', ); }); @@ -256,8 +256,8 @@ export function testSSMConnectDb(ctx: DatabaseTestContext) { it('EC2 instance should be able to connect to the database', async () => { const ssmConnectDb = ctx.outputs.ssmConnectDb.value; const instanceId = ssmConnectDb.ec2SSMConnect.ec2.id; - const dbHost = ssmConnectDb.instance.endpoint.address; - const dbPort = ssmConnectDb.instance.endpoint.port; + const dbHost = ssmConnectDb.instance.address; + const dbPort = ssmConnectDb.instance.port; const testCommand = ` if timeout 5 bash -c " deleteSnapshot(ctx, db.instance.dbInstanceIdentifier)), - ); - - spinner.success({ text: 'Snapshots deleted' }); -} - -async function deleteSnapshot( - ctx: DatabaseTestContext, - DBInstanceIdentifier: string, -) { - const describeCommand = new DescribeDBSnapshotsCommand({ - DBInstanceIdentifier, - SnapshotType: 'manual', - }); - const { DBSnapshots } = await ctx.clients.rds.send(describeCommand); - - if (!DBSnapshots || !DBSnapshots.length) { - throw new Error('Snapshot not found'); - } - const [DBSnapshot] = DBSnapshots; - - const deleteCommand = new DeleteDBSnapshotCommand({ - DBSnapshotIdentifier: DBSnapshot.DBSnapshotIdentifier, - }); - await ctx.clients.rds.send(deleteCommand); -} - -export async function cleanupReplicas(ctx: DatabaseTestContext) { - const spinner = createSpinner('Deleting replicas...').start(); - - const dbs = [ - ctx.outputs.replicaDb.value, - ctx.outputs.configurableReplicaDb.value, - ]; - await Promise.all(dbs.map(db => deleteReplica(ctx, db))); - - spinner.success({ text: 'Replicas deleted' }); -} - -async function deleteReplica(ctx: DatabaseTestContext, db: studion.Database) { - const replicaDBInstanceId = db.replica!.instance - .identifier as unknown as string; - - try { - const deleteCommand = new DeleteDBInstanceCommand({ - DBInstanceIdentifier: replicaDBInstanceId, - SkipFinalSnapshot: true, - }); - - await ctx.clients.rds.send(deleteCommand); - } catch (err) { - if (err instanceof DBInstanceNotFoundFault) { - return; - } - - throw err; - } - - // Wait for replica to be deleted - await backOff(async () => { - try { - const describeCommand = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: replicaDBInstanceId, - }); - const { DBInstances } = await ctx.clients.rds.send(describeCommand); - - if (DBInstances![0].DBInstanceStatus === 'deleting') { - throw new Error('DB instance still deleting'); - } - } catch (err) { - if (err instanceof DBInstanceNotFoundFault) { - return; - } - - throw err; - } - }); - - // Wait for primary instance to exit modifying state - await backOff(async () => { - try { - const primaryDBInstanceId = db.instance - .dbInstanceIdentifier as unknown as string; - const describeCommand = new DescribeDBInstancesCommand({ - DBInstanceIdentifier: primaryDBInstanceId, - }); - const { DBInstances } = await ctx.clients.rds.send(describeCommand); - - if (DBInstances![0].DBInstanceStatus === 'modifying') { - throw new Error('DB instance still modifying'); - } - } catch (err) { - if (err instanceof DBInstanceNotFoundFault) { - throw new NonRetryableError('Db instance not found', { cause: err }); - } - } - }); -}