@studion/infra-code-blocks 0.6.12 → 0.8.0-next.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.
Files changed (105) hide show
  1. package/README.md +81 -2
  2. package/dist/components/acm-certificate.d.ts +1 -0
  3. package/dist/components/acm-certificate.d.ts.map +1 -0
  4. package/dist/components/database-replica.d.ts +2 -1
  5. package/dist/components/database-replica.d.ts.map +1 -0
  6. package/dist/components/database-replica.js +1 -1
  7. package/dist/components/database.d.ts +2 -1
  8. package/dist/components/database.d.ts.map +1 -0
  9. package/dist/components/database.js +1 -1
  10. package/dist/components/ec2-ssm-connect.d.ts +1 -0
  11. package/dist/components/ec2-ssm-connect.d.ts.map +1 -0
  12. package/dist/components/ecs-service.d.ts +16 -2
  13. package/dist/components/ecs-service.d.ts.map +1 -0
  14. package/dist/components/ecs-service.js +54 -19
  15. package/dist/components/mongo.d.ts +5 -2
  16. package/dist/components/mongo.d.ts.map +1 -0
  17. package/dist/components/mongo.js +8 -2
  18. package/dist/components/nuxt-ssr.d.ts +1 -0
  19. package/dist/components/nuxt-ssr.d.ts.map +1 -0
  20. package/dist/components/password.d.ts +1 -0
  21. package/dist/components/password.d.ts.map +1 -0
  22. package/dist/components/project.d.ts +1 -0
  23. package/dist/components/project.d.ts.map +1 -0
  24. package/dist/components/redis.d.ts +1 -0
  25. package/dist/components/redis.d.ts.map +1 -0
  26. package/dist/components/static-site.d.ts +1 -0
  27. package/dist/components/static-site.d.ts.map +1 -0
  28. package/dist/components/web-server.d.ts +2 -1
  29. package/dist/components/web-server.d.ts.map +1 -0
  30. package/dist/components/web-server.js +2 -1
  31. package/dist/constants.d.ts +1 -0
  32. package/dist/constants.d.ts.map +1 -0
  33. package/dist/constants.js +4 -4
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +2 -0
  37. package/dist/types/pulumi.d.ts +5 -0
  38. package/dist/types/pulumi.d.ts.map +1 -0
  39. package/dist/types/pulumi.js +2 -0
  40. package/dist/types/size.d.ts +1 -0
  41. package/dist/types/size.d.ts.map +1 -0
  42. package/dist/v2/components/ecs-service/index.d.ts +156 -0
  43. package/dist/v2/components/ecs-service/index.d.ts.map +1 -0
  44. package/dist/v2/components/ecs-service/index.js +362 -0
  45. package/dist/v2/components/ecs-service/policies.d.ts +3 -0
  46. package/dist/v2/components/ecs-service/policies.d.ts.map +1 -0
  47. package/dist/v2/components/ecs-service/policies.js +16 -0
  48. package/dist/v2/components/grafana/dashboards/index.d.ts +3 -0
  49. package/dist/v2/components/grafana/dashboards/index.d.ts.map +1 -0
  50. package/dist/v2/components/grafana/dashboards/index.js +6 -0
  51. package/dist/v2/components/grafana/dashboards/panels.d.ts +6 -0
  52. package/dist/v2/components/grafana/dashboards/panels.d.ts.map +1 -0
  53. package/dist/v2/components/grafana/dashboards/panels.js +91 -0
  54. package/dist/v2/components/grafana/dashboards/types.d.ts +66 -0
  55. package/dist/v2/components/grafana/dashboards/types.d.ts.map +1 -0
  56. package/dist/v2/components/grafana/dashboards/types.js +2 -0
  57. package/dist/v2/components/grafana/dashboards/web-server-slo.d.ts +17 -0
  58. package/dist/v2/components/grafana/dashboards/web-server-slo.d.ts.map +1 -0
  59. package/dist/v2/components/grafana/dashboards/web-server-slo.js +98 -0
  60. package/dist/v2/components/grafana/index.d.ts +2 -0
  61. package/dist/v2/components/grafana/index.d.ts.map +1 -0
  62. package/dist/v2/components/grafana/index.js +4 -0
  63. package/dist/v2/components/prometheus/index.d.ts +2 -0
  64. package/dist/v2/components/prometheus/index.d.ts.map +1 -0
  65. package/dist/v2/components/prometheus/index.js +4 -0
  66. package/dist/v2/components/prometheus/queries.d.ts +10 -0
  67. package/dist/v2/components/prometheus/queries.d.ts.map +1 -0
  68. package/dist/v2/components/prometheus/queries.js +61 -0
  69. package/dist/v2/components/prometheus/queries.test.d.ts +2 -0
  70. package/dist/v2/components/prometheus/queries.test.d.ts.map +1 -0
  71. package/dist/v2/components/prometheus/queries.test.js +52 -0
  72. package/dist/v2/components/web-server/builder.d.ts +34 -0
  73. package/dist/v2/components/web-server/builder.d.ts.map +1 -0
  74. package/dist/v2/components/web-server/builder.js +72 -0
  75. package/dist/v2/components/web-server/index.d.ts +58 -0
  76. package/dist/v2/components/web-server/index.d.ts.map +1 -0
  77. package/dist/v2/components/web-server/index.js +169 -0
  78. package/dist/v2/components/web-server/load-balancer.d.ts +25 -0
  79. package/dist/v2/components/web-server/load-balancer.d.ts.map +1 -0
  80. package/dist/v2/components/web-server/load-balancer.js +106 -0
  81. package/dist/v2/index.d.ts +13 -0
  82. package/dist/v2/index.d.ts.map +1 -0
  83. package/dist/v2/index.js +16 -0
  84. package/dist/v2/otel/batch-processor.d.ts +14 -0
  85. package/dist/v2/otel/batch-processor.d.ts.map +1 -0
  86. package/dist/v2/otel/batch-processor.js +9 -0
  87. package/dist/v2/otel/builder.d.ts +27 -0
  88. package/dist/v2/otel/builder.d.ts.map +1 -0
  89. package/dist/v2/otel/builder.js +110 -0
  90. package/dist/v2/otel/config.d.ts +26 -0
  91. package/dist/v2/otel/config.d.ts.map +1 -0
  92. package/dist/v2/otel/config.js +159 -0
  93. package/dist/v2/otel/index.d.ts +94 -0
  94. package/dist/v2/otel/index.d.ts.map +1 -0
  95. package/dist/v2/otel/index.js +82 -0
  96. package/dist/v2/otel/memory-limiter-processor.d.ts +13 -0
  97. package/dist/v2/otel/memory-limiter-processor.d.ts.map +1 -0
  98. package/dist/v2/otel/memory-limiter-processor.js +8 -0
  99. package/dist/v2/otel/otlp-receiver.d.ts +19 -0
  100. package/dist/v2/otel/otlp-receiver.d.ts.map +1 -0
  101. package/dist/v2/otel/otlp-receiver.js +11 -0
  102. package/dist/v2/otel/prometheus-remote-write-exporter.d.ts +11 -0
  103. package/dist/v2/otel/prometheus-remote-write-exporter.d.ts.map +1 -0
  104. package/dist/v2/otel/prometheus-remote-write-exporter.js +2 -0
  105. package/package.json +37 -13
