@studion/infra-code-blocks 0.6.12 → 0.7.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/README.md CHANGED
@@ -171,6 +171,14 @@ export type WebServerServiceOptions = {
171
171
  }>;
172
172
  size?: pulumi.Input<Size>;
173
173
  healthCheckPath?: pulumi.Input<string>;
174
+ persistentStorageConfig?: pulumi.Input<{
175
+ volumes: { name: string }[];
176
+ mountPoints: {
177
+ sourceVolume: string;
178
+ containerPath: string;
179
+ readOnly?: boolean;
180
+ }[];
181
+ }>;
174
182
  taskExecutionRoleInlinePolicies?: pulumi.Input<
175
183
  pulumi.Input<RoleInlinePolicy>[]
176
184
  >;
@@ -219,6 +227,14 @@ type MongoServiceOptions = {
219
227
  password?: pulumi.Input<string>;
220
228
  port?: pulumi.Input<number>;
221
229
  size?: pulumi.Input<Size>;
230
+ persistentStorageConfig?: pulumi.Input<{
231
+ volumes: { name: string }[];
232
+ mountPoints: {
233
+ sourceVolume: string;
234
+ containerPath: string;
235
+ readOnly?: boolean;
236
+ }[];
237
+ }>;
222
238
  tags?: pulumi.Input<{
223
239
  [key: string]: pulumi.Input<string>;
224
240
  }>;
@@ -233,7 +249,14 @@ type EcsServiceOptions = {
233
249
  port: pulumi.Input<number>;
234
250
  enableServiceAutoDiscovery: pulumi.Input<boolean>;
235
251
  lbTargetGroupArn?: aws.lb.TargetGroup['arn'];
236
- persistentStorageVolumePath?: pulumi.Input<string>;
252
+ persistentStorageConfig?: pulumi.Input<{
253
+ volumes: { name: string }[];
254
+ mountPoints: {
255
+ sourceVolume: string;
256
+ containerPath: string;
257
+ readOnly?: boolean;
258
+ }[];
259
+ }>;
237
260
  securityGroup?: aws.ec2.SecurityGroup;
238
261
  assignPublicIp?: pulumi.Input<boolean>;
239
262
  dockerCommand?: pulumi.Input<string[]>;
@@ -339,6 +362,37 @@ const project = new studion.Project('demo-project', {
339
362
  });
340
363
  ```
341
364
 
365
+ ### Persistent Storage Configuration
366
+
367
+ Services that require persistent storage (e.g. `ECS`, `Mongo`) can be configured with multiple EFS volumes and mount points.
368
+ Currently, only one access point is configured, with root directory set to `/data`.
369
+ The configuration consists of two main parts:
370
+
371
+ 1. `volumes`: Define the EFS volumes to be created
372
+ 2. `mountPoints`: Specify where these volumes should be mounted in the container
373
+
374
+ Example configuration:
375
+
376
+ ```ts
377
+ persistentStorageConfig: {
378
+ volumes: [
379
+ { name: 'data-volume' },
380
+ { name: 'config-volume' }
381
+ ],
382
+ mountPoints: [
383
+ {
384
+ sourceVolume: 'data-volume',
385
+ containerPath: '/data',
386
+ },
387
+ {
388
+ sourceVolume: 'config-volume',
389
+ containerPath: '/config',
390
+ readOnly: true
391
+ }
392
+ ]
393
+ }
394
+ ```
395
+
342
396
  ### Database
343
397
 
344
398
  AWS RDS Postgres instance.
@@ -559,6 +613,14 @@ export type WebServerArgs = {
559
613
  environment?: aws.ecs.KeyValuePair[];
560
614
  secrets?: aws.ecs.Secret[];
561
615
  healthCheckPath?: pulumi.Input<string>;
616
+ persistentStorageConfig?: pulumi.Input<{
617
+ volumes: { name: string }[];
618
+ mountPoints: {
619
+ sourceVolume: string;
620
+ containerPath: string;
621
+ readOnly?: boolean;
622
+ }[];
623
+ }>;
562
624
  taskExecutionRoleInlinePolicies?: pulumi.Input<
563
625
  pulumi.Input<RoleInlinePolicy>[]
564
626
  >;
@@ -655,6 +717,14 @@ export type MongoArgs = {
655
717
  password?: pulumi.Input<string>;
656
718
  port?: pulumi.Input<number>;
657
719
  size?: pulumi.Input<Size>;
720
+ persistentStorageConfig?: pulumi.Input<{
721
+ volumes: { name: string }[];
722
+ mountPoints: {
723
+ sourceVolume: string;
724
+ containerPath: string;
725
+ readOnly?: boolean;
726
+ }[];
727
+ }>;
658
728
  tags?: pulumi.Input<{
659
729
  [key: string]: pulumi.Input<string>;
660
730
  }>;
@@ -665,6 +735,8 @@ If the password is not specified it will be autogenerated.
665
735
  The Mongo password is stored as a secret inside AWS Secret Manager.
666
736
  The secret will be available on the `Mongo` resource as `password.secret`.
667
737
 
738
+ The Mongo component comes with a default persistent storage configuration that mounts an EFS volume `mongo` to `/data/db`. You can override this by providing your own `persistentStorageConfig`.
739
+
668
740
  ### Ecs Service
669
741
 
670
742
  AWS ECS Fargate.
@@ -708,7 +780,14 @@ export type EcsServiceArgs = {
708
780
  environment?: aws.ecs.KeyValuePair[];
709
781
  secrets?: aws.ecs.Secret[];
710
782
  enableServiceAutoDiscovery: pulumi.Input<boolean>;
711
- persistentStorageVolumePath?: pulumi.Input<string>;
783
+ persistentStorageConfig?: pulumi.Input<{
784
+ volumes: { name: string }[];
785
+ mountPoints: {
786
+ sourceVolume: string;
787
+ containerPath: string;
788
+ readOnly?: boolean;
789
+ }[];
790
+ }>;
712
791
  dockerCommand?: pulumi.Input<string[]>;
713
792
  lbTargetGroupArn?: aws.lb.TargetGroup['arn'];
714
793
  securityGroup?: aws.ec2.SecurityGroup;
@@ -49,7 +49,7 @@ export type DatabaseReplicaArgs = {
49
49
  */
50
50
  parameterGroupName?: pulumi.Input<string>;
51
51
  /**
52
- * The DB engine version. Defaults to '15.5'.
52
+ * The DB engine version. Defaults to '17.2'.
53
53
  */
54
54
  engineVersion?: pulumi.Input<string>;
55
55
  /**
@@ -11,7 +11,7 @@ const defaults = {
11
11
  maxAllocatedStorage: 100,
12
12
  instanceClass: 'db.t4g.micro',
13
13
  enableMonitoring: false,
14
- engineVersion: '15.5',
14
+ engineVersion: '17.2',
15
15
  };
16
16
  class DatabaseReplica extends pulumi.ComponentResource {
17
17
  constructor(name, args, opts = {}) {
@@ -69,7 +69,7 @@ export type DatabaseArgs = {
69
69
  */
70
70
  snapshotIdentifier?: pulumi.Input<string>;
71
71
  /**
72
- * The DB engine version. Defaults to '15.5'.
72
+ * The DB engine version. Defaults to '17.2'.
73
73
  */
74
74
  engineVersion?: pulumi.Input<string>;
75
75
  /**
@@ -14,7 +14,7 @@ const defaults = {
14
14
  instanceClass: 'db.t4g.micro',
15
15
  enableMonitoring: false,
16
16
  allowMajorVersionUpgrade: false,
17
- engineVersion: '15.5',
17
+ engineVersion: '17.2',
18
18
  };
19
19
  class Database extends pulumi.ComponentResource {
20
20
  constructor(name, args, opts = {}) {
@@ -13,6 +13,18 @@ export type RoleInlinePolicy = {
13
13
  */
14
14
  policy?: pulumi.Input<string>;
15
15
  };
16
+ export type PersistentStorageMountPoint = {
17
+ sourceVolume: string;
18
+ containerPath: string;
19
+ readOnly?: boolean;
20
+ };
21
+ export type PersistentStorageVolume = {
22
+ name: string;
23
+ };
24
+ export type PersistentStorageConfig = {
25
+ volumes: PersistentStorageVolume[];
26
+ mountPoints: PersistentStorageMountPoint[];
27
+ };
16
28
  export type EcsServiceArgs = {
17
29
  /**
18
30
  * The ECR image used to start a container.
@@ -70,9 +82,10 @@ export type EcsServiceArgs = {
70
82
  */
71
83
  enableServiceAutoDiscovery: pulumi.Input<boolean>;
72
84
  /**
73
- * Location of persistent storage volume.
85
+ * Configuration for multiple EFS volumes and their mount points.
86
+ * Each mount point specifies a container path where the EFS volume will be mounted.
74
87
  */
75
- persistentStorageVolumePath?: pulumi.Input<string>;
88
+ persistentStorageConfig?: pulumi.Input<PersistentStorageConfig>;
76
89
  /**
77
90
  * Alternate docker CMD instruction.
78
91
  */
@@ -19,6 +19,18 @@ exports.assumeRolePolicy = {
19
19
  },
20
20
  ],
21
21
  };
22
+ /**
23
+ * Standard directory permissions:
24
+ * - Owner: read, write, execute (7)
25
+ * - Group: read, execute (5)
26
+ * - Others: read, execute (5)
27
+ */
28
+ const STANDARD_DIRECTORY_PERMISSIONS = '0755';
29
+ const FIRST_POSIX_NON_ROOT_USER = {
30
+ userId: 1000,
31
+ groupId: 1000,
32
+ permissions: STANDARD_DIRECTORY_PERMISSIONS
33
+ };
22
34
  const defaults = {
23
35
  desiredCount: 1,
24
36
  size: 'small',
@@ -167,6 +179,22 @@ class EcsService extends pulumi.ComponentResource {
167
179
  }
168
180
  throw Error('Incorrect EcsService size argument');
169
181
  });
182
+ const fileSystemId = this.createPersistentStorage(argsWithDefaults).id;
183
+ const accessPoint = new aws.efs.AccessPoint(`${this.name}-efs-ap`, {
184
+ fileSystemId,
185
+ posixUser: {
186
+ uid: FIRST_POSIX_NON_ROOT_USER.userId,
187
+ gid: FIRST_POSIX_NON_ROOT_USER.groupId,
188
+ },
189
+ rootDirectory: {
190
+ path: '/data',
191
+ creationInfo: {
192
+ ownerUid: FIRST_POSIX_NON_ROOT_USER.userId,
193
+ ownerGid: FIRST_POSIX_NON_ROOT_USER.groupId,
194
+ permissions: FIRST_POSIX_NON_ROOT_USER.permissions,
195
+ },
196
+ },
197
+ });
170
198
  const taskDefinition = 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: parsedSize.cpu, memory: parsedSize.memory, requiresCompatibilities: ['FARGATE'], containerDefinitions: pulumi
171
199
  .all([
172
200
  this.name,
@@ -174,25 +202,27 @@ class EcsService extends pulumi.ComponentResource {
174
202
  argsWithDefaults.port,
175
203
  argsWithDefaults.environment,
176
204
  argsWithDefaults.secrets,
177
- argsWithDefaults.persistentStorageVolumePath,
205
+ argsWithDefaults.persistentStorageConfig,
178
206
  argsWithDefaults.dockerCommand,
179
207
  this.logGroup.name,
180
208
  exports.awsRegion,
181
209
  ])
182
- .apply(([containerName, image, port, environment, secrets, persistentStorageVolumePath, command, logGroup, region,]) => {
210
+ .apply(([containerName, image, port, environment, secrets, persistentStorageConfig, command, logGroup, region,]) => {
183
211
  return JSON.stringify([
184
212
  Object.assign(Object.assign({ readonlyRootFilesystem: false, name: containerName, image, essential: true, portMappings: [
185
213
  {
186
214
  containerPort: port,
187
215
  protocol: 'tcp',
188
216
  },
189
- ] }, (persistentStorageVolumePath && {
190
- mountPoints: [
191
- {
192
- containerPath: persistentStorageVolumePath,
193
- sourceVolume: `${this.name}-volume`,
194
- },
195
- ],
217
+ ] }, (persistentStorageConfig && {
218
+ mountPoints: persistentStorageConfig.mountPoints.map(mountPoint => {
219
+ var _a;
220
+ return ({
221
+ containerPath: mountPoint.containerPath,
222
+ sourceVolume: mountPoint.sourceVolume,
223
+ readOnly: (_a = mountPoint.readOnly) !== null && _a !== void 0 ? _a : false,
224
+ });
225
+ }),
196
226
  })), { logConfiguration: {
197
227
  logDriver: 'awslogs',
198
228
  options: {
@@ -204,16 +234,20 @@ class EcsService extends pulumi.ComponentResource {
204
234
  environment,
205
235
  secrets }),
206
236
  ]);
207
- }) }, (argsWithDefaults.persistentStorageVolumePath && {
208
- volumes: [
209
- {
210
- name: `${this.name}-volume`,
211
- efsVolumeConfiguration: {
212
- fileSystemId: this.createPersistentStorage(argsWithDefaults).id,
213
- transitEncryption: 'ENABLED',
237
+ }) }, (argsWithDefaults.persistentStorageConfig && {
238
+ volumes: argsWithDefaults.persistentStorageConfig
239
+ .volumes
240
+ .map(volume => ({
241
+ name: volume.name,
242
+ efsVolumeConfiguration: {
243
+ fileSystemId,
244
+ transitEncryption: 'ENABLED',
245
+ authorizationConfig: {
246
+ accessPointId: accessPoint.id,
247
+ iam: 'ENABLED',
214
248
  },
215
- },
216
- ],
249
+ }
250
+ })),
217
251
  })), { tags: Object.assign(Object.assign({}, constants_1.commonTags), argsWithDefaults.tags) }), { parent: this });
218
252
  return taskDefinition;
219
253
  }
@@ -21,9 +21,11 @@ export type MongoArgs = Pick<EcsServiceArgs, 'size' | 'clusterId' | 'clusterName
21
21
  */
22
22
  port?: pulumi.Input<number>;
23
23
  /**
24
- * Persistent storage volume path. Defaults to '/data/db'.
24
+ * Configuration for persistent storage using EFS volumes.
25
+ * By default, creates a volume named 'mongo' mounted at '/data/db'.
26
+ * You can override this by providing your own volume and mount point configuration.
25
27
  */
26
- persistentStorageVolumePath?: pulumi.Input<string>;
28
+ persistentStorageConfig?: EcsServiceArgs['persistentStorageConfig'];
27
29
  };
28
30
  export declare class Mongo extends pulumi.ComponentResource {
29
31
  readonly name: string;
@@ -21,7 +21,13 @@ class Mongo extends pulumi.ComponentResource {
21
21
  const image = args.image ||
22
22
  'mongo:7.0.3@sha256:238b1636bdd7820c752b91bec8a669f92568eb313ad89a1fc4a92903c1b40489';
23
23
  const port = args.port || 27017;
24
- const persistentStorageVolumePath = args.persistentStorageVolumePath || '/data/db';
24
+ const persistentStorageConfig = args.persistentStorageConfig || {
25
+ volumes: [{ name: 'mongo' }],
26
+ mountPoints: [{
27
+ sourceVolume: 'mongo',
28
+ containerPath: '/data/db'
29
+ }]
30
+ };
25
31
  const { username, password, privateSubnetIds } = args, ecsServiceArgs = __rest(args, ["username", "password", "privateSubnetIds"]);
26
32
  this.name = name;
27
33
  this.host = pulumi.output(`${name}.${name}`);
@@ -29,7 +35,7 @@ class Mongo extends pulumi.ComponentResource {
29
35
  this.port = pulumi.output(port);
30
36
  this.password = new password_1.Password(`${this.name}-mongo-password`, { value: password }, { parent: this });
31
37
  this.service = new ecs_service_1.EcsService(name, Object.assign(Object.assign({}, ecsServiceArgs), { port,
32
- image, desiredCount: 1, autoscaling: { enabled: false }, enableServiceAutoDiscovery: true, persistentStorageVolumePath, dockerCommand: ['mongod', '--port', port.toString()], assignPublicIp: false, subnetIds: privateSubnetIds, environment: [
38
+ image, desiredCount: 1, autoscaling: { enabled: false }, enableServiceAutoDiscovery: true, persistentStorageConfig, dockerCommand: ['mongod', '--port', port.toString()], assignPublicIp: false, subnetIds: privateSubnetIds, environment: [
33
39
  {
34
40
  name: 'MONGO_INITDB_ROOT_USERNAME',
35
41
  value: username,
@@ -2,7 +2,7 @@ import * as pulumi from '@pulumi/pulumi';
2
2
  import * as aws from '@pulumi/aws';
3
3
  import { AcmCertificate } from './acm-certificate';
4
4
  import { EcsService, EcsServiceArgs } from './ecs-service';
5
- export type WebServerArgs = Pick<EcsServiceArgs, 'image' | 'port' | 'clusterId' | 'clusterName' | 'vpcId' | 'vpcCidrBlock' | 'desiredCount' | 'autoscaling' | 'size' | 'environment' | 'secrets' | 'taskExecutionRoleInlinePolicies' | 'taskRoleInlinePolicies' | 'tags'> & {
5
+ export type WebServerArgs = Pick<EcsServiceArgs, 'image' | 'port' | 'clusterId' | 'clusterName' | 'vpcId' | 'vpcCidrBlock' | 'desiredCount' | 'autoscaling' | 'size' | 'environment' | 'secrets' | 'persistentStorageConfig' | 'taskExecutionRoleInlinePolicies' | 'taskRoleInlinePolicies' | 'tags'> & {
6
6
  publicSubnetIds: pulumi.Input<pulumi.Input<string>[]>;
7
7
  /**
8
8
  * The domain which will be used to access the service.
package/dist/constants.js CHANGED
@@ -6,19 +6,19 @@ const CPU_1_VCPU = 1024;
6
6
  const MEMORY_1GB = 1024;
7
7
  exports.PredefinedSize = {
8
8
  small: {
9
- cpu: CPU_1_VCPU / 4,
9
+ cpu: CPU_1_VCPU / 4, // 0.25 vCPU
10
10
  memory: MEMORY_1GB / 2, // 0.5 GB memory
11
11
  },
12
12
  medium: {
13
- cpu: CPU_1_VCPU / 2,
13
+ cpu: CPU_1_VCPU / 2, // 0.5 vCPU
14
14
  memory: MEMORY_1GB, // 1 GB memory
15
15
  },
16
16
  large: {
17
- cpu: CPU_1_VCPU,
17
+ cpu: CPU_1_VCPU, // 1 vCPU
18
18
  memory: MEMORY_1GB * 2, // 2 GB memory
19
19
  },
20
20
  xlarge: {
21
- cpu: CPU_1_VCPU * 2,
21
+ cpu: CPU_1_VCPU * 2, // 2 vCPU
22
22
  memory: MEMORY_1GB * 4, // 4 GB memory
23
23
  },
24
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studion/infra-code-blocks",
3
- "version": "0.6.12",
3
+ "version": "0.7.0",
4
4
  "description": "Studion common infra components",
5
5
  "keywords": [
6
6
  "infrastructure",
@@ -32,18 +32,18 @@
32
32
  },
33
33
  "prettier": "@studion/prettier-config",
34
34
  "dependencies": {
35
- "@pulumi/aws": "^5.0.0",
36
- "@pulumi/awsx": "^1.0.0",
37
- "@pulumi/pulumi": "^3.0.0",
38
- "@pulumi/random": "^4.14.0",
39
- "@upstash/pulumi": "^0.2.0"
35
+ "@pulumi/aws": "^6.66.3",
36
+ "@pulumi/awsx": "^2.21.0",
37
+ "@pulumi/pulumi": "^3.146.0",
38
+ "@pulumi/random": "^4.17.0",
39
+ "@upstash/pulumi": "^0.3.14"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@studion/prettier-config": "^0.1.0",
43
- "@types/node": "^18",
44
- "prettier": "^3.0.3",
45
- "release-it": "^16.2.1",
46
- "typescript": "^5.2.2"
43
+ "@types/node": "^22",
44
+ "prettier": "^3.4.2",
45
+ "release-it": "^18.1.1",
46
+ "typescript": "^5.7.3"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public"