1 | import { ResourceConstants } from './ResourceConstants'
|
2 | import DataSource from 'cloudform-types/types/appSync/dataSource'
|
3 | import IAM from 'cloudform-types/types/iam'
|
4 |
|
5 | import cloudform, { Fn, StringParameter, Refs } from 'cloudform'
|
6 | import Template from 'cloudform-types/types/template'
|
7 | import TemplateContext from './RelationalDBSchemaTransformer'
|
8 | import RelationalDBResolverGenerator from './RelationalDBResolverGenerator'
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | export default class RelationalDBTemplateGenerator {
|
18 | context: TemplateContext
|
19 |
|
20 | constructor(context: TemplateContext) {
|
21 | this.context = context
|
22 | }
|
23 |
|
24 | |
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | public createTemplate(context: any): Template {
|
31 | const template = {
|
32 | AWSTemplateFormatVersion: "2010-09-09",
|
33 | Parameters: this.makeParameters(this.context.databaseName),
|
34 | Resources: {
|
35 | [ResourceConstants.RESOURCES.RelationalDatabaseDataSource]: this.makeRelationalDataSource(context),
|
36 | [ResourceConstants.RESOURCES.RelationalDatabaseAccessRole]: this.makeIAMDataSourceRole()
|
37 | }
|
38 | }
|
39 |
|
40 | return template
|
41 | }
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | public addRelationalResolvers(template: Template, resolverFilePath: string) : Template {
|
51 | let resolverGenerator = new RelationalDBResolverGenerator(this.context)
|
52 | template.Resources = {...template.Resources, ...resolverGenerator.createRelationalResolvers(resolverFilePath)}
|
53 | return template
|
54 | }
|
55 |
|
56 | |
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | public printCloudformationTemplate(template: Template): string {
|
63 | return cloudform(template)
|
64 | }
|
65 |
|
66 | |
67 |
|
68 |
|
69 |
|
70 | |
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | private makeParameters(databaseName: string) {
|
77 | return {
|
78 | [ResourceConstants.PARAMETERS.AppSyncApiName]: new StringParameter({
|
79 | Description: `The name of the AppSync API generated from database ${databaseName}`,
|
80 | Default: `AppSyncSimpleTransform`
|
81 | }),
|
82 | [ResourceConstants.PARAMETERS.Env]: new StringParameter({
|
83 | Description: 'The environment name. e.g. Dev, Test, or Production',
|
84 | Default: 'NONE'
|
85 | }),
|
86 | [ResourceConstants.PARAMETERS.S3DeploymentBucket]: new StringParameter({
|
87 | Description: 'The S3 bucket containing all deployment assets for the project.'
|
88 | }),
|
89 | [ResourceConstants.PARAMETERS.S3DeploymentRootKey]: new StringParameter({
|
90 | Description: 'An S3 key relative to the S3DeploymentBucket that points to the root of the deployment directory.'
|
91 | }),
|
92 | [ResourceConstants.PARAMETERS.AppSyncApiId]: new StringParameter({
|
93 | Description: 'The id of the AppSync API associated with this project.'
|
94 | }),
|
95 | [ResourceConstants.PARAMETERS.rdsRegion]: new StringParameter({
|
96 | Description: 'The region that the RDS Cluster is located in.'
|
97 | }),
|
98 | [ResourceConstants.PARAMETERS.rdsClusterIdentifier]: new StringParameter({
|
99 | Description: 'The ARN identifier denoting the RDS cluster.'
|
100 | }),
|
101 | [ResourceConstants.PARAMETERS.rdsSecretStoreArn]: new StringParameter({
|
102 | Description: 'The ARN for the Secret containing the access for the RDS cluster.'
|
103 | }),
|
104 | [ResourceConstants.PARAMETERS.rdsDatabaseName]: new StringParameter({
|
105 | Description: 'The name of the database within the RDS cluster to use.'
|
106 | })
|
107 | }
|
108 | }
|
109 |
|
110 | |
111 |
|
112 |
|
113 |
|
114 | |
115 |
|
116 |
|
117 |
|
118 |
|
119 | private makeIAMDataSourceRole() {
|
120 | return new IAM.Role ({
|
121 | RoleName: Fn.Join('-', [
|
122 | 'role',
|
123 | Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId),
|
124 | Fn.Ref(ResourceConstants.PARAMETERS.Env)
|
125 | ]),
|
126 |
|
127 | AssumeRolePolicyDocument: {
|
128 | Version: '2012-10-17',
|
129 | Statement: [
|
130 | {
|
131 | Effect: 'Allow',
|
132 | Principal: {
|
133 | Service: 'appsync.amazonaws.com'
|
134 | },
|
135 | Action: 'sts:AssumeRole'
|
136 | }
|
137 | ]
|
138 | },
|
139 | Policies: [
|
140 | new IAM.Role.Policy ({
|
141 | PolicyName: 'RelationalDatabaseAccessPolicy',
|
142 | PolicyDocument: {
|
143 | Version: '2012-10-17',
|
144 | Statement: [
|
145 | {
|
146 | Effect: 'Allow',
|
147 | Action: [
|
148 | 'rds-data:ExecuteSql',
|
149 | 'rds-data:ExecuteStatement',
|
150 | 'rds-data:DeleteItems',
|
151 | 'rds-data:GetItems',
|
152 | 'rds-data:InsertItems',
|
153 | 'rds-data:UpdateItems'
|
154 | ],
|
155 | Resource: [
|
156 | Fn.Ref(ResourceConstants.PARAMETERS.rdsClusterIdentifier)
|
157 | ]
|
158 | },
|
159 | {
|
160 | Effect: 'Allow',
|
161 | Action: [
|
162 | 'secretsmanager:GetSecretValue'
|
163 | ],
|
164 | Resource: [
|
165 | Fn.Ref(ResourceConstants.PARAMETERS.rdsSecretStoreArn)
|
166 | ]
|
167 | }
|
168 | ]
|
169 | }
|
170 | })
|
171 | ]
|
172 | })
|
173 | }
|
174 |
|
175 | |
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 | private makeRelationalDataSource(cliContext: any): DataSource {
|
182 | return new DataSource ({
|
183 | Type: 'RELATIONAL_DATABASE',
|
184 | Name: `${this.context.databaseName}_rds_DataSource`,
|
185 | Description: `RDS Data Source Provisioned for ${this.context.databaseName}`,
|
186 | ApiId: Fn.Ref(ResourceConstants.PARAMETERS.AppSyncApiId),
|
187 | ServiceRoleArn: Fn.GetAtt(ResourceConstants.RESOURCES.RelationalDatabaseAccessRole, 'Arn'),
|
188 | RelationalDatabaseConfig: {
|
189 | RelationalDatabaseSourceType: 'RDS_HTTP_ENDPOINT',
|
190 | RdsHttpEndpointConfig: {
|
191 | AwsRegion: Fn.Ref(ResourceConstants.PARAMETERS.rdsRegion),
|
192 | DbClusterIdentifier: Fn.Ref(ResourceConstants.PARAMETERS.rdsClusterIdentifier),
|
193 | DatabaseName: Fn.Ref(ResourceConstants.PARAMETERS.rdsDatabaseName),
|
194 | Schema: this.context.databaseSchema,
|
195 | AwsSecretStoreArn: Fn.Ref(ResourceConstants.PARAMETERS.rdsSecretStoreArn)
|
196 | }
|
197 | }
|
198 | }).dependsOn([ResourceConstants.RESOURCES.RelationalDatabaseAccessRole])
|
199 | }
|
200 | }
|