@studion/infra-code-blocks 0.1.9 → 0.2.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.
@@ -5,49 +5,33 @@ const pulumi = require("@pulumi/pulumi");
5
5
  const aws = require("@pulumi/aws");
6
6
  const constants_1 = require("../constants");
7
7
  const acm_certificate_1 = require("./acm-certificate");
8
- const config = new pulumi.Config('aws');
9
- const awsRegion = config.require('region');
10
- const assumeRolePolicy = {
11
- Version: '2012-10-17',
12
- Statement: [
13
- {
14
- Action: 'sts:AssumeRole',
15
- Principal: {
16
- Service: 'ecs-tasks.amazonaws.com',
17
- },
18
- Effect: 'Allow',
19
- Sid: '',
20
- },
21
- ],
22
- };
8
+ const ecs_service_1 = require("./ecs-service");
23
9
  const defaults = {
24
- desiredCount: 1,
25
- minCount: 1,
26
- maxCount: 10,
27
- size: 'small',
28
- environment: [],
29
- secrets: [],
30
- healtCheckPath: '/healtcheck',
31
- taskExecutionRoleInlinePolicies: [],
32
- taskRoleInlinePolicies: [],
10
+ healthCheckPath: '/healthcheck',
33
11
  };
34
12
  class WebServer extends pulumi.ComponentResource {
35
13
  constructor(name, args, opts = {}) {
36
- super('studion:WebServer', name, {}, opts);
14
+ super('studion:WebServer', name, args, opts);
15
+ const { vpcId, domain, hostedZoneId } = args;
16
+ const hasCustomDomain = !!domain && !!hostedZoneId;
17
+ if (domain && !hostedZoneId) {
18
+ throw new Error('WebServer:hostedZoneId must be provided when the domain is specified');
19
+ }
37
20
  this.name = name;
38
- const { domain, hostedZoneId, vpc, port, healtCheckPath } = args;
39
- this.certificate = this.createTlsCertificate({ domain, hostedZoneId });
40
- this.logGroup = this.createLogGroup();
41
- const { lb, lbTargetGroup, lbHttpListener, lbTlsListener, lbSecurityGroup, } = this.createLoadBalancer({ vpc, port, healtCheckPath });
21
+ if (hasCustomDomain) {
22
+ this.certificate = this.createTlsCertificate({ domain, hostedZoneId });
23
+ }
24
+ const { lb, lbTargetGroup, lbHttpListener, lbTlsListener, lbSecurityGroup, } = this.createLoadBalancer(args);
42
25
  this.lb = lb;
43
26
  this.lbTargetGroup = lbTargetGroup;
44
27
  this.lbHttpListener = lbHttpListener;
45
28
  this.lbTlsListener = lbTlsListener;
46
29
  this.lbSecurityGroup = lbSecurityGroup;
47
- this.taskDefinition = this.createTaskDefinition(args);
30
+ this.serviceSecurityGroup = this.createSecurityGroup(vpcId);
48
31
  this.service = this.createEcsService(args);
49
- this.createDnsRecord({ domain, hostedZoneId });
50
- this.enableAutoscaling(args);
32
+ if (hasCustomDomain) {
33
+ this.createDnsRecord({ domain, hostedZoneId });
34
+ }
51
35
  this.registerOutputs();
52
36
  }
53
37
  createTlsCertificate({ domain, hostedZoneId, }) {
@@ -57,17 +41,9 @@ class WebServer extends pulumi.ComponentResource {
57
41
  }, { parent: this });
58
42
  return certificate;
59
43
  }
