@stacksjs/cloud 0.65.0 → 0.67.0

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.
package/src/cloud/ai.ts DELETED
@@ -1,24 +0,0 @@
1
- import type { Construct } from 'constructs'
2
- import type { NestedCloudProps } from '../types'
3
- import { config } from '@stacksjs/config'
4
- import { aws_iam as iam } from 'aws-cdk-lib'
5
-
6
- export interface AiStackProps extends NestedCloudProps {}
7
-
8
- export class AiStack {
9
- // eslint-disable-next-line unused-imports/no-unused-vars
10
- constructor(scope: Construct, props: AiStackProps) {
11
- const bedrockAccessPolicy = new iam.PolicyStatement({
12
- effect: iam.Effect.ALLOW,
13
- actions: ['bedrock:InvokeModel', 'bedrock:InvokeModelWithResponseStream'],
14
- resources: config.ai.models?.map((model: string) => `arn:aws:bedrock:us-east-1::foundation-model/${model}`),
15
- })
16
-
17
- const bedrockAccessRole = new iam.Role(scope, 'BedrockAccessRole', {
18
- assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
19
- managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSTaskExecutionRolePolicy')],
20
- })
21
-
22
- bedrockAccessRole.addToPolicy(bedrockAccessPolicy)
23
- }
24
- }
File without changes
package/src/cloud/cdn.ts DELETED
@@ -1,290 +0,0 @@
1
- import type { aws_certificatemanager as acm, aws_s3 as s3, aws_wafv2 as wafv2 } from 'aws-cdk-lib'
2
- import type { ApplicationLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2'
3
- import type { Construct } from 'constructs'
4
- import type { NestedCloudProps } from '../types'
5
- import { config } from '@stacksjs/config'
6
- import {
7
- aws_cloudfront as cloudfront,
8
- Duration,
9
- aws_lambda as lambda,
10
- aws_cloudfront_origins as origins,
11
- CfnOutput as Output,
12
- aws_route53 as route53,
13
- aws_route53_targets as targets,
14
- } from 'aws-cdk-lib'
15
-
16
- export interface CdnStackProps extends NestedCloudProps {
17
- certificate: acm.Certificate
18
- logBucket: s3.Bucket
19
- publicBucket: s3.Bucket
20
- docsBucket?: s3.Bucket
21
- firewall: wafv2.CfnWebACL
22
- originRequestFunction: lambda.Function
23
- zone: route53.IHostedZone
24
- webServer?: lambda.Function
25
- webServerUrl?: lambda.FunctionUrl
26
- lb?: ApplicationLoadBalancer
27
- }
28
-
29
- export class CdnStack {
30
- mainDistribution: cloudfront.Distribution
31
- docsDistribution: cloudfront.Distribution | undefined
32
- cdnCachePolicy: cloudfront.CachePolicy
33
- mainVanityUrl!: string
34
- docsVanityUrl: string | undefined
35
- realtimeLogConfig!: cloudfront.RealtimeLogConfig
36
- props: CdnStackProps
37
-
38
- constructor(scope: Construct, props: CdnStackProps) {
39
- this.props = props
40
-
41
- this.cdnCachePolicy = new cloudfront.CachePolicy(scope, 'CdnCachePolicy', {
42
- comment: 'Stacks CDN Cache Policy',
43
- cachePolicyName: `${props.slug}-${props.appEnv}-cdn-cache-policy`,
44
- minTtl: config.cloud.cdn?.minTtl ? Duration.seconds(config.cloud.cdn.minTtl) : undefined,
45
- defaultTtl: config.cloud.cdn?.defaultTtl ? Duration.seconds(config.cloud.cdn.defaultTtl) : undefined,
46
- maxTtl: config.cloud.cdn?.maxTtl ? Duration.seconds(config.cloud.cdn.maxTtl) : undefined,
47
- cookieBehavior: this.getCookieBehavior(config.cloud.cdn?.cookieBehavior),
48
- })
49
-
50
- const originAccessControl = new cloudfront.S3OriginAccessControl(scope, 'WebOAC', {
51
- originAccessControlName: `${props.slug}-${props.appEnv}-web-oac-${props.timestamp}`,
52
- description: 'Access from CloudFront to the frontend bucket.',
53
- signing: cloudfront.Signing.SIGV4_NO_OVERRIDE,
54
- })
55
-
56
- if (config.app.docMode) {
57
- // In doc mode, create only one distribution for docs
58
- this.mainDistribution = this.createDistribution(
59
- scope,
60
- props,
61
- props.docsBucket as s3.Bucket,
62
- this.createDocsOriginRequestFunction(scope),
63
- props.domain,
64
- 'MainCdn',
65
- originAccessControl,
66
- )
67
- }
68
- else {
69
- // Not in doc mode, create two distributions
70
- this.mainDistribution = this.createDistribution(
71
- scope,
72
- props,
73
- props.publicBucket,
74
- props.originRequestFunction,
75
- props.domain,
76
- 'MainCdn',
77
- originAccessControl,
78
- )
79
-
80
- if (props.docsBucket) {
81
- this.docsDistribution = this.createDistribution(
82
- scope,
83
- props,
84
- props.docsBucket,
85
- this.createDocsOriginRequestFunction(scope),
86
- `docs.${props.domain}`,
87
- 'DocsCdn',
88
- originAccessControl,
89
- )
90
- }
91
- }
92
-
93
- // Create Route53 records
94
- this.createRoute53Records(scope, props)
95
-
96
- // Create outputs
97
- this.createOutputs(scope, props)
98
- }
99
-
100
- createDistribution(
101
- scope: Construct,
102
- props: CdnStackProps,
103
- sourceBucket: s3.Bucket,
104
- originRequestFunction: lambda.Function,
105
- domainName: string,
106
- id: string,
107
- originAccessControl: cloudfront.S3OriginAccessControl,
108
- ): cloudfront.Distribution {
109
- return new cloudfront.Distribution(scope, id, {
110
- domainNames: [domainName],
111
- defaultRootObject: 'index.html',
112
- comment: `CDN for ${domainName}`,
113
- certificate: props.certificate,
114
- enableLogging: true,
115
- logBucket: props.logBucket,
116
- httpVersion: cloudfront.HttpVersion.HTTP2_AND_3,
117
- priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
118
- enabled: true,
119
- minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
120
- webAclId: props.firewall.attrArn,
121
- enableIpv6: true,
122
- defaultBehavior: {
123
- origin: new origins.S3StaticWebsiteOrigin(sourceBucket, {
124
- originPath: '/',
125
- originAccessControlId: originAccessControl.originAccessControlId,
126
- }),
127
- edgeLambdas: [
128
- {
129
- eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
130
- functionVersion: originRequestFunction.currentVersion,
131
- },
132
- ],
133
- compress: config.cloud.cdn?.compress,
134
- allowedMethods: this.allowedMethods(),
135
- cachedMethods: this.cachedMethods(),
136
- viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
137
- cachePolicy: this.cdnCachePolicy,
138
- },
139
- errorResponses: [
140
- {
141
- httpStatus: 404,
142
- responsePagePath: '/index.html',
143
- responseHttpStatus: 200,
144
- ttl: Duration.millis(0),
145
- },
146
- {
147
- httpStatus: 403,
148
- responsePagePath: '/index.html',
149
- responseHttpStatus: 200,
150
- ttl: Duration.millis(0),
151
- },
152
- ],
153
- })
154
- }
155
-
156
- createRoute53Records(scope: Construct, props: CdnStackProps): void {
157
- new route53.ARecord(scope, 'MainAliasRecord', {
158
- recordName: props.domain,
159
- zone: props.zone,
160
- target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(this.mainDistribution)),
161
- })
162
-
163
- if (this.docsDistribution) {
164
- new route53.ARecord(scope, 'DocsAliasRecord', {
165
- recordName: `docs.${props.domain}`,
166
- zone: props.zone,
167
- target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(this.docsDistribution)),
168
- })
169
- }
170
- }
171
-
172
- createOutputs(scope: Construct, props: CdnStackProps): void {
173
- new Output(scope, 'MainDistributionId', {
174
- value: this.mainDistribution.distributionId,
175
- })
176
-
177
- new Output(scope, 'MainUrl', {
178
- value: `https://${props.domain}`,
179
- description: 'The URL of the deployed main application',
180
- })
181
-
182
- this.mainVanityUrl = `https://${this.mainDistribution.domainName}`
183
- new Output(scope, 'MainVanityUrl', {
184
- value: this.mainVanityUrl,
185
- description: 'The vanity URL of the deployed main application',
186
- })
187
-
188
- if (this.docsDistribution) {
189
- new Output(scope, 'DocsDistributionId', {
190
- value: this.docsDistribution.distributionId,
191
- })
192
-
193
- this.docsVanityUrl = `https://${this.docsDistribution.domainName}`
194
- new Output(scope, 'DocsAppVanityUrl', {
195
- value: this.docsVanityUrl,
196
- description: 'The vanity URL of the deployed docs application',
197
- })
198
- }
199
- }
200
-
201
- createDocsOriginRequestFunction(scope: Construct): lambda.Function {
202
- const docsOriginRequestFunction = new lambda.Function(scope, 'DocsOriginRequestFunction', {
203
- functionName: `${this.props.slug}-${this.props.appEnv}-docs-origin-request-function-${this.props.timestamp}`,
204
- description: 'Custom origin request function for the docs',
205
- runtime: lambda.Runtime.NODEJS_20_X,
206
- handler: 'index.handler',
207
- code: lambda.Code.fromInline(`
208
- const config = {
209
- suffix: '.html',
210
- }
211
-
212
- const regexSuffixless = /\\/[^/.]+$/
213
- const regexTrailingSlash = /.+\\/$/
214
-
215
- exports.handler = (event, context, callback) => {
216
- const request = event.Records[0].cf.request;
217
- const uri = request.uri;
218
-
219
- // Append index.html to root URI
220
- if (uri === '/') {
221
- request.uri = '/index.html';
222
- callback(null, request);
223
- return;
224
- }
225
-
226
- // Append .html to suffixless URI
227
- if (uri.match(regexSuffixless)) {
228
- request.uri = uri + '.html';
229
- callback(null, request);
230
- return;
231
- }
232
-
233
- // Remove trailing slash and append .html to origin request
234
- if (uri.match(regexTrailingSlash)) {
235
- request.uri = uri.slice(0, -1) + '.html';
236
- callback(null, request);
237
- return;
238
- }
239
-
240
- callback(null, request);
241
- };
242
- `),
243
- })
244
-
245
- new lambda.CfnPermission(scope, 'DocsOriginRequestFunctionPermission', {
246
- action: 'lambda:InvokeFunction',
247
- principal: 'edgelambda.amazonaws.com',
248
- functionName: docsOriginRequestFunction.functionName,
249
- })
250
-
251
- return docsOriginRequestFunction
252
- }
253
-
254
- getCookieBehavior(cookieBehavior: string | undefined): cloudfront.CacheCookieBehavior | undefined {
255
- switch (cookieBehavior) {
256
- case 'none':
257
- return cloudfront.CacheCookieBehavior.none()
258
- case 'all':
259
- return cloudfront.CacheCookieBehavior.all()
260
- case 'allowList':
261
- return cloudfront.CacheCookieBehavior.allowList(...(config.cloud.cdn?.allowList.cookies || []))
262
- default:
263
- return undefined
264
- }
265
- }
266
-
267
- allowedMethods(): cloudfront.AllowedMethods {
268
- switch (config.cloud.cdn?.allowedMethods) {
269
- case 'ALL':
270
- return cloudfront.AllowedMethods.ALLOW_ALL
271
- case 'GET_HEAD':
272
- return cloudfront.AllowedMethods.ALLOW_GET_HEAD
273
- case 'GET_HEAD_OPTIONS':
274
- return cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS
275
- default:
276
- return cloudfront.AllowedMethods.ALLOW_ALL
277
- }
278
- }
279
-
280
- cachedMethods(): cloudfront.CachedMethods {
281
- switch (config.cloud.cdn?.cachedMethods) {
282
- case 'GET_HEAD':
283
- return cloudfront.CachedMethods.CACHE_GET_HEAD
284
- case 'GET_HEAD_OPTIONS':
285
- return cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS
286
- default:
287
- return cloudfront.CachedMethods.CACHE_GET_HEAD
288
- }
289
- }
290
- }
package/src/cloud/cli.ts DELETED
@@ -1,14 +0,0 @@
1
- import type { Construct } from 'constructs'
2
- import type { NestedCloudProps } from '../types'
3
- import { CfnOutput as Output } from 'aws-cdk-lib'
4
-
5
- export interface CliStackProps extends NestedCloudProps {}
6
-
7
- export class CliStack {
8
- constructor(scope: Construct, props: CliStackProps) {
9
- new Output(scope, 'CliSetupUrl', {
10
- value: `https://api.${props.domain}/install`,
11
- description: 'URL to trigger the CLI setup function',
12
- })
13
- }
14
- }
@@ -1,245 +0,0 @@
1
- import type { aws_certificatemanager as acm, aws_efs as efs } from 'aws-cdk-lib'
2
- import type { Construct } from 'constructs'
3
- import type { EnvKey } from '../../../../env'
4
- import type { NestedCloudProps } from '../types'
5
- import { env } from '@stacksjs/env'
6
- import { path as p } from '@stacksjs/path'
7
- import {
8
- Duration,
9
- aws_ec2 as ec2,
10
- aws_ecs as ecs,
11
- CfnOutput as Output,
12
- RemovalPolicy,
13
- aws_route53 as route53,
14
- aws_route53_targets as route53Targets,
15
- aws_secretsmanager as secretsmanager,
16
- } from 'aws-cdk-lib'
17
- import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2'
18
- import { LogGroup } from 'aws-cdk-lib/aws-logs'
19
-
20
- export interface ComputeStackProps extends NestedCloudProps {
21
- vpc: ec2.Vpc
22
- fileSystem: efs.FileSystem
23
- zone: route53.IHostedZone
24
- certificate: acm.Certificate
25
- }
26
-
27
- export class ComputeStack {
28
- lb: elbv2.ApplicationLoadBalancer
29
- cluster: ecs.Cluster
30
- taskDefinition: ecs.FargateTaskDefinition
31
-
32
- constructor(scope: Construct, props: ComputeStackProps) {
33
- const vpc = props.vpc
34
- const fileSystem = props.fileSystem
35
-
36
- if (!fileSystem)
37
- throw new Error('The file system is missing. Please make sure it was created properly.')
38
-
39
- this.cluster = new ecs.Cluster(scope, 'StacksCluster', {
40
- clusterName: `${props.slug}-${props.appEnv}-web-server-cluster`,
41
- vpc,
42
- })
43
-
44
- this.taskDefinition = new ecs.FargateTaskDefinition(scope, 'TaskDefinition', {
45
- family: `${props.appName}-${props.appEnv}-api`,
46
- memoryLimitMiB: 512, // Match your Lambda memory size
47
- cpu: 256, // Choose an appropriate value
48
- runtimePlatform: {
49
- cpuArchitecture: ecs.CpuArchitecture.ARM64,
50
- },
51
- })
52
-
53
- // const assetImage = new ecr_assets.DockerImageAsset(scope, 'DockerImageAsset', {
54
- // directory: p.frameworkCloudPath(),
55
- // })
56
-
57
- const container = this.taskDefinition.addContainer('WebServerContainer', {
58
- containerName: `${props.appName}-${props.appEnv}-api`,
59
- // image: ecs.ContainerImage.fromDockerImageAsset(assetImage),
60
- image: ecs.ContainerImage.fromAsset(p.frameworkPath('server')),
61
- logging: new ecs.AwsLogDriver({
62
- streamPrefix: `${props.appName}-${props.appEnv}-web-server-logs`,
63
- logGroup: new LogGroup(scope, 'StacksApiLogs', {
64
- logGroupName: '/aws/ecs/stacks-api',
65
- removalPolicy: RemovalPolicy.DESTROY, // Automatically remove logs on stack deletion
66
- }),
67
- }),
68
- healthCheck: {
69
- command: ['CMD-SHELL', 'curl -f http://localhost:3000/health || exit 1'], // requires curl inside the container which isn't available in the base image. I wonder if there is a better way
70
- interval: Duration.seconds(10),
71
- timeout: Duration.seconds(5),
72
- retries: 3,
73
- startPeriod: Duration.seconds(10),
74
- },
75
- })
76
-
77
- container.addPortMappings({
78
- containerPort: 3000,
79
- hostPort: 3000,
80
- })
81
-
82
- const serviceSecurityGroup = new ec2.SecurityGroup(scope, 'ServiceSecurityGroup', {
83
- securityGroupName: `${props.appName}-${props.appEnv}-api-service-sg`,
84
- vpc,
85
- description: 'Stacks Security Group for API Service',
86
- })
87
-
88
- const publicLoadBalancerSG = new ec2.SecurityGroup(scope, 'PublicLoadBalancerSG', {
89
- securityGroupName: `${props.appName}-${props.appEnv}-public-load-balancer-sg`,
90
- vpc,
91
- description: 'Access to the public facing load balancer',
92
- })
93
-
94
- // Assuming serviceSecurityGroup and publicLoadBalancerSG are already defined
95
- serviceSecurityGroup.addIngressRule(publicLoadBalancerSG, ec2.Port.allTraffic(), 'Ingress from the public ALB')
96
-
97
- this.lb = new elbv2.ApplicationLoadBalancer(scope, 'ApplicationLoadBalancer', {
98
- http2Enabled: true,
99
- loadBalancerName: `${props.appName}-${props.appEnv}-alb`,
100
- vpc,
101
- vpcSubnets: {
102
- subnets: vpc.selectSubnets({
103
- subnetType: ec2.SubnetType.PUBLIC,
104
- onePerAz: true,
105
- }).subnets,
106
- },
107
- internetFacing: true,
108
- idleTimeout: Duration.seconds(30),
109
- securityGroup: publicLoadBalancerSG,
110
- })
111
-
112
- new route53.ARecord(scope, 'ApiDomainAliasRecord', {
113
- zone: props.zone,
114
- recordName: 'api',
115
- target: route53.RecordTarget.fromAlias(new route53Targets.LoadBalancerTarget(this.lb)),
116
- })
117
-
118
- const serviceTargetGroup = new elbv2.ApplicationTargetGroup(scope, 'ServiceTargetGroup', {
119
- targetGroupName: `${props.appName}-${props.appEnv}-api-tg`,
120
- vpc,
121
- targetType: elbv2.TargetType.IP,
122
- protocol: elbv2.ApplicationProtocol.HTTP,
123
- port: 3000,
124
- healthCheck: {
125
- interval: Duration.seconds(6),
126
- path: '/health',
127
- protocol: elbv2.Protocol.HTTP,
128
- timeout: Duration.seconds(5),
129
- healthyThresholdCount: 2,
130
- unhealthyThresholdCount: 10,
131
- },
132
- })
133
-
134
- const service = new ecs.FargateService(scope, 'StacksApiService', {
135
- serviceName: `${props.appName}-${props.appEnv}-api-service`,
136
- cluster: this.cluster,
137
- taskDefinition: this.taskDefinition,
138
- desiredCount: 1,
139
- assignPublicIp: true,
140
- maxHealthyPercent: 200,
141
- vpcSubnets: vpc.selectSubnets({
142
- subnetType: ec2.SubnetType.PUBLIC,
143
- onePerAz: true,
144
- }),
145
- minHealthyPercent: 75,
146
- securityGroups: [serviceSecurityGroup],
147
- })
148
-
149
- service.attachToApplicationTargetGroup(serviceTargetGroup)
150
- publicLoadBalancerSG.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.allTraffic())
151
-
152
- this.lb.addListener('HttpsListener', {
153
- port: 443,
154
- certificates: [props.certificate],
155
- defaultAction: elbv2.ListenerAction.forward([serviceTargetGroup]),
156
- })
157
-
158
- this.lb.addListener('HttpListener', {
159
- port: 80,
160
- defaultAction: elbv2.ListenerAction.forward([serviceTargetGroup]),
161
- })
162
-
163
- props.fileSystem.connections.allowFromAnyIpv4(ec2.Port.tcp(2049)) // port 2049 (NFS) for EFS
164
-
165
- const volumeName = `${props.slug}-${props.appEnv}-efs`
166
- this.taskDefinition.addVolume({
167
- name: volumeName,
168
- efsVolumeConfiguration: {
169
- fileSystemId: props.fileSystem.fileSystemId,
170
- },
171
- })
172
-
173
- container.addMountPoints({
174
- sourceVolume: volumeName,
175
- containerPath: '/mnt/efs',
176
- readOnly: false,
177
- })
178
-
179
- // Setup AutoScaling policy
180
- // TODO: make this configurable in cloud.compute
181
- const scaling = service.autoScaleTaskCount({ maxCapacity: 2 })
182
-
183
- scaling.scaleOnCpuUtilization('CpuScaling', {
184
- targetUtilizationPercent: 50,
185
- scaleInCooldown: Duration.seconds(60),
186
- scaleOutCooldown: Duration.seconds(60),
187
- })
188
-
189
- scaling.scaleOnMemoryUtilization('MemoryScaling', {
190
- targetUtilizationPercent: 60,
191
- scaleInCooldown: Duration.seconds(60),
192
- scaleOutCooldown: Duration.seconds(60),
193
- })
194
-
195
- const keysToRemove = [
196
- '_HANDLER',
197
- '_X_AMZN_TRACE_ID',
198
- 'AWS_REGION',
199
- 'AWS_EXECUTION_ENV',
200
- 'AWS_LAMBDA_FUNCTION_NAME',
201
- 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE',
202
- 'AWS_LAMBDA_FUNCTION_VERSION',
203
- 'AWS_LAMBDA_INITIALIZATION_TYPE',
204
- 'AWS_LAMBDA_LOG_GROUP_NAME',
205
- 'AWS_LAMBDA_LOG_STREAM_NAME',
206
- 'AWS_ACCESS_KEY',
207
- 'AWS_ACCESS_KEY_ID',
208
- 'AWS_SECRET_ACCESS_KEY',
209
- 'AWS_SESSION_TOKEN',
210
- 'AWS_LAMBDA_RUNTIME_API',
211
- 'LAMBDA_TASK_ROOT',
212
- 'LAMBDA_RUNTIME_DIR',
213
- '_',
214
- ]
215
- keysToRemove.forEach(key => delete env[key as EnvKey])
216
-
217
- const secrets = new secretsmanager.Secret(scope, 'StacksSecrets', {
218
- secretName: `${props.slug}-${props.appEnv}-secrets`,
219
- description: 'Secrets for the Stacks application',
220
- generateSecretString: {
221
- secretStringTemplate: JSON.stringify(env),
222
- generateStringKey: Object.keys(env).join(',').length.toString(),
223
- },
224
- })
225
-
226
- if (service.taskDefinition.executionRole) {
227
- secrets.grantRead(service.taskDefinition.executionRole)
228
- container.addEnvironment('SECRETS_ARN', secrets.secretArn)
229
- }
230
- else {
231
- throw new Error('Service task execution role is undefined.')
232
- }
233
-
234
- const apiPrefix = 'api'
235
- new Output(scope, 'ApiUrl', {
236
- value: `https://${apiPrefix}.${props.domain}/`,
237
- description: 'The URL of the deployed application',
238
- })
239
-
240
- new Output(scope, 'ApiVanityUrl', {
241
- value: `http://${this.lb.loadBalancerDnsName}`,
242
- description: 'The Vanity URL / DNS name of the load balancer',
243
- })
244
- }
245
- }
@@ -1,85 +0,0 @@
1
- // // TODO: finish this cloudwatch dashboard
2
- // // import type { aws_lambda as lambda } from 'aws-cdk-lib'
3
- // import { Aws, CfnOutput as Output, aws_cloudwatch as cloudwatch } from 'aws-cdk-lib'
4
- // import type { Construct } from 'constructs'
5
- // import type { NestedCloudProps } from '../types'
6
- //
7
- // export interface DashboardStackProps extends NestedCloudProps {
8
- // dashboardName?: string
9
- // }
10
- //
11
- // export class DashboardStack {
12
- // // lambdaFunction: lambda.Function
13
- // dashboard: cloudwatch.Dashboard
14
- //
15
- // constructor(scope: Construct, props: DashboardStackProps) {
16
- // const dashboardName = props.dashboardName || 'StacksDashboard'
17
- //
18
- // // Create Sample Lambda Function which will create metrics
19
- // // this.lambdaFunction = new Function(this, 'SampleLambda', {
20
- // // handler: 'lambda-handler.handler',
21
- // // runtime: Runtime.PYTHON_3_7,
22
- // // code: new AssetCode(`./lambda`),
23
- // // memorySize: 512,
24
- // // timeout: Duration.seconds(10),
25
- // // })
26
- //
27
- // // Create CloudWatch Dashboard
28
- // this.dashboard = new cloudwatch.Dashboard(scope, 'SampleLambdaDashboard', {
29
- // dashboardName,
30
- // })
31
- //
32
- // // Create Title for Dashboard
33
- // this.dashboard.addWidgets(new cloudwatch.TextWidget({
34
- // markdown: `# Dashboard: `,
35
- // // markdown: `# Dashboard: ${this.lambdaFunction.functionName}`,
36
- // height: 1,
37
- // width: 24,
38
- // }))
39
- //
40
- // // Create CloudWatch Dashboard Widgets: Errors, Invocations, Duration, Throttles
41
- // this.dashboard.addWidgets(new cloudwatch.GraphWidget({
42
- // title: 'Invocations',
43
- // left: [this.lambdaFunction.metricInvocations()],
44
- // width: 24,
45
- // }))
46
- //
47
- // this.dashboard.addWidgets(new cloudwatch.GraphWidget({
48
- // title: 'Errors',
49
- // left: [this.lambdaFunction.metricErrors()],
50
- // width: 24,
51
- // }))
52
- //
53
- // this.dashboard.addWidgets(new cloudwatch.GraphWidget({
54
- // title: 'Duration',
55
- // left: [this.lambdaFunction.metricDuration()],
56
- // width: 24,
57
- // }))
58
- //
59
- // this.dashboard.addWidgets(new cloudwatch.GraphWidget({
60
- // title: 'Throttles',
61
- // left: [this.lambdaFunction.metricThrottles()],
62
- // width: 24,
63
- // }))
64
- //
65
- // // Create Widget to show last 20 Log Entries
66
- // this.dashboard.addWidgets(new cloudwatch.LogQueryWidget({
67
- // logGroupNames: [this.lambdaFunction.logGroup.logGroupName],
68
- // queryLines: [
69
- // 'fields @timestamp, @message',
70
- // 'sort @timestamp desc',
71
- // 'limit 20',
72
- // ],
73
- // width: 24,
74
- // }))
75
- //
76
- // // Generate Output
77
- // const cloudwatchDashboardURL = `https://${Aws.REGION}.console.aws.amazon.com/cloudwatch/home?region=${Aws.REGION}#dashboards:name=${dashboardName}`
78
- //
79
- // new Output(scope, 'DashboardOutput', {
80
- // value: cloudwatchDashboardURL,
81
- // description: 'The CloudWatch Dashboard URL',
82
- // exportName: 'StacksDashboardURL',
83
- // })
84
- // }
85
- // }
@@ -1,34 +0,0 @@
1
- import type { aws_ec2 as ec2 } from 'aws-cdk-lib'
2
- import type { Construct } from 'constructs'
3
- import type { NestedCloudProps } from '../types'
4
- import { aws_dynamodb as dynamodb, RemovalPolicy } from 'aws-cdk-lib'
5
-
6
- export interface DatabaseStackProps extends NestedCloudProps {
7
- vpc: ec2.Vpc
8
- }
9
-
10
- export class DatabaseStack {
11
- database: dynamodb.Table
12
-
13
- constructor(scope: Construct, props: DatabaseStackProps) {
14
- this.database = new dynamodb.Table(scope, 'Database', {
15
- tableName: `${props.slug}-${props.appEnv}-database`,
16
- partitionKey: {
17
- // wip
18
- name: 'id',
19
- type: dynamodb.AttributeType.STRING,
20
- },
21
- sortKey: {
22
- // wip
23
- name: 'sort',
24
- type: dynamodb.AttributeType.STRING,
25
- },
26
- billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
27
- readCapacity: 5,
28
- writeCapacity: 5,
29
- pointInTimeRecovery: true,
30
- removalPolicy: RemovalPolicy.DESTROY,
31
- encryption: dynamodb.TableEncryption.AWS_MANAGED,
32
- })
33
- }
34
- }