@@ -0,0 +1,156 @@
1
+ import * as pulumi from '@pulumi/pulumi';
2
+ import * as aws from '@pulumi/aws';
3
+ import * as awsx from '@pulumi/awsx';
4
+ import { Size } from '../../../types/size';
5
+ type PersistentStorage = {
6
+ fileSystem: aws.efs.FileSystem;
7
+ accessPoint: aws.efs.AccessPoint;
8
+ };
9
+ export declare namespace EcsService {
10
+ /**
11
+ * Create a named volume that can be mounted into one or more containers.
12
+ * Used with Amazon EFS to enable persistent storage across:
13
+ * - Container restarts
14
+ * - Multiple containers
15
+ */
16
+ type PersistentStorageVolume = {
17
+ name: pulumi.Input<string>;
18
+ };
19
+ /**
20
+ * Specifies how an EFS volume is mounted into a container.
21
+ * `sourceVolume`: Name of the defined ECS service volume.
22
+ * `containerPath`: Path into which the volume is mounted in the container.
23
+ *
24
+ * @see {@link PersistentStorageVolume} - Required to define volumes before mounting
25
+ * @see {@link Container} - Where `mountPoints` are specified
26
+ */
27
+ type PersistentStorageMountPoint = {
28
+ sourceVolume: pulumi.Input<string>;
29
+ containerPath: pulumi.Input<string>;
30
+ readOnly?: pulumi.Input<boolean>;
31
+ };
32
+ /**
33
+ * Container configuration for the ECS task definition.
34
+ * Multiple containers can be defined to create multi-container tasks.
35
+ */
36
+ type Container = {
37
+ name: pulumi.Input<string>;
38
+ image: pulumi.Input<string>;
39
+ portMappings?: pulumi.Input<pulumi.Input<aws.ecs.PortMapping>[]>;
40
+ command?: pulumi.Input<pulumi.Input<string>[]>;
41
+ mountPoints?: PersistentStorageMountPoint[];
42
+ environment?: pulumi.Input<aws.ecs.KeyValuePair[]>;
43
+ secrets?: pulumi.Input<aws.ecs.Secret[]>;
44
+ dependsOn?: pulumi.Input<aws.ecs.ContainerDependency[]>;
45
+ /**
46
+ * If `false`, task can continue running if this container fails.
47
+ * Should be `false` for containers that execute and then tear down.
48
+ *
49
+ * Examples: Database migration, or configuration containers
50
+ *
51
+ * All containers not marked as `false` will be essential by default.
52
+ */
53
+ essential?: pulumi.Input<boolean>;
54
+ healthCheck?: pulumi.Input<aws.ecs.HealthCheck>;
55
+ };
56
+ type Tags = {
57
+ [key: string]: pulumi.Input<string>;
58
+ };
59
+ type LoadBalancerConfig = {
60
+ containerName: pulumi.Input<string>;
61
+ containerPort: pulumi.Input<number>;
62
+ targetGroupArn: aws.lb.TargetGroup['arn'];
63
+ };
64
+ type RoleInlinePolicy = aws.types.input.iam.RoleInlinePolicy;
65
+ type Args = {
66
+ cluster: pulumi.Input<aws.ecs.Cluster>;
67
+ vpc: pulumi.Input<awsx.ec2.Vpc>;
68
+ containers: EcsService.Container[];
69
+ loadBalancers?: pulumi.Input<LoadBalancerConfig[]>;
70
+ volumes?: pulumi.Input<pulumi.Input<EcsService.PersistentStorageVolume>[]>;
71
+ /**
72
+ * Number of instances of the task definition to place and keep running.
73
+ * @default 1
74
+ */
75
+ desiredCount?: pulumi.Input<number>;
76
+ /**
77
+ * CPU and memory size used for running the container.
78
+ * Available predefined options are:
79
+ * - `small` (0.25 vCPU, 0.5 GB memory)
80
+ * - `medium` (0.5 vCPU, 1 GB memory)
81
+ * - `large` (1 vCPU memory, 2 GB memory)
82
+ * - `xlarge` (2 vCPU, 4 GB memory)
83
+ *
84
+ * @default "small"
85
+ */
86
+ size?: pulumi.Input<Size>;
87
+ /**
88
+ * Custom service security group
89
+ * In case no security group is provided, default security group will be automatically created.
90
+ */
91
+ securityGroup?: pulumi.Input<aws.ec2.SecurityGroup>;
92
+ assignPublicIp?: pulumi.Input<boolean>;
93
+ taskExecutionRoleInlinePolicies?: pulumi.Input<pulumi.Input<RoleInlinePolicy>[]>;
94
+ taskRoleInlinePolicies?: pulumi.Input<pulumi.Input<RoleInlinePolicy>[]>;
95
+ /**
96
+ * Registers tasks with AWS Cloud Map and creates discoverable DNS entries for each task.
97
+ * Simplifies service-to-service communication by enabling service finding based on DNS records such as `http://serviceName.local`.
98
+ *
99
+ * @default false
100
+ */
101
+ enableServiceAutoDiscovery?: pulumi.Input<boolean>;
102
+ autoscaling?: pulumi.Input<{
103
+ /**
104
+ * Is autoscaling enabled or disabled.
105
+ *
106
+ * @default false
107
+ */
108
+ enabled: pulumi.Input<boolean>;
109
+ /**
110
+ * Min capacity of the scalable target.
111
+ *
112
+ * @default 1
113
+ */
114
+ minCount?: pulumi.Input<number>;
115
+ /**
116
+ * Max capacity of the scalable target.
117
+ *
118
+ * @default 1
119
+ */
120
+ maxCount?: pulumi.Input<number>;
121
+ }>;
122
+ /**
123
+ * A map of tags to assign to the resource.
124
+ */
125
+ tags?: pulumi.Input<EcsService.Tags>;
126
+ };
127
+ }
128
+ export declare class EcsService extends pulumi.ComponentResource {
129
+ name: string;
130
+ vpc: pulumi.Output<awsx.ec2.Vpc>;
131
+ logGroup: aws.cloudwatch.LogGroup;
132
+ taskDefinition: pulumi.Output<aws.ecs.TaskDefinition>;
133
+ taskExecutionRole: aws.iam.Role;
134
+ taskRole: aws.iam.Role;
135
+ service: aws.ecs.Service;
136
+ securityGroups: pulumi.Output<aws.ec2.SecurityGroup>[];
137
+ serviceDiscoveryService?: aws.servicediscovery.Service;
138
+ persistentStorage?: PersistentStorage;
139
+ constructor(name: string, args: EcsService.Args, opts?: pulumi.ComponentResourceOptions);
140
+ static createTcpPortMapping(port: pulumi.Input<number>): aws.ecs.PortMapping;
141
+ private createLogGroup;
142
+ private createTaskDefinition;
143
+ private createTaskDefinitionVolumes;
144
+ private createContainerDefinition;
145
+ private createTaskExecutionRole;
146
+ private createTaskRole;
147
+ addSecurityGroup(securityGroup: pulumi.Output<aws.ec2.SecurityGroup>): void;
148
+ private createDefaultSecurityGroup;
149
+ private createEcsService;
150
+ private createServiceDiscovery;
151
+ private createPrivateDnsNameSpace;
152
+ private enableAutoscaling;
153
+ private createPersistentStorage;
154
+ }
155
+ export {};
156
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/ecs-service/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EcsService = void 0;
4
+ const pulumi = require("@pulumi/pulumi");
5
+ const aws = require("@pulumi/aws");
6
+ const constants_1 = require("../../../constants");
7
+ const policies_1 = require("./policies");
8
+ const config = new pulumi.Config('aws');
9
+ const awsRegion = config.require('region');
10
+ /**
11
+ * Standard directory permissions:
12
+ * - Owner: read, write, execute (7)
13
+ * - Group: read, execute (5)
14
+ * - Others: read, execute (5)
15
+ */
16
+ const STANDARD_DIRECTORY_PERMISSIONS = '0755';
17
+ const FIRST_POSIX_NON_ROOT_USER = {
18
+ userId: 1000,
19
+ groupId: 1000,
20
+ permissions: STANDARD_DIRECTORY_PERMISSIONS
21
+ };
22
+ const defaults = {
23
+ desiredCount: 1,
24
+ size: 'small',
25
+ environment: [],
26
+ secrets: [],
27
+ volumes: [],
28
+ enableServiceAutoDiscovery: false,
29
+ assignPublicIp: false,
30
+ taskExecutionRoleInlinePolicies: [],
31
+ taskRoleInlinePolicies: [],
32
+ autoscaling: {
33
+ enabled: false,
34
+ minCount: 1,
35
+ maxCount: 1,
36
+ },
37
+ };
38
+ class EcsService extends pulumi.ComponentResource {
39
+ constructor(name, args, opts = {}) {
40
+ super('studion:ecs:Service', name, {}, opts);
41
+ const argsWithDefaults = Object.assign({}, defaults, args);
42
+ const taskExecutionRoleInlinePolicies = pulumi.output(args.taskExecutionRoleInlinePolicies || defaults.taskExecutionRoleInlinePolicies);
43
+ const taskRoleInlinePolicies = pulumi.output(args.taskRoleInlinePolicies || defaults.taskRoleInlinePolicies);
44
+ this.name = name;
45
+ this.securityGroups = [];
46
+ this.vpc = pulumi.output(argsWithDefaults.vpc);
47
+ this.logGroup = this.createLogGroup();
48
+ this.taskExecutionRole = this.createTaskExecutionRole(taskExecutionRoleInlinePolicies);
49
+ this.taskRole = this.createTaskRole(taskRoleInlinePolicies);
50
+ if (argsWithDefaults.volumes.length) {
51
+ this.persistentStorage = this.createPersistentStorage(this.vpc);
52
+ }
53
+ this.taskDefinition = this.createTaskDefinition(argsWithDefaults.containers, pulumi.output(argsWithDefaults.volumes), this.taskExecutionRole, this.taskRole, argsWithDefaults.size, Object.assign(Object.assign({}, constants_1.commonTags), argsWithDefaults.tags));
54
+ if (argsWithDefaults.enableServiceAutoDiscovery) {
55
+ this.serviceDiscoveryService = this.createServiceDiscovery();
56
+ }
57
+ this.service = this.createEcsService(argsWithDefaults);
58
+ if (argsWithDefaults.autoscaling.enabled) {
59
+ this.enableAutoscaling(pulumi.output(argsWithDefaults.cluster).name, this.service.name, argsWithDefaults.autoscaling.minCount, argsWithDefaults.autoscaling.maxCount);
60
+ }
61
+ this.registerOutputs();
62
+ }
63
+ static createTcpPortMapping(port) {
64
+ return {
65
+ containerPort: port,
66
+ hostPort: port,
67
+ protocol: 'tcp'
68
+ };
69
+ }
70
+ createLogGroup() {
71
+ const logGroup = new aws.cloudwatch.LogGroup(`${this.name}-log-group`, {
72
+ retentionInDays: 14,
73
+ namePrefix: `/ecs/${this.name}-`,
74
+ tags: constants_1.commonTags,
75
+ }, { parent: this });
76
+ return logGroup;
77
+ }
78
+ createTaskDefinition(containers, volumes, taskExecutionRole, taskRole, size, tags) {
79
+ const stack = pulumi.getStack();
80
+ const { cpu, memory } = pulumi.output(size).apply(parseSize);
81
+ const containerDefinitions = containers.map(container => {
82
+ return this.createContainerDefinition(container);
83
+ });
84
+ const taskDefinitionVolumes = this.createTaskDefinitionVolumes(volumes);
85
+ return pulumi.all(containerDefinitions).apply(containerDefinitions => {
86
+ return taskDefinitionVolumes.apply(volumes => {
87
+ return new aws.ecs.TaskDefinition(`${this.name}-task-definition`, Object.assign(Object.assign({ family: `${this.name}-task-definition-${stack}`, networkMode: 'awsvpc', executionRoleArn: taskExecutionRole.arn, taskRoleArn: taskRole.arn, cpu,
88
+ memory, requiresCompatibilities: ['FARGATE'], containerDefinitions: JSON.stringify(containerDefinitions) }, ((volumes === null || volumes === void 0 ? void 0 : volumes.length) ? { volumes } : {})), { tags: Object.assign(Object.assign({}, constants_1.commonTags), tags) }), { parent: this });
89
+ });
90
+ });
91
+ }
92
+ createTaskDefinitionVolumes(volumes) {
93
+ return volumes.apply(volumes => {
94
+ if (!volumes.length || !this.persistentStorage)
95
+ return;
96
+ return volumes.map(volume => ({
97
+ name: pulumi.output(volume).name,
98
+ efsVolumeConfiguration: {
99
+ fileSystemId: this.persistentStorage.fileSystem.id,
100
+ transitEncryption: 'ENABLED',
101
+ authorizationConfig: {
102
+ accessPointId: this.persistentStorage.accessPoint.id,
103
+ iam: 'ENABLED',
104
+ },
105
+ }
106
+ }));
107
+ });
108
+ }
109
+ createContainerDefinition(container) {
110
+ return this.logGroup.name.apply(logGroupName => (Object.assign(Object.assign(Object.assign(Object.assign({}, container), { readonlyRootFilesystem: false }), container.mountPoints && {
111
+ mountPoints: container.mountPoints.map(mountPoint => pulumi.all([
112
+ mountPoint.sourceVolume,
113
+ mountPoint.containerPath,
114
+ mountPoint.readOnly
115
+ ]).apply(([sourceVolume, containerPath, readOnly]) => ({
116
+ containerPath,
117
+ sourceVolume,
118
+ readOnly: readOnly !== null && readOnly !== void 0 ? readOnly : false,
119
+ })))
120
+ }), { logConfiguration: {
121
+ logDriver: 'awslogs',
122
+ options: {
123
+ 'awslogs-group': logGroupName,
124
+ 'awslogs-region': awsRegion,
125
+ 'awslogs-stream-prefix': 'ecs',
126
+ },
127
+ } })));
128
+ }
129
+ createTaskExecutionRole(inlinePolicies) {
130
+ const secretManagerSecretsInlinePolicy = {
131
+ name: `${this.name}-secret-manager-access`,
132
+ policy: JSON.stringify({
133
+ Version: '2012-10-17',
134
+ Statement: [
135
+ {
136
+ Sid: 'AllowContainerToGetSecretManagerSecrets',
137
+ Effect: 'Allow',
138
+ Action: ['ssm:GetParameters', 'secretsmanager:GetSecretValue'],
139
+ Resource: '*',
140
+ },
141
+ ],
142
+ }),
143
+ };
144
+ const taskExecutionRole = new aws.iam.Role(`${this.name}-task-exec-role`, {
145
+ namePrefix: `${this.name}-task-exec-role-`,
146
+ assumeRolePolicy: policies_1.assumeRolePolicy,
147
+ managedPolicyArns: [
148
+ 'arn:aws:iam::aws:policy/CloudWatchFullAccess',
149
+ 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess',
150
+ ],
151
+ inlinePolicies: inlinePolicies.apply(policies => [
152
+ secretManagerSecretsInlinePolicy,
153
+ ...policies,
154
+ ]),
155
+ tags: constants_1.commonTags,
156
+ }, { parent: this });
157
+ return taskExecutionRole;
158
+ }
159
+ createTaskRole(inlinePolicies) {
160
+ const execCmdInlinePolicy = {
161
+ name: `${this.name}-exec`,
162
+ policy: JSON.stringify({
163
+ Version: '2012-10-17',
164
+ Statement: [
165
+ {
166
+ Sid: 'AllowContainerToCreateECSExecSSMChannel',
167
+ Effect: 'Allow',
168
+ Action: [
169
+ 'ssmmessages:CreateControlChannel',
170
+ 'ssmmessages:CreateDataChannel',
171
+ 'ssmmessages:OpenControlChannel',
172
+ 'ssmmessages:OpenDataChannel',
173
+ ],
174
+ Resource: '*',
175
+ },
176
+ ],
177
+ }),
178
+ };
179
+ return new aws.iam.Role(`${this.name}-task-role`, {
180
+ namePrefix: `${this.name}-task-role-`,
181
+ assumeRolePolicy: policies_1.assumeRolePolicy,
182
+ inlinePolicies: inlinePolicies.apply(policies => [
183
+ execCmdInlinePolicy,
184
+ ...policies,
185
+ ]),
186
+ tags: constants_1.commonTags,
187
+ }, { parent: this });
188
+ }
189
+ addSecurityGroup(securityGroup) {
190
+ this.securityGroups.push(securityGroup);
191
+ }
192
+ createDefaultSecurityGroup() {
193
+ const securityGroup = pulumi.all([
194
+ this.vpc,
195
+ this.vpc.vpcId,
196
+ this.vpc.vpc.cidrBlock
197
+ ]).apply(([vpc, vpcId, cidrBlock]) => {
198
+ return new aws.ec2.SecurityGroup(`${this.name}-service-security-group`, {
199
+ vpcId,
200
+ ingress: [
201
+ {
202
+ fromPort: 0,
203
+ toPort: 0,
204
+ protocol: '-1',
205
+ cidrBlocks: [cidrBlock],
206
+ },
207
+ ],
208
+ egress: [
209
+ {
210
+ fromPort: 0,
211
+ toPort: 0,
212
+ protocol: '-1',
213
+ cidrBlocks: ['0.0.0.0/0'],
214
+ },
215
+ ],
216
+ tags: constants_1.commonTags,
217
+ }, { parent: this, dependsOn: [vpc] });
218
+ });
219
+ this.addSecurityGroup(securityGroup);
220
+ }
221
+ createEcsService(ecsServiceArgs) {
222
+ if (!this.securityGroups.length)
223
+ this.createDefaultSecurityGroup();
224
+ const networkConfiguration = {
225
+ assignPublicIp: ecsServiceArgs.assignPublicIp,
226
+ subnets: ecsServiceArgs.assignPublicIp ? this.vpc.publicSubnetIds : this.vpc.privateSubnetIds,
227
+ securityGroups: pulumi
228
+ .all(this.securityGroups)
229
+ .apply(groups => groups.map(it => it.id)),
230
+ };
231
+ return new aws.ecs.Service(`${this.name}-service`, Object.assign(Object.assign(Object.assign({ name: this.name, cluster: pulumi.output(ecsServiceArgs.cluster).id, launchType: 'FARGATE', desiredCount: ecsServiceArgs.desiredCount, taskDefinition: this.taskDefinition.arn, enableExecuteCommand: true, networkConfiguration }, ecsServiceArgs.loadBalancers && { loadBalancers: ecsServiceArgs.loadBalancers }), this.serviceDiscoveryService && {
232
+ serviceRegistries: {
233
+ registryArn: this.serviceDiscoveryService.arn,
234
+ },
235
+ }), { tags: Object.assign(Object.assign({}, constants_1.commonTags), ecsServiceArgs.tags) }), { parent: this, });
236
+ }
237
+ createServiceDiscovery() {
238
+ const privateDnsNamespace = this.createPrivateDnsNameSpace();
239
+ return new aws.servicediscovery.Service(`${this.name}-service-discovery`, {
240
+ name: this.name,
241
+ dnsConfig: {
242
+ namespaceId: privateDnsNamespace.id,
243
+ dnsRecords: [
244
+ {
245
+ ttl: 10,
246
+ type: 'A',
247
+ },
248
+ ],
249
+ routingPolicy: 'MULTIVALUE',
250
+ },
251
+ tags: constants_1.commonTags,
252
+ }, { parent: this });
253
+ }
254
+ createPrivateDnsNameSpace() {
255
+ return new aws.servicediscovery.PrivateDnsNamespace(`${this.name}-private-dns-namespace`, {
256
+ vpc: this.vpc.vpcId,
257
+ name: this.name,
258
+ tags: constants_1.commonTags,
259
+ }, { parent: this });
260
+ }
261
+ enableAutoscaling(clusterName, serviceName, minCount, maxCount) {
262
+ const autoscalingTarget = new aws.appautoscaling.Target(`${this.name}-autoscale-target`, {
263
+ minCapacity: minCount,
264
+ maxCapacity: maxCount,
265
+ resourceId: pulumi.interpolate `service/${clusterName}/${serviceName}`,
266
+ serviceNamespace: 'ecs',
267
+ scalableDimension: 'ecs:service:DesiredCount',
268
+ tags: constants_1.commonTags,
269
+ }, { parent: this });
270
+ const memoryAutoscalingPolicy = new aws.appautoscaling.Policy(`${this.name}-memory-autoscale-policy`, {
271
+ policyType: 'TargetTrackingScaling',
272
+ resourceId: autoscalingTarget.resourceId,
273
+ scalableDimension: autoscalingTarget.scalableDimension,
274
+ serviceNamespace: autoscalingTarget.serviceNamespace,
275
+ targetTrackingScalingPolicyConfiguration: {
276
+ predefinedMetricSpecification: {
277
+ predefinedMetricType: 'ECSServiceAverageMemoryUtilization',
278
+ },
279
+ targetValue: 70,
280
+ },
281
+ }, { parent: this });
282
+ const cpuAutoscalingPolicy = new aws.appautoscaling.Policy(`${this.name}-cpu-autoscale-policy`, {
283
+ policyType: 'TargetTrackingScaling',
284
+ resourceId: autoscalingTarget.resourceId,
285
+ scalableDimension: autoscalingTarget.scalableDimension,
286
+ serviceNamespace: autoscalingTarget.serviceNamespace,
287
+ targetTrackingScalingPolicyConfiguration: {
288
+ predefinedMetricSpecification: {
289
+ predefinedMetricType: 'ECSServiceAverageCPUUtilization',
290
+ },
291
+ targetValue: 70,
292
+ },
293
+ }, { parent: this });
294
+ }
295
+ createPersistentStorage(vpc) {
296
+ const efs = new aws.efs.FileSystem(`${this.name}-efs`, {
297
+ encrypted: true,
298
+ lifecyclePolicies: [
299
+ {
300
+ transitionToPrimaryStorageClass: 'AFTER_1_ACCESS',
301
+ },
302
+ {
303
+ transitionToIa: 'AFTER_7_DAYS',
304
+ },
305
+ ],
306
+ performanceMode: 'generalPurpose',
307
+ throughputMode: 'bursting',
308
+ tags: Object.assign(Object.assign({}, constants_1.commonTags), { Name: `${this.name}-data` }),
309
+ }, { parent: this });
310
+ const securityGroup = new aws.ec2.SecurityGroup(`${this.name}-persistent-storage-security-group`, {
311
+ vpcId: vpc.vpcId,
312
+ ingress: [
313
+ {
314
+ fromPort: 2049,
315
+ toPort: 2049,
316
+ protocol: 'tcp',
317
+ cidrBlocks: [vpc.vpc.cidrBlock],
318
+ },
319
+ ],
320
+ tags: constants_1.commonTags,
321
+ }, { parent: this });
322
+ this.vpc.privateSubnetIds.apply((subnetIds) => {
323
+ subnetIds.forEach(subnetId => {
324
+ const mountTarget = new aws.efs.MountTarget(`${this.name}-mount-target-${subnetId}`, {
325
+ fileSystemId: efs.id,
326
+ subnetId,
327
+ securityGroups: [securityGroup.id],
328
+ }, { parent: this });
329
+ });
330
+ });
331
+ const accessPoint = new aws.efs.AccessPoint(`${this.name}-efs-ap`, {
332
+ fileSystemId: efs.id,
333
+ posixUser: {
334
+ uid: FIRST_POSIX_NON_ROOT_USER.userId,
335
+ gid: FIRST_POSIX_NON_ROOT_USER.groupId,
336
+ },
337
+ rootDirectory: {
338
+ path: '/data',
339
+ creationInfo: {
340
+ ownerUid: FIRST_POSIX_NON_ROOT_USER.userId,
341
+ ownerGid: FIRST_POSIX_NON_ROOT_USER.groupId,
342
+ permissions: FIRST_POSIX_NON_ROOT_USER.permissions,
343
+ },
344
+ },
345
+ });
346
+ return { fileSystem: efs, accessPoint };
347
+ }
348
+ }
349
+ exports.EcsService = EcsService;
350
+ function parseSize(size) {
351
+ const mapCapabilities = ({ cpu, memory }) => ({
352
+ cpu: String(cpu),
353
+ memory: String(memory),
354
+ });
355
+ if (typeof size === 'string') {
356
+ return mapCapabilities(constants_1.PredefinedSize[size]);
357
+ }
358
+ if (typeof size === 'object') {
359
+ return mapCapabilities(size);
360
+ }
361
+ throw Error('Incorrect EcsService size argument');
362
+ }
@@ -0,0 +1,3 @@
1
+ import * as aws from '@pulumi/aws';
2
+ export declare const assumeRolePolicy: aws.iam.PolicyDocument;
3
+ //# sourceMappingURL=policies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/ecs-service/policies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AAEnC,eAAO,MAAM,gBAAgB,EAAE,GAAG,CAAC,GAAG,CAAC,cAYtC,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assumeRolePolicy = void 0;
4
+ exports.assumeRolePolicy = {
5
+ Version: '2012-10-17',
6
+ Statement: [
7
+ {
8
+ Action: 'sts:AssumeRole',
9
+ Principal: {
10
+ Service: 'ecs-tasks.amazonaws.com',
11
+ },
12
+ Effect: 'Allow',
13
+ Sid: '',
14
+ },
15
+ ],
16
+ };
@@ -0,0 +1,3 @@
1
+ export { default as WebServerSloDashboardBuilder } from "./web-server-slo";
2
+ export * as panel from './panels';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/v2/components/grafana/dashboards/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,KAAK,KAAK,MAAM,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.panel = exports.WebServerSloDashboardBuilder = void 0;
4
+ var web_server_slo_1 = require("./web-server-slo");
5
+ Object.defineProperty(exports, "WebServerSloDashboardBuilder", { enumerable: true, get: function () { return web_server_slo_1.default; } });
6
+ exports.panel = require("./panels");
@@ -0,0 +1,6 @@
1
+ import { Grafana } from './types';
2
+ export declare function createStatPercentagePanel(title: string, position: Grafana.Panel.Position, dataSource: string, metric: Grafana.Metric): Grafana.Panel;
3
+ export declare function createTimeSeriesPercentagePanel(title: string, position: Grafana.Panel.Position, dataSource: string, metric: Grafana.Metric): Grafana.Panel;
4
+ export declare function createTimeSeriesPanel(title: string, position: Grafana.Panel.Position, dataSource: string, metric: Grafana.Metric, unit?: string, min?: number, max?: number): Grafana.Panel;
5
+ export declare function createBurnRatePanel(title: string, position: Grafana.Panel.Position, dataSource: string, metric: Grafana.Metric): Grafana.Panel;
6
+ //# sourceMappingURL=panels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panels.d.ts","sourceRoot":"","sources":["../../../../../src/v2/components/grafana/dashboards/panels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQlC,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAChC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,MAAM,GACrB,OAAO,CAAC,KAAK,CAsBf;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAChC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,MAAM,GACrB,OAAO,CAAC,KAAK,CAUf;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAChC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,MAAM,EACtB,IAAI,CAAC,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,CAwBf;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,QAAQ,EAChC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,MAAM,GACrB,OAAO,CAAC,KAAK,CAkCf"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStatPercentagePanel = createStatPercentagePanel;
4
+ exports.createTimeSeriesPercentagePanel = createTimeSeriesPercentagePanel;
5
+ exports.createTimeSeriesPanel = createTimeSeriesPanel;
6
+ exports.createBurnRatePanel = createBurnRatePanel;
7
+ const percentageFieldConfig = {
8
+ unit: 'percent',
9
+ min: 0,
10
+ max: 100
11
+ };
12
+ function createStatPercentagePanel(title, position, dataSource, metric) {
13
+ return {
14
+ title,
15
+ gridPos: position,
16
+ type: 'stat',
17
+ datasource: dataSource,
18
+ targets: [{
19
+ expr: metric.query,
20
+ legendFormat: metric.label
21
+ }],
22
+ fieldConfig: {
23
+ defaults: Object.assign(Object.assign({}, percentageFieldConfig), (metric.thresholds ? {
24
+ thresholds: {
25
+ mode: 'absolute',
26
+ steps: metric.thresholds
27
+ }
28
+ } : {}))
29
+ }
30
+ };
31
+ }
32
+ function createTimeSeriesPercentagePanel(title, position, dataSource, metric) {
33
+ return createTimeSeriesPanel(title, position, dataSource, metric, percentageFieldConfig.unit, percentageFieldConfig.min, percentageFieldConfig.max);
34
+ }
35
+ function createTimeSeriesPanel(title, position, dataSource, metric, unit, min, max) {
36
+ return {
37
+ title,
38
+ type: 'timeseries',
39
+ datasource: dataSource,
40
+ gridPos: position,
41
+ targets: [{
42
+ expr: metric.query,
43
+ legendFormat: metric.label
44
+ }],
45
+ fieldConfig: {
46
+ defaults: Object.assign({ unit,
47
+ min,
48
+ max }, (metric.thresholds ? {
49
+ thresholds: {
50
+ mode: 'absolute',
51
+ steps: metric.thresholds
52
+ }
53
+ } : {}))
54
+ }
55
+ };
56
+ }
57
+ function createBurnRatePanel(title, position, dataSource, metric) {
58
+ return {
59
+ type: 'stat',
60
+ title,
61
+ gridPos: position,
62
+ datasource: dataSource,
63
+ targets: [{
64
+ expr: metric.query,
65
+ legendFormat: metric.label
66
+ }],
67
+ options: {
68
+ reduceOptions: {
69
+ calcs: ['last'],
70
+ fields: '',
71
+ values: false
72
+ },
73
+ colorMode: 'value',
74
+ graphMode: 'none',
75
+ textMode: 'value'
76
+ },
77
+ fieldConfig: {
78
+ defaults: {
79
+ unit: 'none',
80
+ thresholds: {
81
+ mode: 'absolute',
82
+ steps: [
83
+ { color: 'green', value: null },
84
+ { color: 'orange', value: 1 },
85
+ { color: 'red', value: 2 }
86
+ ]
87
+ }
88
+ }
89
+ },
90
+ };
91
+ }