UNPKG

8.48 kBPlain TextView Raw
1import { ResourceConstants } from './ResourceConstants'
2import DataSource from 'cloudform-types/types/appSync/dataSource'
3import IAM from 'cloudform-types/types/iam'
4
5import cloudform, { Fn, StringParameter, Refs } from 'cloudform'
6import Template from 'cloudform-types/types/template'
7import TemplateContext from './RelationalDBSchemaTransformer'
8import RelationalDBResolverGenerator from './RelationalDBResolverGenerator'
9
10/**
11 * This is the Class responsible for generating and managing the CloudForm template
12 * provided a TemplateContext object, which is generated by the RelationalDBSchemaTransformer.
13 *
14 * It will generate the basic CloudForm template needed for getting the AppSync API and
15 * RDS DataSource provisioned. It also allows for adding the CRUDL+Q Resolvers upon need.
16 */
17export default class RelationalDBTemplateGenerator {
18 context: TemplateContext
19
20 constructor(context: TemplateContext) {
21 this.context = context
22 }
23
24 /**
25 * Creates and returns the basic Cloudform template needed for setting
26 * up an AppSync API pointing at the RDS DataSource.
27 *
28 * @returns the created CloudFormation template.
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 * Provided a Cloudform Template, this method adds Resolver Resources to the
45 * Template.
46 *
47 * @param template - the Cloudform template
48 * @returns the given template, updated with new resolvers.
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 * Provided a Cloudform Template, this method returns the cfn json template as a string
58 *
59 * @param template - the Cloudform template
60 * @returns the json, string form of the template given.
61 */
62 public printCloudformationTemplate(template: Template): string {
63 return cloudform(template)
64 }
65
66 /*
67 * Private Helper Methods for Generating the Necessary CFN Specs for the CFN Template
68 */
69
70 /**
71 * Creates any Parmaters needed for the CFN Template
72 *
73 * @param databaseName - the name of the database being parsed.
74 * @returns the parameters for the template.
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 * Resources
112 */
113
114 /**
115 * Creates the IAM Role CFN Spec to allow AppSync to interact with the RDS cluster
116 *
117 * @returns the IAM role CloudFormation resource.
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 * Creates the AppSync DataSource CFN Spec pointing at the provided RDS Cluster
177 *
178 * @param cliContext - the Amplify context, used to load environment variables.
179 * @returns the data source CloudFormation resource.
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}