Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

Commit

Permalink
efs: Amazon EFS component
Browse files Browse the repository at this point in the history
  • Loading branch information
fwang committed Oct 18, 2024
1 parent db7eee8 commit 0d80976
Show file tree
Hide file tree
Showing 18 changed files with 630 additions and 8 deletions.
3 changes: 3 additions & 0 deletions examples/aws-efs/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

# sst
.sst
10 changes: 10 additions & 0 deletions examples/aws-efs/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM node:18-bullseye-slim
WORKDIR /app/

COPY package.json /app
RUN npm install

COPY service.mjs /app
COPY common.mjs /app

ENTRYPOINT ["node", "service.mjs"]
20 changes: 20 additions & 0 deletions examples/aws-efs/common.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { readFile, writeFile } from "fs/promises";

export async function increment() {
// read the counter file from EFS
let oldValue = 0;
try {
oldValue = parseInt(await readFile("/mnt/efs/counter", "utf8"));
oldValue = isNaN(oldValue) ? 0 : oldValue;
} catch (e) {
// file doesn't exist
}

// increment the counter
const newValue = oldValue + 1;

// write the counter file to EFS
await writeFile("/mnt/efs/counter", newValue.toString());

return newValue;
}
12 changes: 12 additions & 0 deletions examples/aws-efs/lambda.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { increment } from "./common.mjs";

export const handler = async () => {
const counter = await increment();
console.log("COUNTER", counter);
return {
statusCode: 200,
body: JSON.stringify({
counter,
}),
};
};
12 changes: 12 additions & 0 deletions examples/aws-efs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "aws-efs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.19.2"
}
}
18 changes: 18 additions & 0 deletions examples/aws-efs/service.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import express from "express";
import { increment } from "./common.mjs";

const PORT = 80;

const app = express();

app.get("/", async (req, res) => {
res.send(
JSON.stringify({
counter: await increment(),
})
);
});

app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
22 changes: 22 additions & 0 deletions examples/aws-efs/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
import "sst"
export {}
declare module "sst" {
export interface Resource {
"MyFunction": {
"name": string
"type": "sst.aws.Function"
"url": string
}
"MyService": {
"service": string
"type": "sst.aws.Service"
"url": string
}
"MyVpc": {
"type": "sst.aws.Vpc"
}
}
}
43 changes: 43 additions & 0 deletions examples/aws-efs/sst.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/// <reference path="./.sst/platform/config.d.ts" />

export default $config({
app(input) {
return {
name: "aws-efs",
removal: input?.stage === "production" ? "retain" : "remove",
home: "aws",
};
},
async run() {
// NAT Gateways are required for Lambda functions
const vpc = new sst.aws.Vpc("MyVpc", { nat: "managed" });

// Create an EFS file system to store a counter
const efs = new sst.aws.Efs("MyEfs", { vpc });

// Create a Lambda function that increments the counter
new sst.aws.Function("MyFunction", {
handler: "lambda.handler",
url: true,
vpc,
volume: {
efs,
path: "/mnt/efs",
},
});

// Create a service that increments the same counter
const cluster = new sst.aws.Cluster("MyCluster", { vpc });
cluster.addService("MyService", {
public: {
ports: [{ listen: "80/http" }],
},
volumes: [
{
efs,
path: "/mnt/efs",
},
],
});
},
});
27 changes: 27 additions & 0 deletions examples/internal/playground/functions/efs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { stat, readFile, writeFile } from "fs/promises";

export const handler = async () => {
const dir = await stat("/mnt/efs");
console.log("DIR STAT", dir);
if (!dir.isDirectory()) {
return {
statusCode: 500,
body: "/mnt/efs not mounted",
};
}

let value;
try {
const content = await readFile("/mnt/efs/counter", "utf8");
value = parseInt(content) + 1;
} catch (e) {
console.log("READ ERROR", e);
value = 1;
}
await writeFile("/mnt/efs/counter", value.toString());

return {
statusCode: 200,
body: value.toString(),
};
};
20 changes: 18 additions & 2 deletions examples/internal/playground/sst.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default $config({

const vpc = addVpc();
const bucket = addBucket();
//const efs = addEfs();
//const email = addEmail();
//const apiv1 = addApiV1();
//const apiv2 = addApiV2();
Expand All @@ -33,6 +34,22 @@ export default $config({
return bucket;
}

function addEfs() {
const efs = new sst.aws.Efs("MyEfs", { vpc });
ret.efs = efs.id;
ret.efsAccessPoint = efs.nodes.accessPoint.id;

const app = new sst.aws.Function("MyEfsApp", {
handler: "functions/efs/index.handler",
volume: { efs },
url: true,
vpc,
});
ret.efsApp = app.url;

return efs;
}

function addEmail() {
const topic = new sst.aws.SnsTopic("MyTopic");
topic.subscribe("functions/email/index.notification");
Expand Down Expand Up @@ -114,7 +131,6 @@ export default $config({
link: [bucket],
});
ret.service = service.url;

return service;
}

Expand All @@ -123,7 +139,7 @@ export default $config({
vpc,
});
ret.pgHost = postgres.host;
ret.pgPort = postgres.port;
ret.pgPort = $interpolate`postgres.port`;
ret.pgUsername = postgres.username;
ret.pgPassword = postgres.password;
return postgres;
Expand Down
54 changes: 53 additions & 1 deletion platform/src/components/aws/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { cloudwatch, ec2, ecs, iam, lb } from "@pulumi/aws";
import { ImageArgs } from "@pulumi/docker-build";
import { Cluster as ClusterV1 } from "./cluster-v1";
import { Vpc } from "./vpc";
import { Efs } from "./efs";
export type { ClusterArgs as ClusterV1Args } from "./cluster-v1";

export const supportedCpus = {
Expand Down Expand Up @@ -569,7 +570,7 @@ export interface ClusterServiceArgs {
*/
memory?: `${number} GB`;
/**
* The amount of ephemeral storage (in GB) allocated to a container in this service.
* The amount of ephemeral storage (in GB) allocated to the container in this service.
*
* @default `"21 GB"`
*
Expand Down Expand Up @@ -855,6 +856,52 @@ export interface ClusterServiceArgs {
*/
retention?: Input<keyof typeof RETENTION>;
}>;
/**
* Mount Amazon EFS file systems into the container.
*
* @example
* Create an EFS file system.
*
* ```js
* const fileSystem = new sst.aws.Efs("MyFileSystem", { vpc });
* ```
*
* And pass it in.
*
* ```js
* {
* volumes: [
* {
* efs: fileSystem,
* path: "/mnt/efs"
* }
* ]
* }
* ```
*
* Or pass in a the EFS file system ID.
*
* ```js
* {
* volumes: [
* {
* efs: "fs-12345678",
* path: "/mnt/efs"
* }
* ]
* }
* ```
*/
volumes?: Input<{
/**
* The Amazon EFS file system to mount.
*/
efs: Input<Efs | string>;
/**
* The path to mount the volumne.
*/
path: Input<string>;
}>[];
/**
* The containers to run in the service.
*
Expand Down Expand Up @@ -958,6 +1005,11 @@ export interface ClusterServiceArgs {
*/
retention?: Input<keyof typeof RETENTION>;
}>;
/**
* Mount Amazon EFS file systems into the container. Same as the top-level
* [`efs`](#efs).
*/
volumes?: ClusterServiceArgs["volumes"];
/**
* Configure how this container works in `sst dev`. Same as the top-level
* [`dev`](#dev).
Expand Down
Loading

0 comments on commit 0d80976

Please sign in to comment.