60
- createLogGroup() {
61
- const logGroup = new aws.cloudwatch.LogGroup(`${this.name}-log-group`, {
62
- retentionInDays: 14,
63
- namePrefix: `/ecs/${this.name}-`,
64
- tags: constants_1.commonTags,
65
- }, { parent: this });
66
- return logGroup;
67
- }
68
- createLoadBalancer({ vpc, port, healtCheckPath, }) {
44
+ createLoadBalancer({ vpcId, publicSubnetIds, port, healthCheckPath, }) {
69
45
  const lbSecurityGroup = new aws.ec2.SecurityGroup(`${this.name}-lb-security-group`, {
70
- vpcId: vpc.vpcId,
46
+ vpcId,
71
47
  ingress: [
72
48
  {
73
49
  protocol: 'tcp',
@@ -95,7 +71,7 @@ class WebServer extends pulumi.ComponentResource {
95
71
  const lb = new aws.lb.LoadBalancer(`${this.name}-lb`, {
96
72
  namePrefix: 'lb-',
97
73
  loadBalancerType: 'application',
98
- subnets: vpc.publicSubnetIds,
74
+ subnets: publicSubnetIds,
99
75
  securityGroups: [lbSecurityGroup.id],
100
76
  internal: false,
101
77
  ipAddressType: 'ipv4',
@@ -106,13 +82,13 @@ class WebServer extends pulumi.ComponentResource {
106
82
  port,
107
83
  protocol: 'HTTP',
108
84
  targetType: 'ip',
109
- vpcId: vpc.vpcId,
85
+ vpcId,
110
86
  healthCheck: {
111
87
  healthyThreshold: 3,
112
88
  unhealthyThreshold: 2,
113
89
  interval: 60,
114
90
  timeout: 5,
115
- path: healtCheckPath || defaults.healtCheckPath,
91
+ path: healthCheckPath || defaults.healthCheckPath,
116
92
  },
117
93
  tags: Object.assign(Object.assign({}, constants_1.commonTags), { Name: `${this.name}-lb-target-group` }),
118
94
  }, { parent: this, dependsOn: [this.lb] });
@@ -131,20 +107,23 @@ class WebServer extends pulumi.ComponentResource {
131
107
  ],
132
108
  tags: constants_1.commonTags,
133
109
  }, { parent: this });
134
- const lbTlsListener = new aws.lb.Listener(`${this.name}-lb-listener-443`, {
135
- loadBalancerArn: lb.arn,
136
- port: 443,
137
- protocol: 'HTTPS',
138
- sslPolicy: 'ELBSecurityPolicy-2016-08',
139
- certificateArn: this.certificate.certificate.arn,
140
- defaultActions: [
141
- {
142
- type: 'forward',
143
- targetGroupArn: lbTargetGroup.arn,
144
- },
145
- ],
146
- tags: constants_1.commonTags,
147
- }, { parent: this });
110
+ let lbTlsListener = undefined;
111
+ if (this.certificate) {
112
+ lbTlsListener = new aws.lb.Listener(`${this.name}-lb-listener-443`, {
113
+ loadBalancerArn: lb.arn,
114
+ port: 443,
115
+ protocol: 'HTTPS',
116
+ sslPolicy: 'ELBSecurityPolicy-2016-08',
117
+ certificateArn: this.certificate.certificate.arn,
118
+ defaultActions: [
119
+ {
120
+ type: 'forward',
121
+ targetGroupArn: lbTargetGroup.arn,
122
+ },
123
+ ],
124
+ tags: constants_1.commonTags,
125
+ }, { parent: this });
126
+ }
148
127
  return {
149
128
  lb,
150
129
  lbTargetGroup,
@@ -153,129 +132,9 @@ class WebServer extends pulumi.ComponentResource {
153
132
  lbSecurityGroup,
154
133
  };
155
134
  }
156
- createTaskDefinition(args) {
157
- const argsWithDefaults = Object.assign({}, defaults, args);
158
- const stack = pulumi.getStack();
159
- const secretManagerSecretsInlinePolicy = {
160
- name: `${this.name}-secret-manager-access`,
161
- policy: JSON.stringify({
162
- Version: '2012-10-17',
163
- Statement: [
164
- {
165
- Sid: 'AllowContainerToGetSecretManagerSecrets',
166
- Effect: 'Allow',
167
- Action: ['secretsmanager:GetSecretValue'],
168
- Resource: '*',
169
- },
170
- ],
171
- }),
172
- };
173
- const taskExecutionRole = new aws.iam.Role(`${this.name}-ecs-task-exec-role`, {
174
- namePrefix: `${this.name}-ecs-task-exec-role-`,
175
- assumeRolePolicy,
176
- managedPolicyArns: [
177
- 'arn:aws:iam::aws:policy/CloudWatchFullAccess',
178
- 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess',
179
- ],
180
- inlinePolicies: [
181
- secretManagerSecretsInlinePolicy,
182
- ...argsWithDefaults.taskExecutionRoleInlinePolicies,
183
- ],
184
- tags: constants_1.commonTags,
185
- }, { parent: this });
186
- const execCmdInlinePolicy = {
187
- name: `${this.name}-ecs-exec`,
188
- policy: JSON.stringify({
189
- Version: '2012-10-17',
190
- Statement: [
191
- {
192
- Sid: 'AllowContainerToCreateECSExecSSMChannel',
193
- Effect: 'Allow',
194
- Action: [
195
- 'ssmmessages:CreateControlChannel',
196
- 'ssmmessages:CreateDataChannel',
197
- 'ssmmessages:OpenControlChannel',
198
- 'ssmmessages:OpenDataChannel',
199
- ],
200
- Resource: '*',
201
- },
202
- ],
203
- }),
204
- };
205
- const taskRole = new aws.iam.Role(`${this.name}-ecs-task-role`, {
206
- namePrefix: `${this.name}-ecs-task-role-`,
207
- assumeRolePolicy,
208
- inlinePolicies: [
209
- execCmdInlinePolicy,
210
- ...argsWithDefaults.taskRoleInlinePolicies,
211
- ],
212
- tags: constants_1.commonTags,
213
- }, { parent: this });
214
- const parsedSize = pulumi.all([argsWithDefaults.size]).apply(([size]) => {
215
- const mapCapabilities = ({ cpu, memory }) => ({
216
- cpu: String(cpu),
217
- memory: String(memory),
218
- });
219
- if (typeof size === 'string') {
220
- return mapCapabilities(constants_1.PredefinedSize[size]);
221
- }
222
- if (typeof size === 'object') {
223
- return mapCapabilities(size);
224
- }
225
- throw Error('Incorrect EcsService size argument');
226
- });
227
- const taskDefinition = new aws.ecs.TaskDefinition(`${this.name}-task-definition`, {
228
- family: `${this.name}-task-definition-${stack}`,
229
- networkMode: 'awsvpc',
230
- executionRoleArn: taskExecutionRole.arn,
231
- taskRoleArn: taskRole.arn,
232
- cpu: parsedSize.cpu,
233
- memory: parsedSize.memory,
234
- requiresCompatibilities: ['FARGATE'],
235
- containerDefinitions: pulumi
236
- .all([
237
- this.name,
238
- argsWithDefaults.image,
239
- argsWithDefaults.port,
240
- argsWithDefaults.environment,
241
- argsWithDefaults.secrets,
242
- this.logGroup.name,
243
- awsRegion,
244
- ])
245
- .apply(([containerName, image, port, environment, secrets, logGroup, region,]) => {
246
- return JSON.stringify([
247
- {
248
- readonlyRootFilesystem: false,
249
- name: containerName,
250
- image,
251
- essential: true,
252
- portMappings: [
253
- {
254
- containerPort: port,
255
- protocol: 'tcp',
256
- },
257
- ],
258
- logConfiguration: {
259
- logDriver: 'awslogs',
260
- options: {
261
- 'awslogs-group': logGroup,
262
- 'awslogs-region': region,
263
- 'awslogs-stream-prefix': 'ecs',
264
- },
265
- },
266
- environment,
267
- secrets,
268
- },
269
- ]);
270
- }),
271
- tags: Object.assign(Object.assign({}, constants_1.commonTags), argsWithDefaults.tags),
272
- }, { parent: this });
273
- return taskDefinition;
274
- }
275
- createEcsService(args) {
276
- const argsWithDefaults = Object.assign({}, defaults, args);
277
- const serviceSecurityGroup = new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
278
- vpcId: argsWithDefaults.vpc.vpcId,
135
+ createSecurityGroup(vpcId) {
136
+ const securityGroup = new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
137
+ vpcId,
279
138
  ingress: [
280
139
  {
281
140
  fromPort: 0,
@@ -294,34 +153,12 @@ class WebServer extends pulumi.ComponentResource {
294
153
  ],
295
154
  tags: constants_1.commonTags,
296
155
  }, { parent: this });
297
- const service = new aws.ecs.Service(`${this.name}-service`, {
298
- name: this.name,
299
- cluster: argsWithDefaults.cluster.id,
300
- launchType: 'FARGATE',
301
- desiredCount: argsWithDefaults.desiredCount,
302
- taskDefinition: this.taskDefinition.arn,
303
- enableExecuteCommand: true,
304
- loadBalancers: [
305
- {
306
- containerName: this.name,
307
- containerPort: argsWithDefaults.port,
308
- targetGroupArn: this.lbTargetGroup.arn,
309
- },
310
- ],
311
- networkConfiguration: {
312
- assignPublicIp: true,
313
- subnets: argsWithDefaults.vpc.publicSubnetIds,
314
- securityGroups: [serviceSecurityGroup.id],
315
- },
316
- tags: Object.assign(Object.assign({}, constants_1.commonTags), argsWithDefaults.tags),
317
- }, {
156
+ return securityGroup;
157
+ }
158
+ createEcsService(args) {
159
+ const service = new ecs_service_1.EcsService(this.name, Object.assign(Object.assign({}, args), { enableServiceAutoDiscovery: false, lbTargetGroupArn: this.lbTargetGroup.arn, assignPublicIp: true, subnetIds: args.publicSubnetIds, securityGroup: this.serviceSecurityGroup }), {
318
160
  parent: this,
319
- dependsOn: [
320
- this.lb,
321
- this.lbTargetGroup,
322
- this.lbHttpListener,
323
- this.lbTlsListener,
324
- ],
161
+ dependsOn: [this.lb, this.lbTargetGroup],
325
162
  });
326
163
  return service;
327
164
  }
@@ -339,40 +176,5 @@ class WebServer extends pulumi.ComponentResource {
339
176
  ],
340
177
  }, { parent: this });
341
178
  }
342
- enableAutoscaling(args) {
343
- const argsWithDefaults = Object.assign({}, defaults, args);
344
- const autoscalingTarget = new aws.appautoscaling.Target(`${this.name}-autoscale-target`, {
345
- minCapacity: argsWithDefaults.minCount,
346
- maxCapacity: argsWithDefaults.maxCount,
347
- resourceId: pulumi.interpolate `service/${argsWithDefaults.cluster.name}/${this.service.name}`,
348
- serviceNamespace: 'ecs',
349
- scalableDimension: 'ecs:service:DesiredCount',
350
- tags: constants_1.commonTags,
351
- }, { parent: this });
352
- const memoryAutoscalingPolicy = new aws.appautoscaling.Policy(`${this.name}-memory-autoscale-policy`, {
353
- policyType: 'TargetTrackingScaling',
354
- resourceId: autoscalingTarget.resourceId,
355
- scalableDimension: autoscalingTarget.scalableDimension,
356
- serviceNamespace: autoscalingTarget.serviceNamespace,
357
- targetTrackingScalingPolicyConfiguration: {
358
- predefinedMetricSpecification: {
359
- predefinedMetricType: 'ECSServiceAverageMemoryUtilization',
360
- },
361
- targetValue: 80,
362
- },
363
- }, { parent: this });
364
- const cpuAutoscalingPolicy = new aws.appautoscaling.Policy(`${this.name}-cpu-autoscale-policy`, {
365
- policyType: 'TargetTrackingScaling',
366
- resourceId: autoscalingTarget.resourceId,
367
- scalableDimension: autoscalingTarget.scalableDimension,
368
- serviceNamespace: autoscalingTarget.serviceNamespace,
369
- targetTrackingScalingPolicyConfiguration: {
370
- predefinedMetricSpecification: {
371
- predefinedMetricType: 'ECSServiceAverageCPUUtilization',
372
- },
373
- targetValue: 60,
374
- },
375
- }, { parent: this });
376
- }
377
179
  }
378
180
  exports.WebServer = WebServer;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export * from './components/web-server';
2
+ export * from './components/mongo';
2
3
  export * from './components/static-site';
3
4
  export * from './components/database';
4
5
  export * from './components/redis';
5
6
  export * from './components/project';
6
7
  export * from './components/ec2-ssm-connect';
8
+ export * from './components/ecs-service';
9
+ export * from './components/nuxt-ssr';
package/dist/index.js CHANGED
@@ -15,8 +15,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./components/web-server"), exports);
18
+ __exportStar(require("./components/mongo"), exports);
18
19
  __exportStar(require("./components/static-site"), exports);
19
20
  __exportStar(require("./components/database"), exports);
20
21
  __exportStar(require("./components/redis"), exports);
21
22
  __exportStar(require("./components/project"), exports);
22
23
  __exportStar(require("./components/ec2-ssm-connect"), exports);
24
+ __exportStar(require("./components/ecs-service"), exports);
25
+ __exportStar(require("./components/nuxt-ssr"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studion/infra-code-blocks",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "Studion common infra components",
5
5
  "keywords": [
6
6
  "infrastructure",