|
1 | | -import format from "pg-format"; |
2 | | -import { getConnectedClient, validateConnection, hashCode } from "./util"; |
3 | | -import * as postgres from "./postgres"; |
| 1 | +import format from 'pg-format' |
| 2 | +import { getConnectedClient, validateConnection, hashCode } from './util' |
| 3 | +import * as postgres from './postgres' |
4 | 4 |
|
5 | 5 | import { |
6 | 6 | CloudFormationCustomResourceEvent, |
7 | 7 | CloudFormationCustomResourceCreateEvent, |
8 | 8 | CloudFormationCustomResourceUpdateEvent, |
9 | | - CloudFormationCustomResourceDeleteEvent, |
10 | | -} from "aws-lambda/trigger/cloudformation-custom-resource"; |
11 | | -import { Connection } from "./lambda.types"; |
| 9 | + CloudFormationCustomResourceDeleteEvent |
| 10 | +} from 'aws-lambda/trigger/cloudformation-custom-resource' |
| 11 | +import { Connection } from './lambda.types' |
12 | 12 |
|
13 | 13 | interface Props { |
14 | | - ServiceToken: string; |
15 | | - Connection: Connection; |
16 | | - Name: string; |
17 | | - Owner: string; |
| 14 | + ServiceToken: string |
| 15 | + Connection: Connection |
| 16 | + Name: string |
| 17 | + Owner: string |
18 | 18 | } |
19 | 19 |
|
20 | 20 | export const handler = async (event: CloudFormationCustomResourceEvent) => { |
21 | 21 | switch (event.RequestType) { |
22 | | - case "Create": |
23 | | - return handleCreate(event); |
24 | | - case "Update": |
25 | | - return handleUpdate(event); |
26 | | - case "Delete": |
27 | | - return handleDelete(event); |
| 22 | + case 'Create': |
| 23 | + return handleCreate(event) |
| 24 | + case 'Update': |
| 25 | + return handleUpdate(event) |
| 26 | + case 'Delete': |
| 27 | + return handleDelete(event) |
28 | 28 | } |
29 | | -}; |
| 29 | +} |
30 | 30 |
|
31 | 31 | const generatePhysicalId = (props: Props): string => { |
32 | | - const { Host, Port } = props.Connection; |
33 | | - const suffix = Math.abs(hashCode(`${Host}-${Port}`)); |
34 | | - return `${props.Name}-${suffix}`; |
35 | | -}; |
| 32 | + const { Host, Port } = props.Connection |
| 33 | + const suffix = Math.abs(hashCode(`${Host}-${Port}`)) |
| 34 | + return `${props.Name}-${suffix}` |
| 35 | +} |
36 | 36 |
|
37 | 37 | const handleCreate = async (event: CloudFormationCustomResourceCreateEvent) => { |
38 | | - const props = event.ResourceProperties as Props; |
39 | | - validateProps(props); |
| 38 | + const props = event.ResourceProperties as Props |
| 39 | + validateProps(props) |
40 | 40 | await createDatabase({ |
41 | 41 | connection: props.Connection, |
42 | 42 | name: props.Name, |
43 | | - owner: props.Owner, |
44 | | - }); |
| 43 | + owner: props.Owner |
| 44 | + }) |
45 | 45 | return { |
46 | | - PhysicalResourceId: generatePhysicalId(props), |
47 | | - }; |
48 | | -}; |
| 46 | + PhysicalResourceId: generatePhysicalId(props) |
| 47 | + } |
| 48 | +} |
49 | 49 |
|
50 | 50 | const handleUpdate = async (event: CloudFormationCustomResourceUpdateEvent) => { |
51 | | - const props = event.ResourceProperties as Props; |
52 | | - validateProps(props); |
53 | | - const oldProps = event.OldResourceProperties as Props; |
| 51 | + const props = event.ResourceProperties as Props |
| 52 | + validateProps(props) |
| 53 | + const oldProps = event.OldResourceProperties as Props |
54 | 54 |
|
55 | | - const oldPhysicalResourceId = generatePhysicalId(oldProps); |
56 | | - const physicalResourceId = generatePhysicalId(props); |
| 55 | + const oldPhysicalResourceId = generatePhysicalId(oldProps) |
| 56 | + const physicalResourceId = generatePhysicalId(props) |
57 | 57 |
|
58 | 58 | if (physicalResourceId != oldPhysicalResourceId) { |
59 | 59 | await createDatabase({ |
60 | 60 | connection: props.Connection, |
61 | 61 | name: props.Name, |
62 | | - owner: props.Owner, |
63 | | - }); |
64 | | - return { PhysicalResourceId: physicalResourceId }; |
| 62 | + owner: props.Owner |
| 63 | + }) |
| 64 | + return { PhysicalResourceId: physicalResourceId } |
65 | 65 | } |
66 | 66 |
|
67 | 67 | if (props.Owner != oldProps.Owner) { |
68 | | - await updateDbOwner(props.Connection, props.Name, props.Owner); |
| 68 | + await updateDbOwner(props.Connection, props.Name, props.Owner) |
69 | 69 | } |
70 | 70 |
|
71 | | - return { PhysicalResourceId: physicalResourceId }; |
72 | | -}; |
| 71 | + return { PhysicalResourceId: physicalResourceId } |
| 72 | +} |
73 | 73 |
|
74 | 74 | const handleDelete = async (event: CloudFormationCustomResourceDeleteEvent) => { |
75 | | - const props = event.ResourceProperties as Props; |
76 | | - validateProps(props); |
77 | | - await deleteDatabase(props.Connection, props.Name, props.Owner); |
78 | | - return {}; |
79 | | -}; |
| 75 | + const props = event.ResourceProperties as Props |
| 76 | + validateProps(props) |
| 77 | + await deleteDatabase(props.Connection, props.Name, props.Owner) |
| 78 | + return {} |
| 79 | +} |
80 | 80 |
|
81 | 81 | const validateProps = (props: Props) => { |
82 | | - if (!("Connection" in props)) { |
83 | | - throw "Connection property is required"; |
| 82 | + if (!('Connection' in props)) { |
| 83 | + throw 'Connection property is required' |
84 | 84 | } |
85 | | - validateConnection(props.Connection); |
| 85 | + validateConnection(props.Connection) |
86 | 86 |
|
87 | | - if (!("Name" in props)) { |
88 | | - throw "Name property is required"; |
| 87 | + if (!('Name' in props)) { |
| 88 | + throw 'Name property is required' |
89 | 89 | } |
90 | | - if (!("Owner" in props)) { |
91 | | - throw "Owner property is required"; |
| 90 | + if (!('Owner' in props)) { |
| 91 | + throw 'Owner property is required' |
92 | 92 | } |
93 | | -}; |
94 | | - |
95 | | -export const createDatabase = async (props: { |
96 | | - connection: Connection; |
97 | | - name: string; |
98 | | - owner: string; |
99 | | -}) => { |
100 | | - const { connection, name, owner } = props; |
101 | | - console.log("Creating database", name); |
102 | | - const client = await getConnectedClient(connection); |
| 93 | +} |
| 94 | + |
| 95 | +export const createDatabase = async (props: { connection: Connection; name: string; owner: string }) => { |
| 96 | + const { connection, name, owner } = props |
| 97 | + console.log('Creating database', name) |
| 98 | + const client = await getConnectedClient(connection) |
103 | 99 | try { |
104 | | - await postgres.createDatabase({ client, name, owner }); |
105 | | - console.log("Created database"); |
| 100 | + await postgres.createDatabase({ client, name, owner }) |
| 101 | + console.log('Created database') |
106 | 102 | } finally { |
107 | | - await client.end(); |
| 103 | + await client.end() |
108 | 104 | } |
109 | | -}; |
110 | | - |
111 | | -export const deleteDatabase = async ( |
112 | | - connection: Connection, |
113 | | - name: string, |
114 | | - owner: string |
115 | | -) => { |
116 | | - console.log("Deleting database", name); |
117 | | - const client = await getConnectedClient(connection); |
| 105 | +} |
| 106 | + |
| 107 | +export const deleteDatabase = async (connection: Connection, name: string, owner: string) => { |
| 108 | + console.log('Deleting database', name) |
| 109 | + const client = await getConnectedClient(connection) |
118 | 110 | try { |
119 | 111 | // First, drop all remaining DB connections |
120 | 112 | // Sometimes, DB connections are still alive even though the ECS service has been deleted |
121 | 113 | await client.query( |
122 | | - format( |
123 | | - "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE datname=%L", |
124 | | - name |
125 | | - ) |
126 | | - ); |
| 114 | + format('SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE datname=%L', name) |
| 115 | + ) |
127 | 116 | // Then, drop the DB |
128 | | - await client.query(format("DROP DATABASE %I", name)); |
| 117 | + await client.query(format('DROP DATABASE %I', name)) |
129 | 118 | } finally { |
130 | | - await client.end(); |
| 119 | + await client.end() |
131 | 120 | } |
132 | | -}; |
133 | | - |
134 | | -export const updateDbOwner = async ( |
135 | | - connection: Connection, |
136 | | - name: string, |
137 | | - owner: string |
138 | | -) => { |
139 | | - console.log(`Updating DB ${name} owner to ${owner}`); |
140 | | - const client = await getConnectedClient(connection); |
| 121 | +} |
| 122 | + |
| 123 | +export const updateDbOwner = async (connection: Connection, name: string, owner: string) => { |
| 124 | + console.log(`Updating DB ${name} owner to ${owner}`) |
| 125 | + const client = await getConnectedClient(connection) |
141 | 126 | try { |
142 | | - await client.query(format("ALTER DATABASE %I OWNER TO %I", name, owner)); |
| 127 | + await client.query(format('ALTER DATABASE %I OWNER TO %I', name, owner)) |
143 | 128 | } finally { |
144 | | - await client.end(); |
| 129 | + await client.end() |
145 | 130 | } |
146 | | -}; |
| 131 | +} |
0 commit comments