@studion/infra-code-blocks 2.0.0-alpha.4 → 2.0.0-alpha.6
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/dist/components/acm-certificate/index.js +6 -1
- package/dist/components/cloudfront/index.d.ts.map +1 -1
- package/dist/components/cloudfront/index.js +97 -55
- package/dist/components/cloudfront/lb-cache-strategy.js +9 -1
- package/dist/components/cloudfront/s3-cache-strategy.js +12 -4
- package/dist/components/database/builder.js +34 -7
- package/dist/components/database/database-replica.js +27 -3
- package/dist/components/database/ec2-ssm-connect.d.ts +2 -1
- package/dist/components/database/ec2-ssm-connect.d.ts.map +1 -1
- package/dist/components/database/ec2-ssm-connect.js +33 -16
- package/dist/components/database/index.js +55 -7
- package/dist/components/ecs-service/index.js +70 -28
- package/dist/components/grafana/dashboards/panels.js +23 -17
- package/dist/components/grafana/dashboards/web-server-slo.js +4 -1
- package/dist/components/password/index.js +7 -1
- package/dist/components/prometheus/queries.test.js +10 -19
- package/dist/components/redis/elasticache-redis.js +6 -1
- package/dist/components/redis/upstash-redis.js +8 -2
- package/dist/components/static-site/index.js +7 -1
- package/dist/components/static-site/s3-assets.js +4 -1
- package/dist/components/vpc/index.js +2 -1
- package/dist/components/web-server/builder.js +32 -6
- package/dist/components/web-server/index.js +47 -15
- package/dist/components/web-server/load-balancer.js +13 -3
- package/dist/otel/builder.js +4 -1
- package/dist/otel/config.js +11 -14
- package/dist/otel/index.js +7 -3
- package/package.json +36 -44
|
@@ -39,8 +39,21 @@ const defaults = {
|
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
class EcsService extends pulumi.ComponentResource {
|
|
42
|
+
name;
|
|
43
|
+
vpc;
|
|
44
|
+
logGroup;
|
|
45
|
+
taskDefinition;
|
|
46
|
+
taskExecutionRole;
|
|
47
|
+
taskRole;
|
|
48
|
+
service;
|
|
49
|
+
securityGroups;
|
|
50
|
+
serviceDiscoveryService;
|
|
51
|
+
persistentStorage;
|
|
42
52
|
constructor(name, args, opts = {}) {
|
|
43
|
-
super('studion:ecs-service:EcsService', name, {},
|
|
53
|
+
super('studion:ecs-service:EcsService', name, {}, {
|
|
54
|
+
...opts,
|
|
55
|
+
aliases: [...(opts.aliases || []), { type: 'studion:ecs:Service' }],
|
|
56
|
+
});
|
|
44
57
|
const argsWithDefaults = (0, merge_with_defaults_1.mergeWithDefaults)(defaults, args);
|
|
45
58
|
const taskExecutionRoleInlinePolicies = pulumi.output(args.taskExecutionRoleInlinePolicies ||
|
|
46
59
|
defaults.taskExecutionRoleInlinePolicies);
|
|
@@ -56,7 +69,7 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
56
69
|
this.persistentStorage = this.createPersistentStorage(this.vpc);
|
|
57
70
|
}
|
|
58
71
|
});
|
|
59
|
-
this.taskDefinition = this.createTaskDefinition(argsWithDefaults.containers, pulumi.output(argsWithDefaults.volumes), this.taskExecutionRole, this.taskRole, argsWithDefaults.family, argsWithDefaults.size,
|
|
72
|
+
this.taskDefinition = this.createTaskDefinition(argsWithDefaults.containers, pulumi.output(argsWithDefaults.volumes), this.taskExecutionRole, this.taskRole, argsWithDefaults.family, argsWithDefaults.size, { ...common_tags_1.commonTags, ...argsWithDefaults.tags });
|
|
60
73
|
if (argsWithDefaults.enableServiceAutoDiscovery) {
|
|
61
74
|
this.serviceDiscoveryService = this.createServiceDiscovery();
|
|
62
75
|
}
|
|
@@ -76,7 +89,7 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
76
89
|
createLogGroup(namePrefix) {
|
|
77
90
|
const logGroup = new aws.cloudwatch.LogGroup(`${this.name}-log-group`, {
|
|
78
91
|
retentionInDays: 14,
|
|
79
|
-
namePrefix: namePrefix
|
|
92
|
+
namePrefix: namePrefix ?? `/ecs/${this.name}-`,
|
|
80
93
|
tags: common_tags_1.commonTags,
|
|
81
94
|
}, { parent: this });
|
|
82
95
|
return logGroup;
|
|
@@ -90,8 +103,18 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
90
103
|
const taskDefinitionVolumes = this.createTaskDefinitionVolumes(volumes);
|
|
91
104
|
return pulumi.all(containerDefinitions).apply(containerDefinitions => {
|
|
92
105
|
return taskDefinitionVolumes.apply(volumes => {
|
|
93
|
-
return new aws.ecs.TaskDefinition(`${this.name}-task-definition`,
|
|
94
|
-
|
|
106
|
+
return new aws.ecs.TaskDefinition(`${this.name}-task-definition`, {
|
|
107
|
+
family: family ?? `${this.name}-task-definition-${stack}`,
|
|
108
|
+
networkMode: 'awsvpc',
|
|
109
|
+
executionRoleArn: taskExecutionRole.arn,
|
|
110
|
+
taskRoleArn: taskRole.arn,
|
|
111
|
+
cpu,
|
|
112
|
+
memory,
|
|
113
|
+
requiresCompatibilities: ['FARGATE'],
|
|
114
|
+
containerDefinitions: JSON.stringify(containerDefinitions),
|
|
115
|
+
...(volumes?.length ? { volumes } : {}),
|
|
116
|
+
tags: { ...common_tags_1.commonTags, ...tags },
|
|
117
|
+
}, { parent: this });
|
|
95
118
|
});
|
|
96
119
|
});
|
|
97
120
|
}
|
|
@@ -113,26 +136,31 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
113
136
|
});
|
|
114
137
|
}
|
|
115
138
|
createContainerDefinition(container) {
|
|
116
|
-
return this.logGroup.name.apply(logGroupName => (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
mountPoint
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
139
|
+
return this.logGroup.name.apply(logGroupName => ({
|
|
140
|
+
...container,
|
|
141
|
+
readonlyRootFilesystem: false,
|
|
142
|
+
...(container.mountPoints && {
|
|
143
|
+
mountPoints: container.mountPoints.map(mountPoint => pulumi
|
|
144
|
+
.all([
|
|
145
|
+
mountPoint.sourceVolume,
|
|
146
|
+
mountPoint.containerPath,
|
|
147
|
+
mountPoint.readOnly,
|
|
148
|
+
])
|
|
149
|
+
.apply(([sourceVolume, containerPath, readOnly]) => ({
|
|
150
|
+
containerPath,
|
|
151
|
+
sourceVolume,
|
|
152
|
+
readOnly: readOnly ?? false,
|
|
153
|
+
}))),
|
|
154
|
+
}),
|
|
155
|
+
logConfiguration: {
|
|
129
156
|
logDriver: 'awslogs',
|
|
130
157
|
options: {
|
|
131
158
|
'awslogs-group': logGroupName,
|
|
132
159
|
'awslogs-region': awsRegion,
|
|
133
160
|
'awslogs-stream-prefix': 'ecs',
|
|
134
161
|
},
|
|
135
|
-
}
|
|
162
|
+
},
|
|
163
|
+
}));
|
|
136
164
|
}
|
|
137
165
|
createTaskExecutionRole(inlinePolicies) {
|
|
138
166
|
const secretManagerSecretsInlinePolicy = {
|
|
@@ -221,7 +249,6 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
221
249
|
this.addSecurityGroup(securityGroup);
|
|
222
250
|
}
|
|
223
251
|
createEcsService(ecsServiceArgs) {
|
|
224
|
-
var _a;
|
|
225
252
|
if (ecsServiceArgs.securityGroup) {
|
|
226
253
|
this.addSecurityGroup(ecsServiceArgs.securityGroup);
|
|
227
254
|
}
|
|
@@ -237,13 +264,25 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
237
264
|
.all(this.securityGroups)
|
|
238
265
|
.apply(groups => groups.map(it => it.id)),
|
|
239
266
|
};
|
|
240
|
-
return new aws.ecs.Service(`${this.name}-service`,
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
267
|
+
return new aws.ecs.Service(`${this.name}-service`, {
|
|
268
|
+
name: ecsServiceArgs.name ?? this.name,
|
|
269
|
+
cluster: pulumi.output(ecsServiceArgs.cluster).id,
|
|
270
|
+
launchType: 'FARGATE',
|
|
271
|
+
deploymentController: { type: ecsServiceArgs.deploymentController },
|
|
272
|
+
desiredCount: ecsServiceArgs.desiredCount,
|
|
273
|
+
taskDefinition: this.taskDefinition.arn,
|
|
274
|
+
enableExecuteCommand: true,
|
|
275
|
+
networkConfiguration,
|
|
276
|
+
...(ecsServiceArgs.loadBalancers && {
|
|
277
|
+
loadBalancers: ecsServiceArgs.loadBalancers,
|
|
278
|
+
}),
|
|
279
|
+
...(this.serviceDiscoveryService && {
|
|
280
|
+
serviceRegistries: {
|
|
281
|
+
registryArn: this.serviceDiscoveryService.arn,
|
|
282
|
+
},
|
|
283
|
+
}),
|
|
284
|
+
tags: { ...common_tags_1.commonTags, ...ecsServiceArgs.tags },
|
|
285
|
+
}, { parent: this });
|
|
247
286
|
}
|
|
248
287
|
createServiceDiscovery() {
|
|
249
288
|
const privateDnsNamespace = this.createPrivateDnsNameSpace();
|
|
@@ -316,7 +355,10 @@ class EcsService extends pulumi.ComponentResource {
|
|
|
316
355
|
],
|
|
317
356
|
performanceMode: 'generalPurpose',
|
|
318
357
|
throughputMode: 'bursting',
|
|
319
|
-
tags:
|
|
358
|
+
tags: {
|
|
359
|
+
...common_tags_1.commonTags,
|
|
360
|
+
Name: `${this.name}-data`,
|
|
361
|
+
},
|
|
320
362
|
}, { parent: this });
|
|
321
363
|
const securityGroup = new aws.ec2.SecurityGroup(`${this.name}-persistent-storage-security-group`, {
|
|
322
364
|
vpcId: vpc.vpcId,
|
|
@@ -22,14 +22,17 @@ function createStatPercentagePanel(title, position, dataSource, metric) {
|
|
|
22
22
|
},
|
|
23
23
|
],
|
|
24
24
|
fieldConfig: {
|
|
25
|
-
defaults:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
defaults: {
|
|
26
|
+
...percentageFieldConfig,
|
|
27
|
+
...(metric.thresholds
|
|
28
|
+
? {
|
|
29
|
+
thresholds: {
|
|
30
|
+
mode: 'absolute',
|
|
31
|
+
steps: metric.thresholds,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
: {}),
|
|
35
|
+
},
|
|
33
36
|
},
|
|
34
37
|
};
|
|
35
38
|
}
|
|
@@ -49,16 +52,19 @@ function createTimeSeriesPanel(title, position, dataSource, metric, unit, min, m
|
|
|
49
52
|
},
|
|
50
53
|
],
|
|
51
54
|
fieldConfig: {
|
|
52
|
-
defaults:
|
|
55
|
+
defaults: {
|
|
56
|
+
unit,
|
|
53
57
|
min,
|
|
54
|
-
max
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
max,
|
|
59
|
+
...(metric.thresholds
|
|
60
|
+
? {
|
|
61
|
+
thresholds: {
|
|
62
|
+
mode: 'absolute',
|
|
63
|
+
steps: metric.thresholds,
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
: {}),
|
|
67
|
+
},
|
|
62
68
|
},
|
|
63
69
|
};
|
|
64
70
|
}
|
|
@@ -5,8 +5,11 @@ const grafana = require("@pulumiverse/grafana");
|
|
|
5
5
|
const prometheus_1 = require("../../prometheus");
|
|
6
6
|
const panels_1 = require("./panels");
|
|
7
7
|
class WebServerSloDashboardBuilder {
|
|
8
|
+
name;
|
|
9
|
+
title;
|
|
10
|
+
panels = [];
|
|
11
|
+
tags;
|
|
8
12
|
constructor(name, args) {
|
|
9
|
-
this.panels = [];
|
|
10
13
|
this.name = name;
|
|
11
14
|
this.title = pulumi.output(args.title);
|
|
12
15
|
}
|
|
@@ -6,8 +6,14 @@ const pulumi = require("@pulumi/pulumi");
|
|
|
6
6
|
const random = require("@pulumi/random");
|
|
7
7
|
const common_tags_1 = require("../../shared/common-tags");
|
|
8
8
|
class Password extends pulumi.ComponentResource {
|
|
9
|
+
name;
|
|
10
|
+
value;
|
|
11
|
+
secret;
|
|
9
12
|
constructor(name, args = {}, opts = {}) {
|
|
10
|
-
super('studion:password:Password', name, {},
|
|
13
|
+
super('studion:password:Password', name, {}, {
|
|
14
|
+
...opts,
|
|
15
|
+
aliases: [...(opts.aliases || []), { type: 'studion:Password' }],
|
|
16
|
+
});
|
|
11
17
|
this.name = name;
|
|
12
18
|
if (args.value) {
|
|
13
19
|
this.value = pulumi.secret(args.value);
|
|
@@ -1,46 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const node_test_1 = require("node:test");
|
|
13
4
|
const assert = require("node:assert/strict");
|
|
14
5
|
const queries_1 = require("./queries");
|
|
15
|
-
(0, node_test_1.describe)('Prometheus Query Builders', () =>
|
|
6
|
+
(0, node_test_1.describe)('Prometheus Query Builders', async () => {
|
|
16
7
|
const namespace = 'app';
|
|
17
8
|
const timeRange = '2m';
|
|
18
9
|
const apiRouteFilter = 'http_route=~"/api/.*"';
|
|
19
|
-
(0, node_test_1.describe)('getAvailabilityQuery', () =>
|
|
10
|
+
(0, node_test_1.describe)('getAvailabilityQuery', async () => {
|
|
20
11
|
(0, node_test_1.it)('should build correct query', () => {
|
|
21
12
|
const result = (0, queries_1.getAvailabilityQuery)(namespace, timeRange);
|
|
22
13
|
const expected = `(sum(rate(${namespace}_http_server_duration_milliseconds_count{http_status_code!~"5.."}[${timeRange}]))) / ` +
|
|
23
14
|
`(sum(rate(${namespace}_http_server_duration_milliseconds_count[${timeRange}]))) * 100`;
|
|
24
15
|
assert.equal(result, expected);
|
|
25
16
|
});
|
|
26
|
-
})
|
|
27
|
-
(0, node_test_1.describe)('getSuccessRateQuery', () =>
|
|
17
|
+
});
|
|
18
|
+
(0, node_test_1.describe)('getSuccessRateQuery', async () => {
|
|
28
19
|
(0, node_test_1.it)('should build correct query', () => {
|
|
29
20
|
const result = (0, queries_1.getSuccessRateQuery)(namespace, timeRange, apiRouteFilter);
|
|
30
21
|
const expected = `(sum(rate(${namespace}_http_server_duration_milliseconds_count{http_status_code=~"[2-4]..",${apiRouteFilter}}[2m]))) / ` +
|
|
31
22
|
`(sum(rate(${namespace}_http_server_duration_milliseconds_count{${apiRouteFilter}}[2m]))) * 100`;
|
|
32
23
|
assert.equal(result, expected);
|
|
33
24
|
});
|
|
34
|
-
})
|
|
35
|
-
(0, node_test_1.describe)('getPercentileLatencyQuery', () =>
|
|
25
|
+
});
|
|
26
|
+
(0, node_test_1.describe)('getPercentileLatencyQuery', async () => {
|
|
36
27
|
(0, node_test_1.it)('should build correct query', () => {
|
|
37
28
|
const percentile = 0.95;
|
|
38
29
|
const result = (0, queries_1.getPercentileLatencyQuery)(namespace, timeRange, percentile, apiRouteFilter);
|
|
39
30
|
const expected = `histogram_quantile(${percentile}, sum by(le) (rate(${namespace}_http_server_duration_milliseconds_bucket{${apiRouteFilter}}[${timeRange}])))`;
|
|
40
31
|
assert.equal(result, expected);
|
|
41
32
|
});
|
|
42
|
-
})
|
|
43
|
-
(0, node_test_1.describe)('getLatencyPercentageQuery', () =>
|
|
33
|
+
});
|
|
34
|
+
(0, node_test_1.describe)('getLatencyPercentageQuery', async () => {
|
|
44
35
|
(0, node_test_1.it)('should build correct query', () => {
|
|
45
36
|
const threshold = 200;
|
|
46
37
|
const result = (0, queries_1.getLatencyPercentageQuery)(namespace, timeRange, threshold, apiRouteFilter);
|
|
@@ -48,5 +39,5 @@ const queries_1 = require("./queries");
|
|
|
48
39
|
`(sum(rate(${namespace}_http_server_duration_milliseconds_count{${apiRouteFilter}}[2m]))) * 100`;
|
|
49
40
|
assert.equal(result, expected);
|
|
50
41
|
});
|
|
51
|
-
})
|
|
52
|
-
})
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -11,6 +11,11 @@ const defaults = {
|
|
|
11
11
|
parameterGroupName: 'default.redis7',
|
|
12
12
|
};
|
|
13
13
|
class ElastiCacheRedis extends pulumi.ComponentResource {
|
|
14
|
+
name;
|
|
15
|
+
vpc;
|
|
16
|
+
cluster;
|
|
17
|
+
securityGroup;
|
|
18
|
+
subnetGroup;
|
|
14
19
|
constructor(name, args, opts = {}) {
|
|
15
20
|
super('studion:redis:ElastiCacheRedis', name, {}, opts);
|
|
16
21
|
const argsWithDefaults = (0, merge_with_defaults_1.mergeWithDefaults)(defaults, args);
|
|
@@ -31,7 +36,7 @@ class ElastiCacheRedis extends pulumi.ComponentResource {
|
|
|
31
36
|
subnetGroupName: this.subnetGroup.name,
|
|
32
37
|
parameterGroupName: parameterGroupName,
|
|
33
38
|
port: 6379,
|
|
34
|
-
tags:
|
|
39
|
+
tags: { ...common_tags_1.commonTags, ...tags },
|
|
35
40
|
}, { parent: this });
|
|
36
41
|
}
|
|
37
42
|
createSubnetGroup() {
|
|
@@ -10,10 +10,16 @@ const defaults = {
|
|
|
10
10
|
primaryRegion: 'us-east-1',
|
|
11
11
|
};
|
|
12
12
|
class UpstashRedis extends pulumi.ComponentResource {
|
|
13
|
+
name;
|
|
14
|
+
instance;
|
|
15
|
+
password;
|
|
13
16
|
constructor(name, args, opts = {}) {
|
|
14
|
-
super('studion:redis:UpstashRedis', name, {},
|
|
17
|
+
super('studion:redis:UpstashRedis', name, {}, {
|
|
18
|
+
...opts,
|
|
19
|
+
aliases: [...(opts.aliases || []), { type: 'studion:Redis' }],
|
|
20
|
+
});
|
|
15
21
|
const dbName = `${pulumi.getProject()}-${pulumi.getStack()}`;
|
|
16
|
-
const argsWithDefaults = (0, merge_with_defaults_1.mergeWithDefaults)(
|
|
22
|
+
const argsWithDefaults = (0, merge_with_defaults_1.mergeWithDefaults)({ ...defaults, dbName }, args);
|
|
17
23
|
this.name = name;
|
|
18
24
|
this.instance = new upstash.RedisDatabase(`${this.name}-database`, {
|
|
19
25
|
databaseName: argsWithDefaults.dbName,
|
|
@@ -6,8 +6,14 @@ const cache_rule_ttl_1 = require("./cache-rule-ttl");
|
|
|
6
6
|
const s3_assets_1 = require("./s3-assets");
|
|
7
7
|
const cloudfront_1 = require("../cloudfront");
|
|
8
8
|
class StaticSite extends pulumi.ComponentResource {
|
|
9
|
+
name;
|
|
10
|
+
s3Assets;
|
|
11
|
+
cf;
|
|
9
12
|
constructor(name, args, opts = {}) {
|
|
10
|
-
super('studion:static-site:StaticSite', name, {},
|
|
13
|
+
super('studion:static-site:StaticSite', name, {}, {
|
|
14
|
+
...opts,
|
|
15
|
+
aliases: [...(opts.aliases || []), { type: 'studion:StaticSite' }],
|
|
16
|
+
});
|
|
11
17
|
const { domain, hostedZoneId, certificate, bucketPrefix, indexDocument, errorDocument, cacheRules, tags, } = args;
|
|
12
18
|
if (!domain && !certificate) {
|
|
13
19
|
throw new Error('Provide either domain or certificate, or both');
|
|
@@ -5,6 +5,9 @@ const pulumi = require("@pulumi/pulumi");
|
|
|
5
5
|
const aws = require("@pulumi/aws");
|
|
6
6
|
const common_tags_1 = require("../../shared/common-tags");
|
|
7
7
|
class S3Assets extends pulumi.ComponentResource {
|
|
8
|
+
name;
|
|
9
|
+
bucket;
|
|
10
|
+
websiteConfig;
|
|
8
11
|
constructor(name, args, opts = {}) {
|
|
9
12
|
super('studion:static-site:S3Assets', name, {}, opts);
|
|
10
13
|
this.name = name;
|
|
@@ -30,7 +33,7 @@ class S3Assets extends pulumi.ComponentResource {
|
|
|
30
33
|
createWebsiteBucket(bucketPrefix, indexDocument, errorDocument, tags) {
|
|
31
34
|
const bucket = new aws.s3.Bucket(`${this.name}-bucket`, {
|
|
32
35
|
bucketPrefix,
|
|
33
|
-
tags:
|
|
36
|
+
tags: { ...common_tags_1.commonTags, ...tags },
|
|
34
37
|
}, { parent: this });
|
|
35
38
|
const config = new aws.s3.BucketWebsiteConfiguration(`${this.name}-bucket-website-config`, {
|
|
36
39
|
bucket: bucket.id,
|
|
@@ -10,6 +10,7 @@ exports.defaults = {
|
|
|
10
10
|
numberOfAvailabilityZones: 2,
|
|
11
11
|
};
|
|
12
12
|
class Vpc extends pulumi.ComponentResource {
|
|
13
|
+
vpc;
|
|
13
14
|
constructor(name, args, opts = {}) {
|
|
14
15
|
super('studion:vpc:Vpc', name, {}, opts);
|
|
15
16
|
const argsWithDefaults = (0, merge_with_defaults_1.mergeWithDefaults)(exports.defaults, args);
|
|
@@ -26,7 +27,7 @@ class Vpc extends pulumi.ComponentResource {
|
|
|
26
27
|
{ type: awsx.ec2.SubnetType.Public, cidrMask: 24 },
|
|
27
28
|
{ type: awsx.ec2.SubnetType.Isolated, cidrMask: 24 },
|
|
28
29
|
],
|
|
29
|
-
tags:
|
|
30
|
+
tags: { ...common_tags_1.commonTags, ...argsWithDefaults.tags },
|
|
30
31
|
}, { parent: this });
|
|
31
32
|
this.registerOutputs();
|
|
32
33
|
}
|
|
@@ -4,15 +4,28 @@ exports.WebServerBuilder = void 0;
|
|
|
4
4
|
const pulumi = require("@pulumi/pulumi");
|
|
5
5
|
const _1 = require(".");
|
|
6
6
|
class WebServerBuilder {
|
|
7
|
+
_name;
|
|
8
|
+
_container;
|
|
9
|
+
_vpc;
|
|
10
|
+
_ecsConfig;
|
|
11
|
+
_domain;
|
|
12
|
+
_hostedZoneId;
|
|
13
|
+
_certificate;
|
|
14
|
+
_healthCheckPath;
|
|
15
|
+
_loadBalancingAlgorithmType;
|
|
16
|
+
_otelCollector;
|
|
17
|
+
_initContainers = [];
|
|
18
|
+
_sidecarContainers = [];
|
|
19
|
+
_volumes = [];
|
|
7
20
|
constructor(name) {
|
|
8
|
-
this._initContainers = [];
|
|
9
|
-
this._sidecarContainers = [];
|
|
10
|
-
this._volumes = [];
|
|
11
21
|
this._name = name;
|
|
12
22
|
}
|
|
13
23
|
withContainer(image, port, config = {}) {
|
|
14
|
-
this._container =
|
|
15
|
-
|
|
24
|
+
this._container = {
|
|
25
|
+
image,
|
|
26
|
+
port,
|
|
27
|
+
...config,
|
|
28
|
+
};
|
|
16
29
|
return this;
|
|
17
30
|
}
|
|
18
31
|
withEcsConfig(config) {
|
|
@@ -80,7 +93,20 @@ class WebServerBuilder {
|
|
|
80
93
|
if (!this._vpc) {
|
|
81
94
|
throw new Error('VPC not provided. Make sure to call WebServerBuilder.withVpc().');
|
|
82
95
|
}
|
|
83
|
-
return new _1.WebServer(this._name,
|
|
96
|
+
return new _1.WebServer(this._name, {
|
|
97
|
+
...this._ecsConfig,
|
|
98
|
+
...this._container,
|
|
99
|
+
vpc: this._vpc,
|
|
100
|
+
volumes: this._volumes,
|
|
101
|
+
domain: this._domain,
|
|
102
|
+
hostedZoneId: this._hostedZoneId,
|
|
103
|
+
certificate: this._certificate,
|
|
104
|
+
healthCheckPath: this._healthCheckPath,
|
|
105
|
+
loadBalancingAlgorithmType: this._loadBalancingAlgorithmType,
|
|
106
|
+
otelCollector: this._otelCollector,
|
|
107
|
+
initContainers: this._initContainers,
|
|
108
|
+
sidecarContainers: this._sidecarContainers,
|
|
109
|
+
}, opts);
|
|
84
110
|
}
|
|
85
111
|
}
|
|
86
112
|
exports.WebServerBuilder = WebServerBuilder;
|
|
@@ -8,9 +8,22 @@ const acm_certificate_1 = require("../acm-certificate");
|
|
|
8
8
|
const ecs_service_1 = require("../ecs-service");
|
|
9
9
|
const load_balancer_1 = require("./load-balancer");
|
|
10
10
|
class WebServer extends pulumi.ComponentResource {
|
|
11
|
+
name;
|
|
12
|
+
container;
|
|
13
|
+
ecsConfig;
|
|
14
|
+
service;
|
|
15
|
+
serviceSecurityGroup;
|
|
16
|
+
lb;
|
|
17
|
+
initContainers;
|
|
18
|
+
sidecarContainers;
|
|
19
|
+
volumes;
|
|
20
|
+
acmCertificate;
|
|
21
|
+
dnsRecords;
|
|
11
22
|
constructor(name, args, opts = {}) {
|
|
12
|
-
|
|
13
|
-
|
|
23
|
+
super('studion:web-server:WebServer', name, {}, {
|
|
24
|
+
...opts,
|
|
25
|
+
aliases: [...(opts.aliases || []), { type: 'studion:WebServer' }],
|
|
26
|
+
});
|
|
14
27
|
const { vpc, domain, hostedZoneId, certificate } = args;
|
|
15
28
|
const hasCustomDomain = !!domain || !!certificate;
|
|
16
29
|
if (hasCustomDomain && !hostedZoneId) {
|
|
@@ -23,12 +36,15 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
23
36
|
this.lb = new load_balancer_1.WebServerLoadBalancer(`${this.name}-lb`, {
|
|
24
37
|
vpc,
|
|
25
38
|
port: args.port,
|
|
26
|
-
certificate: certificate
|
|
39
|
+
certificate: certificate ?? this.acmCertificate?.certificate,
|
|
27
40
|
healthCheckPath: args.healthCheckPath,
|
|
28
41
|
loadBalancingAlgorithmType: args.loadBalancingAlgorithmType,
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
}, {
|
|
43
|
+
parent: this,
|
|
44
|
+
...(this.acmCertificate
|
|
45
|
+
? { dependsOn: [this.acmCertificate.certificateValidation] }
|
|
46
|
+
: undefined),
|
|
47
|
+
});
|
|
32
48
|
this.serviceSecurityGroup = this.createSecurityGroup(vpc);
|
|
33
49
|
this.initContainers = this.getInitContainers(args);
|
|
34
50
|
this.sidecarContainers = this.getSidecarContainers(args);
|
|
@@ -37,7 +53,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
37
53
|
this.volumes = this.getVolumes(args);
|
|
38
54
|
this.service = this.createEcsService(this.container, this.lb, this.ecsConfig, this.volumes, this.initContainers, this.sidecarContainers);
|
|
39
55
|
if (hasCustomDomain && hostedZoneId) {
|
|
40
|
-
this.dnsRecords = this.createDnsRecords(certificate
|
|
56
|
+
this.dnsRecords = this.createDnsRecords(certificate ?? this.acmCertificate.certificate, hostedZoneId, domain);
|
|
41
57
|
}
|
|
42
58
|
this.registerOutputs();
|
|
43
59
|
}
|
|
@@ -62,7 +78,10 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
62
78
|
containers.push(...passedInits);
|
|
63
79
|
if (otelCollector)
|
|
64
80
|
containers.push(otelCollector.configContainer);
|
|
65
|
-
return containers.map(container => (
|
|
81
|
+
return containers.map(container => ({
|
|
82
|
+
...container,
|
|
83
|
+
essential: false,
|
|
84
|
+
}));
|
|
66
85
|
});
|
|
67
86
|
}
|
|
68
87
|
getSidecarContainers(args) {
|
|
@@ -74,7 +93,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
74
93
|
containers.push(...passedSidecars);
|
|
75
94
|
if (otelCollector)
|
|
76
95
|
containers.push(otelCollector.container);
|
|
77
|
-
return containers.map(container => (
|
|
96
|
+
return containers.map(container => ({ ...container, essential: true }));
|
|
78
97
|
});
|
|
79
98
|
}
|
|
80
99
|
getTaskRoleInlinePolicies(args) {
|
|
@@ -154,19 +173,32 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
154
173
|
sidecarContainers || pulumi.output([]),
|
|
155
174
|
])
|
|
156
175
|
.apply(([inits, sidecars]) => {
|
|
157
|
-
return new ecs_service_1.EcsService(`${this.name}-ecs`,
|
|
158
|
-
|
|
176
|
+
return new ecs_service_1.EcsService(`${this.name}-ecs`, {
|
|
177
|
+
...ecsConfig,
|
|
178
|
+
volumes,
|
|
179
|
+
containers: [
|
|
180
|
+
{
|
|
181
|
+
...webServerContainer,
|
|
182
|
+
name: this.name,
|
|
183
|
+
portMappings: [
|
|
159
184
|
ecs_service_1.EcsService.createTcpPortMapping(webServerContainer.port),
|
|
160
|
-
],
|
|
185
|
+
],
|
|
186
|
+
essential: true,
|
|
187
|
+
},
|
|
161
188
|
...inits,
|
|
162
189
|
...sidecars,
|
|
163
|
-
],
|
|
190
|
+
],
|
|
191
|
+
enableServiceAutoDiscovery: false,
|
|
192
|
+
loadBalancers: [
|
|
164
193
|
{
|
|
165
194
|
containerName: this.name,
|
|
166
195
|
containerPort: webServerContainer.port,
|
|
167
196
|
targetGroupArn: lb.targetGroup.arn,
|
|
168
197
|
},
|
|
169
|
-
],
|
|
198
|
+
],
|
|
199
|
+
assignPublicIp: true,
|
|
200
|
+
securityGroup: this.serviceSecurityGroup,
|
|
201
|
+
}, {
|
|
170
202
|
parent: this,
|
|
171
203
|
dependsOn: [lb, lb.targetGroup],
|
|
172
204
|
});
|
|
@@ -176,7 +208,7 @@ class WebServer extends pulumi.ComponentResource {
|
|
|
176
208
|
const certOutput = pulumi.output(certificate);
|
|
177
209
|
return pulumi
|
|
178
210
|
.all([domain, certOutput.domainName, certOutput.subjectAlternativeNames])
|
|
179
|
-
.apply(([domain, certDomain, certSans = []]) => (domain ? [domain] : [...new Set([certDomain, ...certSans])]).map((alias, index) => new aws.route53.Record(`${this.name}-
|
|
211
|
+
.apply(([domain, certDomain, certSans = []]) => (domain ? [domain] : [...new Set([certDomain, ...certSans])]).map((alias, index) => new aws.route53.Record(`${this.name}-dns-a-record-${index}`, {
|
|
180
212
|
type: 'A',
|
|
181
213
|
name: alias,
|
|
182
214
|
zoneId: hostedZoneId,
|
|
@@ -33,6 +33,12 @@ const defaults = {
|
|
|
33
33
|
healthCheckPath: '/healthcheck',
|
|
34
34
|
};
|
|
35
35
|
class WebServerLoadBalancer extends pulumi.ComponentResource {
|
|
36
|
+
name;
|
|
37
|
+
lb;
|
|
38
|
+
targetGroup;
|
|
39
|
+
httpListener;
|
|
40
|
+
tlsListener;
|
|
41
|
+
securityGroup;
|
|
36
42
|
constructor(name, args, opts = {}) {
|
|
37
43
|
super('studion:web-server:WebServerLoadBalancer', name, {}, opts);
|
|
38
44
|
this.name = name;
|
|
@@ -47,7 +53,7 @@ class WebServerLoadBalancer extends pulumi.ComponentResource {
|
|
|
47
53
|
securityGroups: [this.securityGroup.id],
|
|
48
54
|
internal: false,
|
|
49
55
|
ipAddressType: 'ipv4',
|
|
50
|
-
tags:
|
|
56
|
+
tags: { ...common_tags_1.commonTags, Name: name },
|
|
51
57
|
}, { parent: this });
|
|
52
58
|
this.targetGroup = this.createLbTargetGroup(port, vpc.vpcId, healthCheckPath, loadBalancingAlgorithmType);
|
|
53
59
|
this.httpListener = this.createLbHttpListener(this.lb, this.targetGroup, !!certificate);
|
|
@@ -109,11 +115,15 @@ class WebServerLoadBalancer extends pulumi.ComponentResource {
|
|
|
109
115
|
timeout: 5,
|
|
110
116
|
path: healthCheckPath,
|
|
111
117
|
},
|
|
112
|
-
tags:
|
|
118
|
+
tags: { ...common_tags_1.commonTags, Name: `${this.name}-target-group` },
|
|
113
119
|
}, { parent: this, dependsOn: [this.lb] });
|
|
114
120
|
}
|
|
115
121
|
createLbSecurityGroup(vpcId) {
|
|
116
|
-
return new aws.ec2.SecurityGroup(`${this.name}-security-group`,
|
|
122
|
+
return new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
|
|
123
|
+
...webServerLoadBalancerNetworkConfig,
|
|
124
|
+
vpcId,
|
|
125
|
+
tags: common_tags_1.commonTags,
|
|
126
|
+
}, { parent: this });
|
|
117
127
|
}
|
|
118
128
|
}
|
|
119
129
|
exports.WebServerLoadBalancer = WebServerLoadBalancer;
|
package/dist/otel/builder.js
CHANGED
|
@@ -7,8 +7,11 @@ const memoryLimiterProcessor = require("./memory-limiter-processor");
|
|
|
7
7
|
const _1 = require(".");
|
|
8
8
|
const config_1 = require("./config");
|
|
9
9
|
class OtelCollectorBuilder {
|
|
10
|
+
_serviceName;
|
|
11
|
+
_env;
|
|
12
|
+
_configBuilder;
|
|
13
|
+
_taskRoleInlinePolicies = [];
|
|
10
14
|
constructor(serviceName, env) {
|
|
11
|
-
this._taskRoleInlinePolicies = [];
|
|
12
15
|
this._serviceName = pulumi.output(serviceName);
|
|
13
16
|
this._env = pulumi.output(env);
|
|
14
17
|
this._configBuilder = new config_1.OtelCollectorConfigBuilder();
|