-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feature/DO-1607-feature-environments
- Loading branch information
Showing
29 changed files
with
3,020 additions
and
1,302 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
*.ts | ||
!assets/handlers/*.ts | ||
!assets/handlers/**/*.ts | ||
!*.d.ts | ||
!*.js | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,7 @@ | ||
# GraphQL Mesh in Fargate | ||
A construct host [GraphQL Mesh](https://the-guild.dev/graphql/mesh) server in Fargate. | ||
A construct to host a [GraphQL Mesh](https://the-guild.dev/graphql/mesh) server in Fargate. | ||
|
||
![graphql mesh server hosting diagram](docs/graphql_mesh_server_hosting.png) | ||
|
||
## Deployment notifications | ||
If notificationArn is set this construct creates a CodeStar notification rule, SNS topic and Lambda function to receive notifications for codepipeline executions and forward them to another SNS topic. This is so that you can setup AWS Chatbot either in this account OR another account and forward the notifications there. | ||
|
||
## Props | ||
|
||
- `vpc?`: VPC to attach Redis and Fargate instances to (default: create a vpc) | ||
- `vpcName?`: If no VPC is provided create one with this name (default: 'graphql-server-vpc') | ||
- `cacheNodeType?`: Cache node type (default: 'cache.t2.micro') | ||
- `repository?`: Repository to pull the container image from | ||
- `certificateArn:` ARN of the certificate to add to the load balancer | ||
- `minCapacity?`: Minimum number of Fargate instances | ||
- `maxCapacity?`: Maximum number of Fargate instances | ||
- `cpu?`: Amount of vCPU per Fargate instance (default: 512) | ||
- `memory?`: Amount of memory per Fargate instance (default: 1024) | ||
- `redis?`: Redis instance to use for mesh caching | ||
- `secrets?`: SSM values to pass through to the container as secrets | ||
- `cpuScalingSteps?`: Pass custom CPU scaling steps (default: [{ upper: 30, change: -1 }, { lower: 50, change: +1 }, { lower: 85, change: +3 }]) | ||
- `notificationArn?`: SNS Topic ARN to publish deployment notifications to | ||
- `notificationRegion?`: Region of the SNS Topic that deployment notifications are sent to | ||
- `blockedIps?`: List of IPv4 addresses to block | ||
- `blockedIpPriority?`: The WAF rule priority (defaults to 2) | ||
- `blockedIpv6s?`: List of IPv6 addresses to block | ||
- `blockedIpv6Priority?`: The WAF rule priority (defaults to 3) | ||
- `wafManagedRules?`: List of AWS Managed rules to add to the WAF | ||
- `wafRules?`: List of custom rules | ||
- `rateLimit?`: The limit on requests per 5-minute period. If provided, rate limiting will be enabled | ||
- `rateLimitPriority?`: The WAF rule priority. Only used when a rateLimit value is provided (defaults to 10) | ||
- `rateLimitBypassList?`: List of IPv4 addresses that can bypass rate limiting | ||
- `containerInsights?`: Enable/disable container insights (defaults to true) | ||
- `logStreamPrefix?`: Log stream prefix (defaults to 'graphql-server') | ||
- `snsTopic?`: Optional SNS topic to subscribe all alarms to | ||
- `additionalAlarms?`: Any additional custom alarms |
29 changes: 29 additions & 0 deletions
29
packages/graphql-mesh-server/assets/handlers/invalidate-cloudfront-cache.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { | ||
CloudFrontClient, | ||
CreateInvalidationCommand, | ||
CreateInvalidationCommandInput, | ||
CreateInvalidationCommandOutput, | ||
} from "@aws-sdk/client-cloudfront"; | ||
|
||
const cfClient = new CloudFrontClient(); | ||
|
||
const PATHS = process.env.PATHS as string; | ||
const DISTRIBUTION_ID = process.env.DISTRIBUTION_ID as string; | ||
|
||
export const handler = async (): Promise<CreateInvalidationCommandOutput> => { | ||
const paths = PATHS.split(","); | ||
|
||
const invalidationInput: CreateInvalidationCommandInput = { | ||
DistributionId: DISTRIBUTION_ID, | ||
InvalidationBatch: { | ||
Paths: { | ||
Quantity: paths.length, | ||
Items: paths, | ||
}, | ||
CallerReference: "lambda", | ||
}, | ||
}; | ||
|
||
const command = new CreateInvalidationCommand(invalidationInput); | ||
return cfClient.send(command); | ||
}; |
64 changes: 64 additions & 0 deletions
64
packages/graphql-mesh-server/assets/handlers/maintenance/lib/file.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs"; | ||
|
||
const IP_REGEX = | ||
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/([1-9]|[1-2][0-9]|3[1-2]))?$/; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
const MAINTENANCE_FILE_PATH = process.env.MAINTENANCE_FILE_PATH!; | ||
const FILE_NAME = "maintenance"; | ||
const PATHS = [ | ||
`${MAINTENANCE_FILE_PATH}/${FILE_NAME}.disabled`, | ||
`${MAINTENANCE_FILE_PATH}/${FILE_NAME}.enabled`, | ||
]; | ||
|
||
export const getFilePath = (): string => { | ||
for (const path of PATHS) { | ||
if (existsSync(path)) { | ||
return path; | ||
} | ||
} | ||
|
||
// If the maintenance file wasn't found, create one | ||
writeFileSync(PATHS[0], ""); | ||
return PATHS[0]; | ||
}; | ||
|
||
export const getFileContents = (): string => { | ||
return readFileSync(getFilePath(), "utf-8"); | ||
}; | ||
|
||
export const setFileContents = (input: string): void => { | ||
if (!validateIps(input)) throw new Error("List of IP addresses not valid"); | ||
const uniqueIps = [...new Set(input.split(","))].join(","); | ||
|
||
writeFileSync(getFilePath(), uniqueIps, { encoding: "utf-8" }); | ||
}; | ||
|
||
export const updateFileContents = (input: string): void => { | ||
if (!input) throw new Error("Nothing to update."); | ||
if (!validateIps(input)) throw new Error("List of IP addresses not valid"); | ||
|
||
setFileContents(`${getFileContents()},${input}`); | ||
}; | ||
|
||
export const getCurrentStatus = (): "disabled" | "enabled" => { | ||
return inMaintenanceMode() ? "enabled" : "disabled"; | ||
}; | ||
|
||
export const inMaintenanceMode = (): boolean => { | ||
return getFilePath().includes("enabled"); | ||
}; | ||
|
||
export const toggleMaintenanceStatus = () => { | ||
const desiredStatus = inMaintenanceMode() ? "disabled" : "enabled"; | ||
|
||
renameSync( | ||
getFilePath(), | ||
`${MAINTENANCE_FILE_PATH}/${FILE_NAME}.${desiredStatus}` | ||
); | ||
}; | ||
|
||
const validateIps = (ipList: string) => { | ||
const ips = ipList.split(","); | ||
return ips.find(ip => !IP_REGEX.test(ip)) === undefined; | ||
}; |
51 changes: 51 additions & 0 deletions
51
packages/graphql-mesh-server/assets/handlers/maintenance/maintenance.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda"; | ||
import { getCurrentStatus, toggleMaintenanceStatus } from "./lib/file"; | ||
|
||
const MAINTENANCE_FILE_PATH = process.env.MAINTENANCE_FILE_PATH; | ||
|
||
export const handler = async ( | ||
event: APIGatewayProxyEvent | ||
): Promise<APIGatewayProxyResult> => { | ||
if (!MAINTENANCE_FILE_PATH) throw new Error("a"); | ||
let body = "Method not implemented"; | ||
let status = 200; | ||
|
||
switch (event.httpMethod) { | ||
case "GET": | ||
body = getCurrentStatus(); | ||
break; | ||
case "POST": | ||
body = changeMaintenanceStatus(extractDesiredStatusFromEvent(event)); | ||
break; | ||
default: | ||
status = 501; | ||
} | ||
|
||
return { | ||
body: body, | ||
statusCode: status, | ||
}; | ||
}; | ||
const extractDesiredStatusFromEvent = ( | ||
event: APIGatewayProxyEvent | ||
): "enabled" | "disabled" | undefined => { | ||
if (event.resource.includes("enable")) return "enabled"; | ||
if (event.resource.includes("disable")) return "disabled"; | ||
return undefined; | ||
}; | ||
|
||
const changeMaintenanceStatus = ( | ||
desiredStatus?: "enabled" | "disabled" | ||
): string => { | ||
// If no status is provided then toggle | ||
if (desiredStatus === undefined) { | ||
toggleMaintenanceStatus(); | ||
return getCurrentStatus(); | ||
} | ||
|
||
const currentStatus = getCurrentStatus(); | ||
if (currentStatus === desiredStatus) return currentStatus; | ||
|
||
toggleMaintenanceStatus(); | ||
return getCurrentStatus(); | ||
}; |
56 changes: 56 additions & 0 deletions
56
packages/graphql-mesh-server/assets/handlers/maintenance/whitelist.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda"; | ||
import { | ||
getFileContents, | ||
setFileContents, | ||
updateFileContents, | ||
} from "./lib/file"; | ||
|
||
const MAINTENANCE_FILE_PATH = process.env.MAINTENANCE_FILE_PATH; | ||
|
||
export const handler = async ( | ||
event: APIGatewayProxyEvent | ||
): Promise<APIGatewayProxyResult> => { | ||
if (!MAINTENANCE_FILE_PATH) throw new Error("a"); | ||
let body = "Method not implemented"; | ||
let status = 200; | ||
|
||
try { | ||
switch (event.httpMethod) { | ||
case "GET": | ||
body = getFileContents(); | ||
break; | ||
case "PUT": | ||
setFileContents(event.body || ""); | ||
body = "Successfully updated whitelist"; | ||
break; | ||
case "PATCH": | ||
updateFileContents(event.body || ""); | ||
body = "Successfully updated whitelist"; | ||
break; | ||
default: | ||
status = 501; | ||
} | ||
} catch (error) { | ||
let statusCode = 500; | ||
const errorMsg = error.errorMessage; | ||
|
||
if (!errorMsg) { | ||
return { | ||
body: "Unknown Error", | ||
statusCode: statusCode, | ||
}; | ||
} | ||
|
||
if (errorMsg === "List of IP addresses not valid") statusCode = 403; | ||
|
||
return { | ||
body: errorMsg, | ||
statusCode: statusCode, | ||
}; | ||
} | ||
|
||
return { | ||
body: body, | ||
statusCode: status, | ||
}; | ||
}; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.