cdk-rds-sql 6.1.0 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,15 @@ import { ConnectionOptions } from "tls"
3
3
  import { format as pgFormat } from "node-pg-format"
4
4
  import { Client, ClientConfig } from "pg"
5
5
  import { AbstractEngine, EngineConnectionConfig } from "./engine.abstract"
6
+ import {
7
+ EngineDatabaseProperties,
8
+ EngineRoleProperties,
9
+ EngineSchemaProperties,
10
+ EngineSqlProperties,
11
+ } from "./types"
6
12
 
7
13
  export class PostgresqlEngine extends AbstractEngine {
8
- createDatabase(resourceId: string, props?: any): string | string[] {
14
+ createDatabase(resourceId: string, props: EngineDatabaseProperties): string | string[] {
9
15
  const owner = props?.Owner
10
16
  if (owner) {
11
17
  return [
@@ -17,7 +23,11 @@ export class PostgresqlEngine extends AbstractEngine {
17
23
  }
18
24
  }
19
25
 
20
- updateDatabase(resourceId: string, oldResourceId: string, props?: any): string[] {
26
+ updateDatabase(
27
+ resourceId: string,
28
+ oldResourceId: string,
29
+ props: EngineDatabaseProperties
30
+ ): string[] {
21
31
  const statements: string[] = []
22
32
  if (resourceId !== oldResourceId) {
23
33
  if (props?.MasterOwner) {
@@ -52,24 +62,24 @@ export class PostgresqlEngine extends AbstractEngine {
52
62
  ]
53
63
  }
54
64
 
55
- async createRole(resourceId: string, props?: any): Promise<string[]> {
65
+ async createRole(resourceId: string, props: EngineRoleProperties): Promise<string[]> {
56
66
  const sql = ["start transaction"]
57
-
58
- if (props.EnableIamAuth) {
67
+
68
+ if (props?.EnableIamAuth) {
59
69
  // Create role for IAM authentication
60
70
  sql.push(pgFormat("create role %I with login", resourceId))
61
71
  sql.push(pgFormat("grant rds_iam to %I", resourceId))
62
72
  } else {
63
73
  // Create role with password authentication
64
- if (!props.PasswordArn) throw "No PasswordArn provided"
74
+ if (!props?.PasswordArn) throw "No PasswordArn provided"
65
75
  const password = await this.getPassword(props.PasswordArn)
66
76
  if (!password) {
67
77
  throw `Cannot parse password from ${props.PasswordArn}`
68
78
  }
69
79
  sql.push(pgFormat("create role %I with login password %L", resourceId, password))
70
80
  }
71
-
72
- if (props.DatabaseName) {
81
+
82
+ if (props?.DatabaseName) {
73
83
  sql.push(
74
84
  pgFormat(
75
85
  `DO $$
@@ -84,7 +94,7 @@ END$$;`,
84
94
  )
85
95
  )
86
96
  }
87
-
97
+
88
98
  sql.push("commit")
89
99
  return sql
90
100
  }
@@ -92,15 +102,15 @@ END$$;`,
92
102
  async updateRole(
93
103
  resourceId: string,
94
104
  oldResourceId: string,
95
- props?: any,
96
- oldProps?: any
105
+ props: EngineRoleProperties,
106
+ oldProps: EngineRoleProperties
97
107
  ): Promise<string[]> {
98
108
  const sql = ["start transaction"]
99
-
109
+
100
110
  if (oldResourceId !== resourceId) {
101
111
  sql.push(pgFormat("alter role %I rename to %I", oldResourceId, resourceId))
102
112
  }
103
-
113
+
104
114
  // Handle authentication method changes
105
115
  if (props?.EnableIamAuth && !oldProps?.EnableIamAuth) {
106
116
  // Switching from password to IAM auth
@@ -123,7 +133,7 @@ END$$;`,
123
133
  }
124
134
  sql.push(pgFormat("alter role %I with password %L", resourceId, password))
125
135
  }
126
-
136
+
127
137
  // Check if database name has changed
128
138
  if (
129
139
  oldProps?.DatabaseName &&
@@ -161,12 +171,12 @@ END$$;`,
161
171
  )
162
172
  )
163
173
  }
164
-
174
+
165
175
  sql.push("commit")
166
176
  return sql
167
177
  }
168
178
 
169
- deleteRole(resourceId: string, props?: any): string[] {
179
+ deleteRole(resourceId: string, props: EngineRoleProperties): string[] {
170
180
  return [
171
181
  "start transaction",
172
182
  pgFormat(
@@ -186,7 +196,7 @@ END$$;`,
186
196
  ]
187
197
  }
188
198
 
189
- createSchema(resourceId: string, props?: any): string[] {
199
+ createSchema(resourceId: string, props: EngineSchemaProperties): string[] {
190
200
  const sql: string[] = [pgFormat("create schema if not exists %I", resourceId)]
191
201
  if (props?.RoleName) {
192
202
  this.grantRoleForSchema(resourceId, props.RoleName).forEach((stmt) =>
@@ -196,7 +206,11 @@ END$$;`,
196
206
  return sql
197
207
  }
198
208
 
199
- updateSchema(resourceId: string, oldResourceId: string, props?: any): string[] {
209
+ updateSchema(
210
+ resourceId: string,
211
+ oldResourceId: string,
212
+ props: EngineSchemaProperties
213
+ ): string[] {
200
214
  const sql: string[] = []
201
215
  if (props?.RoleName) {
202
216
  this.revokeRoleFromSchema(oldResourceId, props.RoleName).forEach((stmt) =>
@@ -212,7 +226,7 @@ END$$;`,
212
226
  return sql
213
227
  }
214
228
 
215
- deleteSchema(resourceId: string, props?: any): string[] {
229
+ deleteSchema(resourceId: string, props: EngineSchemaProperties): string[] {
216
230
  const sql: string[] = []
217
231
  if (props?.RoleName) {
218
232
  this.revokeRoleFromSchema(resourceId, props.RoleName).forEach((stmt) =>
@@ -223,16 +237,20 @@ END$$;`,
223
237
  return sql
224
238
  }
225
239
 
226
- createSql(_resourceId: string, props?: any): string {
227
- return props.Statement
240
+ createSql(_resourceId: string, props: EngineSqlProperties): string {
241
+ return props?.Statement || ""
228
242
  }
229
243
 
230
- updateSql(_resourceId: string, _oldResourceId: string, props?: any): string {
231
- return props.Statement
244
+ updateSql(
245
+ _resourceId: string,
246
+ _oldResourceId: string,
247
+ props: EngineSqlProperties
248
+ ): string {
249
+ return props?.Statement || ""
232
250
  }
233
251
 
234
- deleteSql(_resourceId: string, props?: any): string {
235
- return props.Rollback
252
+ deleteSql(_resourceId: string, props: EngineSqlProperties): string {
253
+ return props?.Rollback || ""
236
254
  }
237
255
 
238
256
  private grantRoleForSchema(schema: string, roleName: string): string[] {
@@ -1,26 +1,13 @@
1
1
  import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager"
2
2
  import { createConnection } from "mysql2/promise"
3
3
  import { GenericContainer, StartedTestContainer } from "testcontainers"
4
- import { createRequest, updateRequest, deleteRequest } from "./util"
5
4
  import { handler } from "./handler"
5
+ import { createRequest, updateRequest, deleteRequest } from "./util"
6
6
 
7
7
  jest.mock("@aws-sdk/client-secrets-manager")
8
8
  const SecretsManagerClientMock = SecretsManagerClient as jest.MockedClass<
9
9
  typeof SecretsManagerClient
10
10
  >
11
- SecretsManagerClientMock.prototype.send.mockImplementation(() => {
12
- return {
13
- SecretString: JSON.stringify({
14
- host: mysqlHost,
15
- port: mysqlPort,
16
- username: DB_MASTER_USERNAME,
17
- password: DB_MASTER_PASSWORD,
18
- dbname: DB_DEFAULT_DB,
19
- engine: "mysql",
20
- dbClusterIdentifier: "dummy",
21
- }),
22
- }
23
- })
24
11
 
25
12
  const DB_PORT = 3306
26
13
  const DB_MASTER_USERNAME = "root"
@@ -45,6 +32,21 @@ beforeEach(async () => {
45
32
  .start()
46
33
  mysqlHost = mysqlContainer.getHost()
47
34
  mysqlPort = mysqlContainer.getMappedPort(DB_PORT)
35
+
36
+ // Set up the mock after we have the host and port values
37
+ SecretsManagerClientMock.prototype.send.mockImplementation(() => {
38
+ return {
39
+ SecretString: JSON.stringify({
40
+ host: mysqlHost,
41
+ port: mysqlPort,
42
+ username: DB_MASTER_USERNAME,
43
+ password: DB_MASTER_PASSWORD,
44
+ dbname: DB_DEFAULT_DB,
45
+ engine: "mysql",
46
+ dbClusterIdentifier: "dummy",
47
+ }),
48
+ }
49
+ })
48
50
  }, 30000)
49
51
 
50
52
  afterEach(async () => {
@@ -57,14 +59,14 @@ afterEach(async () => {
57
59
  // Helper functions for MySQL tests
58
60
  async function databaseExists(connection: any, dbName: string): Promise<boolean> {
59
61
  const [rows] = await connection.query(
60
- `SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?`,
62
+ "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?",
61
63
  [dbName]
62
64
  )
63
65
  return rows.length > 0
64
66
  }
65
67
 
66
68
  async function userExists(connection: any, username: string): Promise<boolean> {
67
- const [rows] = await connection.query(`SELECT User FROM mysql.user WHERE User = ?`, [
69
+ const [rows] = await connection.query("SELECT User FROM mysql.user WHERE User = ?", [
68
70
  username,
69
71
  ])
70
72
  return rows.length > 0
@@ -76,7 +78,7 @@ async function tableExists(
76
78
  tableName: string
77
79
  ): Promise<boolean> {
78
80
  const [rows] = await connection.query(
79
- `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`,
81
+ "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?",
80
82
  [dbName, tableName]
81
83
  )
82
84
  return rows.length > 0
@@ -103,7 +105,7 @@ test("database", async () => {
103
105
  const newDatabaseName = "mydb2"
104
106
  const create = createRequest("database", oldDatabaseName)
105
107
  await handler(create)
106
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(1)
108
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(1)
107
109
  const connection = await newConnection()
108
110
  try {
109
111
  expect(await databaseExists(connection, oldDatabaseName)).toEqual(true)
@@ -188,7 +190,7 @@ describe("User creation", () => {
188
190
  DatabaseName: DB_DEFAULT_DB,
189
191
  })
190
192
  await handler(create)
191
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(2)
193
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(2)
192
194
 
193
195
  const connection = await newConnection()
194
196
  try {
@@ -227,7 +229,7 @@ describe("User creation", () => {
227
229
  DatabaseName: DB_DEFAULT_DB,
228
230
  })
229
231
  await handler(create)
230
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(2)
232
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(2)
231
233
 
232
234
  const connection = await newConnection()
233
235
  try {
@@ -1,6 +1,7 @@
1
1
  import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager"
2
2
  import { Client, ClientConfig } from "pg"
3
3
  import { GenericContainer, StartedTestContainer } from "testcontainers"
4
+ import { handler } from "./handler"
4
5
  import {
5
6
  createRequest,
6
7
  updateRequest,
@@ -12,7 +13,6 @@ import {
12
13
  rowCount,
13
14
  roleGrantedForSchema,
14
15
  } from "./util"
15
- import { handler } from "./handler"
16
16
 
17
17
  jest.mock("@aws-sdk/client-secrets-manager")
18
18
  const SecretsManagerClientMock = SecretsManagerClient as jest.MockedClass<
@@ -71,7 +71,7 @@ test("schema", async () => {
71
71
  const newSchemaName = "test2"
72
72
  const create = createRequest("schema", oldSchemaName)
73
73
  await handler(create)
74
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(1)
74
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(1)
75
75
 
76
76
  const client = await newClient()
77
77
  try {
@@ -128,7 +128,7 @@ test("role with existing database", async () => {
128
128
  DatabaseName: "postgres",
129
129
  })
130
130
  await handler(create)
131
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(2)
131
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(2)
132
132
  const client = await newClient()
133
133
  try {
134
134
  expect(await roleExists(client, oldRoleName)).toEqual(true)
@@ -165,7 +165,7 @@ test("role without database", async () => {
165
165
  PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
166
166
  })
167
167
  await handler(create)
168
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(2)
168
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(2)
169
169
  const client = await newClient()
170
170
  try {
171
171
  expect(await roleExists(client, roleName)).toEqual(true)
@@ -180,7 +180,7 @@ test("change role password", async () => {
180
180
  PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
181
181
  })
182
182
  await handler(create)
183
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(2)
183
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(2)
184
184
  const client = await newClient()
185
185
  try {
186
186
  expect(await roleExists(client, roleName)).toEqual(true)
@@ -198,7 +198,7 @@ test("database", async () => {
198
198
  const newDatabaseName = "mydb2"
199
199
  const create = createRequest("database", oldDatabaseName)
200
200
  await handler(create)
201
- expect(SecretsManagerClientMock).toHaveBeenCalledTimes(1)
201
+ expect(SecretsManagerClientMock.prototype.send).toHaveBeenCalledTimes(1)
202
202
  const client = await newClient()
203
203
  try {
204
204
  expect(await databaseExists(client, oldDatabaseName)).toEqual(true)
@@ -0,0 +1,164 @@
1
+ import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager"
2
+ import { MysqlEngine } from "./engine.mysql"
3
+ import { PostgresqlEngine } from "./engine.postgresql"
4
+ import { handler } from "./handler"
5
+ import { createRequest } from "./util"
6
+
7
+ // Mock the secrets manager client
8
+ jest.mock("@aws-sdk/client-secrets-manager")
9
+ const SecretsManagerClientMock = SecretsManagerClient as jest.MockedClass<
10
+ typeof SecretsManagerClient
11
+ >
12
+
13
+ // Mock the database engines
14
+ jest.mock("./engine.mysql")
15
+ jest.mock("./engine.postgresql")
16
+
17
+ const MockedMysqlEngine = MysqlEngine as jest.MockedClass<typeof MysqlEngine>
18
+ const MockedPostgresqlEngine = PostgresqlEngine as jest.MockedClass<
19
+ typeof PostgresqlEngine
20
+ >
21
+
22
+ describe("Handler CloudFormation Property Conversion", () => {
23
+ let mockMysqlEngine: jest.Mocked<MysqlEngine>
24
+ let mockPostgresqlEngine: jest.Mocked<PostgresqlEngine>
25
+
26
+ beforeEach(() => {
27
+ jest.clearAllMocks()
28
+
29
+ // Mock the engine instances
30
+ mockMysqlEngine = {
31
+ createRole: jest.fn(),
32
+ executeSQL: jest.fn(),
33
+ } as any
34
+
35
+ mockPostgresqlEngine = {
36
+ createRole: jest.fn(),
37
+ executeSQL: jest.fn(),
38
+ } as any
39
+
40
+ MockedMysqlEngine.mockImplementation(() => mockMysqlEngine)
41
+ MockedPostgresqlEngine.mockImplementation(() => mockPostgresqlEngine)
42
+
43
+ // Mock secrets manager to return MySQL engine
44
+ SecretsManagerClientMock.prototype.send.mockImplementation(() => {
45
+ return Promise.resolve({
46
+ SecretString: JSON.stringify({
47
+ host: "localhost",
48
+ port: 3306,
49
+ username: "root",
50
+ password: "password",
51
+ dbname: "test",
52
+ engine: "mysql",
53
+ }),
54
+ })
55
+ })
56
+ })
57
+
58
+ describe("EnableIamAuth property conversion", () => {
59
+ it("should convert string 'false' to boolean false", async () => {
60
+ mockMysqlEngine.createRole.mockResolvedValue(["CREATE USER test"])
61
+ mockMysqlEngine.executeSQL.mockResolvedValue({})
62
+
63
+ // Create a request with EnableIamAuth as string 'false' (simulating CloudFormation)
64
+ const request = createRequest("role", "testuser", {
65
+ EnableIamAuth: "false",
66
+ PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
67
+ })
68
+
69
+ await handler(request)
70
+
71
+ // Verify that createRole was called with boolean false, not string 'false'
72
+ expect(mockMysqlEngine.createRole).toHaveBeenCalledWith(
73
+ "testuser",
74
+ expect.objectContaining({
75
+ EnableIamAuth: false, // Should be converted to boolean false
76
+ PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
77
+ })
78
+ )
79
+ })
80
+
81
+ it("should convert string 'true' to boolean true", async () => {
82
+ mockMysqlEngine.createRole.mockResolvedValue(["CREATE USER test"])
83
+ mockMysqlEngine.executeSQL.mockResolvedValue({})
84
+
85
+ // Create a request with EnableIamAuth as string 'true' (simulating CloudFormation)
86
+ const request = createRequest("role", "testuser", {
87
+ EnableIamAuth: "true", // CloudFormation passes boolean as string
88
+ })
89
+
90
+ await handler(request)
91
+
92
+ // Verify that createRole was called with boolean true, not string 'true'
93
+ expect(mockMysqlEngine.createRole).toHaveBeenCalledWith(
94
+ "testuser",
95
+ expect.objectContaining({
96
+ EnableIamAuth: true, // Should be converted to boolean true
97
+ })
98
+ )
99
+ })
100
+
101
+ it("should handle number 0 correctly", async () => {
102
+ mockMysqlEngine.createRole.mockResolvedValue(["CREATE USER test"])
103
+ mockMysqlEngine.executeSQL.mockResolvedValue({})
104
+
105
+ // Create a request with EnableIamAuth as actual boolean false
106
+ const request = createRequest("role", "testuser", {
107
+ EnableIamAuth: "0",
108
+ PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
109
+ })
110
+
111
+ await handler(request)
112
+
113
+ // Verify that createRole was called with boolean false
114
+ expect(mockMysqlEngine.createRole).toHaveBeenCalledWith(
115
+ "testuser",
116
+ expect.objectContaining({
117
+ EnableIamAuth: false,
118
+ PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
119
+ })
120
+ )
121
+ })
122
+
123
+ it("should handle number 1 correctly", async () => {
124
+ mockMysqlEngine.createRole.mockResolvedValue(["CREATE USER test"])
125
+ mockMysqlEngine.executeSQL.mockResolvedValue({})
126
+
127
+ // Create a request with EnableIamAuth as actual boolean true
128
+ const request = createRequest("role", "testuser", {
129
+ EnableIamAuth: "1",
130
+ })
131
+
132
+ await handler(request)
133
+
134
+ // Verify that createRole was called with boolean true
135
+ expect(mockMysqlEngine.createRole).toHaveBeenCalledWith(
136
+ "testuser",
137
+ expect.objectContaining({
138
+ EnableIamAuth: true,
139
+ })
140
+ )
141
+ })
142
+
143
+ it("should handle undefined EnableIamAuth correctly", async () => {
144
+ mockMysqlEngine.createRole.mockResolvedValue(["CREATE USER test"])
145
+ mockMysqlEngine.executeSQL.mockResolvedValue({})
146
+
147
+ // Create a request without EnableIamAuth property
148
+ const request = createRequest("role", "testuser", {
149
+ PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
150
+ })
151
+
152
+ await handler(request)
153
+
154
+ // Verify that createRole was called without EnableIamAuth
155
+ expect(mockMysqlEngine.createRole).toHaveBeenCalledWith(
156
+ "testuser",
157
+ expect.objectContaining({
158
+ PasswordArn: "arn:aws:secretsmanager:us-east-1:123456789:secret:dummy",
159
+ EnableIamAuth: false,
160
+ })
161
+ )
162
+ })
163
+ })
164
+ })
package/lambda/handler.ts CHANGED
@@ -15,10 +15,17 @@ import {
15
15
  CloudFormationCustomResourceDeleteEvent,
16
16
  } from "aws-lambda"
17
17
  import { backOff } from "exponential-backoff"
18
- import { EngineFactory } from "./engine.factory"
19
18
  import { EngineConnectionConfig } from "./engine.abstract"
19
+ import { EngineFactory } from "./engine.factory"
20
+ import {
21
+ ResourceProperties,
22
+ CustomResourceResponse,
23
+ EngineDatabaseProperties,
24
+ EngineRoleProperties,
25
+ EngineSchemaProperties,
26
+ EngineSqlProperties,
27
+ } from "./types"
20
28
  import { RdsSqlResource } from "../src/enum"
21
- import { ResourceProperties, CustomResourceResponse } from "./types"
22
29
 
23
30
  const maxAttempts = 20
24
31
 
@@ -29,6 +36,40 @@ const log =
29
36
 
30
37
  const secrets_client = new SecretsManagerClient({})
31
38
 
39
+ // Helper functions to extract engine properties from CloudFormation properties
40
+ // These functions throw if the resource type doesn't match the expected type
41
+ function toDatabaseEngineProps(props: ResourceProperties): EngineDatabaseProperties {
42
+ if (props.Resource !== RdsSqlResource.DATABASE) {
43
+ throw new Error(`Expected DATABASE resource, got ${props.Resource}`)
44
+ }
45
+ return props
46
+ }
47
+
48
+ function toRoleEngineProps(props: ResourceProperties): EngineRoleProperties {
49
+ if (props.Resource !== RdsSqlResource.ROLE) {
50
+ throw new Error(`Expected ROLE resource, got ${props.Resource}`)
51
+ }
52
+ // Convert string 'true'/'false' to boolean for EnableIamAuth
53
+ return {
54
+ ...props,
55
+ EnableIamAuth: props.EnableIamAuth === "true" || props.EnableIamAuth === "1",
56
+ }
57
+ }
58
+
59
+ function toSchemaEngineProps(props: ResourceProperties): EngineSchemaProperties {
60
+ if (props.Resource !== RdsSqlResource.SCHEMA) {
61
+ throw new Error(`Expected SCHEMA resource, got ${props.Resource}`)
62
+ }
63
+ return props
64
+ }
65
+
66
+ function toSqlEngineProps(props: ResourceProperties): EngineSqlProperties {
67
+ if (props.Resource !== RdsSqlResource.SQL) {
68
+ throw new Error(`Expected SQL resource, got ${props.Resource}`)
69
+ }
70
+ return props
71
+ }
72
+
32
73
  export const handler = async (
33
74
  event:
34
75
  | CloudFormationCustomResourceCreateEvent<ResourceProperties>
@@ -82,16 +123,25 @@ export const handler = async (
82
123
  case "Create": {
83
124
  switch (resource) {
84
125
  case RdsSqlResource.DATABASE:
85
- sql = dbEngine.createDatabase(resourceId, event.ResourceProperties)
126
+ sql = dbEngine.createDatabase(
127
+ resourceId,
128
+ toDatabaseEngineProps(event.ResourceProperties)
129
+ )
86
130
  break
87
131
  case RdsSqlResource.ROLE:
88
- sql = await dbEngine.createRole(resourceId, event.ResourceProperties)
132
+ sql = await dbEngine.createRole(
133
+ resourceId,
134
+ toRoleEngineProps(event.ResourceProperties)
135
+ )
89
136
  break
90
137
  case RdsSqlResource.SCHEMA:
91
- sql = dbEngine.createSchema(resourceId, event.ResourceProperties)
138
+ sql = dbEngine.createSchema(
139
+ resourceId,
140
+ toSchemaEngineProps(event.ResourceProperties)
141
+ )
92
142
  break
93
143
  case RdsSqlResource.SQL:
94
- sql = dbEngine.createSql(resourceId, event.ResourceProperties)
144
+ sql = dbEngine.createSql(resourceId, toSqlEngineProps(event.ResourceProperties))
95
145
  break
96
146
  case RdsSqlResource.PARAMETER_PASSWORD:
97
147
  await handleParameterPassword(event.ResourceProperties)
@@ -104,24 +154,35 @@ export const handler = async (
104
154
  .PhysicalResourceId
105
155
  switch (resource) {
106
156
  case RdsSqlResource.DATABASE:
157
+ const dbProps = toDatabaseEngineProps(event.ResourceProperties)
107
158
  sql = dbEngine.updateDatabase(resourceId, oldResourceId, {
108
- ...event.ResourceProperties,
159
+ ...dbProps,
109
160
  MasterOwner: secretValues.username,
110
161
  })
111
162
  break
112
163
  case RdsSqlResource.ROLE:
164
+ const updateEvent =
165
+ event as CloudFormationCustomResourceUpdateEvent<ResourceProperties>
113
166
  sql = await dbEngine.updateRole(
114
167
  resourceId,
115
168
  oldResourceId,
116
- event.ResourceProperties,
117
- (event as CloudFormationCustomResourceUpdateEvent).OldResourceProperties
169
+ toRoleEngineProps(event.ResourceProperties),
170
+ toRoleEngineProps(updateEvent.OldResourceProperties)
118
171
  )
119
172
  break
120
173
  case RdsSqlResource.SCHEMA:
121
- sql = dbEngine.updateSchema(resourceId, oldResourceId, event.ResourceProperties)
174
+ sql = dbEngine.updateSchema(
175
+ resourceId,
176
+ oldResourceId,
177
+ toSchemaEngineProps(event.ResourceProperties)
178
+ )
122
179
  break
123
180
  case RdsSqlResource.SQL:
124
- sql = dbEngine.updateSql(resourceId, oldResourceId, event.ResourceProperties)
181
+ sql = dbEngine.updateSql(
182
+ resourceId,
183
+ oldResourceId,
184
+ toSqlEngineProps(event.ResourceProperties)
185
+ )
125
186
  break
126
187
  case RdsSqlResource.PARAMETER_PASSWORD:
127
188
  await handleParameterPassword(event.ResourceProperties)
@@ -136,13 +197,19 @@ export const handler = async (
136
197
  sql = dbEngine.deleteDatabase(resourceId, secretValues.username)
137
198
  break
138
199
  case RdsSqlResource.ROLE:
139
- sql = dbEngine.deleteRole(resourceId, event.ResourceProperties)
200
+ sql = dbEngine.deleteRole(
201
+ resourceId,
202
+ toRoleEngineProps(event.ResourceProperties)
203
+ )
140
204
  break
141
205
  case RdsSqlResource.SCHEMA:
142
- sql = dbEngine.deleteSchema(resourceId, event.ResourceProperties)
206
+ sql = dbEngine.deleteSchema(
207
+ resourceId,
208
+ toSchemaEngineProps(event.ResourceProperties)
209
+ )
143
210
  break
144
211
  case RdsSqlResource.SQL:
145
- sql = dbEngine.deleteSql(resourceId, event.ResourceProperties)
212
+ sql = dbEngine.deleteSql(resourceId, toSqlEngineProps(event.ResourceProperties))
146
213
  break
147
214
  case RdsSqlResource.PARAMETER_PASSWORD:
148
215
  await deleteParameterPassword(event.ResourceProperties)