feat(api): add EFS file systems to the cloud explorer
CI / checks (pull_request) Successful in 28m26s
CI / checks (pull_request) Successful in 28m26s
Create file systems (with a mount target in each default subnet unless asked not to), add and remove mount targets, create and delete access points, and attach a file system to a Lambda function through an access point. A function not yet in a VPC is put in the file system's mount target subnets with the default security group, as Lambda requires. TheCloud's mounts are real, so two functions on one access point share files. Deleting a file system removes its access points and mount targets first, and is refused while a function still mounts it.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import type {CloudProvider, FieldSchema, ServiceSchema, TableColumnSchema} from './types'
|
||||
|
||||
/** The Name tag EFS shows for a file system; AWS caps tag values at 256 characters. */
|
||||
export const FILE_SYSTEM_NAME_PATTERN = '^[^\\x00-\\x1f]{1,256}$'
|
||||
export const FILE_SYSTEM_PERFORMANCE_MODES = ['generalPurpose', 'maxIO'] as const
|
||||
export const FILE_SYSTEM_THROUGHPUT_MODES = ['bursting', 'elastic'] as const
|
||||
/** An access point's root: an absolute path of up to 100 characters. */
|
||||
export const ACCESS_POINT_PATH_PATTERN = '^/[^\\x00]{0,99}$'
|
||||
/** Lambda mounts file systems under /mnt only. */
|
||||
export const LAMBDA_MOUNT_PATH_PATTERN = '^/mnt/[a-zA-Z0-9-_.]{1,160}$'
|
||||
|
||||
const fileSystemColumns: TableColumnSchema[] = [
|
||||
{name: 'name', label: 'Name'},
|
||||
{name: 'id', label: 'File system ID', path: 'metadata.fileSystemId'},
|
||||
{name: 'status', label: 'State', format: 'badge'},
|
||||
{name: 'mountTargets', label: 'Mount targets', path: 'metadata.numberOfMountTargets'},
|
||||
{name: 'performanceMode', label: 'Performance', path: 'metadata.performanceMode'},
|
||||
{name: 'encrypted', label: 'Encrypted', path: 'metadata.encrypted', format: 'boolean'},
|
||||
{name: 'createdAt', label: 'Created', format: 'datetime'},
|
||||
]
|
||||
|
||||
const fileSystemFilters: FieldSchema[] = [{name: 'search', label: 'Search', type: 'text', required: false}]
|
||||
|
||||
export function awsFileSystemsSchema(): ServiceSchema {
|
||||
return {
|
||||
cloud: 'aws',
|
||||
service: 'filesystems',
|
||||
displayName: 'EFS file systems',
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
type: 'text',
|
||||
required: false,
|
||||
description: 'Stored as the Name tag, as the AWS console does.',
|
||||
validation: {pattern: FILE_SYSTEM_NAME_PATTERN, message: 'Use up to 256 characters'},
|
||||
},
|
||||
{
|
||||
name: 'mountTargets',
|
||||
label: 'Mount targets',
|
||||
type: 'select',
|
||||
required: false,
|
||||
defaultValue: 'default',
|
||||
description: 'Lambda functions and ECS tasks reach a file system through a mount target in their subnet.',
|
||||
options: [
|
||||
{label: 'One in each default subnet', value: 'default'},
|
||||
{label: 'None for now', value: 'none'},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'performanceMode',
|
||||
label: 'Performance mode',
|
||||
type: 'select',
|
||||
required: false,
|
||||
defaultValue: 'generalPurpose',
|
||||
options: [
|
||||
{label: 'General Purpose', value: 'generalPurpose'},
|
||||
{label: 'Max I/O', value: 'maxIO'},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'throughputMode',
|
||||
label: 'Throughput mode',
|
||||
type: 'select',
|
||||
required: false,
|
||||
defaultValue: 'bursting',
|
||||
options: [
|
||||
{label: 'Bursting', value: 'bursting'},
|
||||
{label: 'Elastic', value: 'elastic'},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'encrypted',
|
||||
label: 'Encryption at rest',
|
||||
type: 'select',
|
||||
required: false,
|
||||
defaultValue: 'true',
|
||||
options: [
|
||||
{label: 'Encrypted', value: 'true'},
|
||||
{label: 'Not encrypted', value: 'false'},
|
||||
],
|
||||
},
|
||||
],
|
||||
actions: ['list', 'create', 'delete', 'inspect'],
|
||||
capabilities: {
|
||||
resourceActions: [
|
||||
{name: 'list', label: 'List file systems', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'create', label: 'Create file system', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'delete', label: 'Delete file system', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'inspect', label: 'Inspect file system', enabled: true, status: 'available', runtimeRequired: true},
|
||||
],
|
||||
fileSystemActions: [
|
||||
{name: 'createMountTarget', label: 'Add mount target', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'deleteMountTarget', label: 'Remove mount target', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'createAccessPoint', label: 'Create access point', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'deleteAccessPoint', label: 'Delete access point', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'attachFunction', label: 'Attach to a Lambda function', enabled: true, status: 'available', runtimeRequired: true},
|
||||
{name: 'detachFunction', label: 'Detach from a Lambda function', enabled: true, status: 'available', runtimeRequired: true},
|
||||
],
|
||||
},
|
||||
filters: fileSystemFilters,
|
||||
columns: fileSystemColumns,
|
||||
}
|
||||
}
|
||||
|
||||
export function fileSystemsSchemaFor(cloud: CloudProvider): ServiceSchema | null {
|
||||
return cloud === 'aws' ? awsFileSystemsSchema() : null
|
||||
}
|
||||
@@ -132,6 +132,13 @@ export const SERVICE_CATALOG = {
|
||||
group: 'Storage',
|
||||
order: 20,
|
||||
},
|
||||
filesystems: {
|
||||
displayName: 'File Systems',
|
||||
displayNameByCloud: {aws: 'EFS'},
|
||||
iconKey: 'filesystems',
|
||||
group: 'Storage',
|
||||
order: 30,
|
||||
},
|
||||
database: {displayName: 'Database', iconKey: 'database', group: 'Databases', order: 10},
|
||||
nosql: {
|
||||
displayName: 'NoSQL',
|
||||
|
||||
@@ -188,6 +188,7 @@ export type UserPoolActionName =
|
||||
export type DistributionActionName = 'setEnabled' | 'createInvalidation'
|
||||
export type AutoScalingActionName = 'setCapacity' | 'terminateInstance'
|
||||
export type CertificateActionName = 'download' | 'export' | 'revoke'
|
||||
export type FileSystemActionName = 'createMountTarget' | 'deleteMountTarget' | 'createAccessPoint' | 'deleteAccessPoint' | 'attachFunction' | 'detachFunction'
|
||||
export type MonitoringActionName = 'listMetrics' | 'getMetricData' | 'alarmHistory' | 'setAlarmState' | 'setAlarmActions'
|
||||
export type HttpApiActionName =
|
||||
| 'describe'
|
||||
@@ -249,6 +250,7 @@ export interface ServiceSchema {
|
||||
distributionActions?: CapabilitySchema<DistributionActionName>[]
|
||||
autoScalingActions?: CapabilitySchema<AutoScalingActionName>[]
|
||||
certificateActions?: CapabilitySchema<CertificateActionName>[]
|
||||
fileSystemActions?: CapabilitySchema<FileSystemActionName>[]
|
||||
monitoringActions?: CapabilitySchema<MonitoringActionName>[]
|
||||
/** API Gateway v2 (HTTP and WebSocket APIs): what the routes, stages and security panel can do. */
|
||||
httpApiActions?: CapabilitySchema<HttpApiActionName>[]
|
||||
@@ -546,6 +548,22 @@ export interface AutoScalingCapacityInput {
|
||||
maxSize?: number
|
||||
}
|
||||
|
||||
export interface AccessPointInput {
|
||||
name?: string
|
||||
/** Where the access point's root sits inside the file system; created on first use. */
|
||||
path: string
|
||||
uid: number
|
||||
gid: number
|
||||
/** Octal permissions for the root directory when EFS creates it, such as 755. */
|
||||
permissions: string
|
||||
}
|
||||
|
||||
export interface FileSystemAttachmentInput {
|
||||
accessPointId: string
|
||||
functionName: string
|
||||
mountPath: string
|
||||
}
|
||||
|
||||
export interface DistributionInvalidation {
|
||||
id: string
|
||||
status: string
|
||||
@@ -1217,6 +1235,13 @@ export interface CloudServiceAdapter {
|
||||
/** With `replace`, the group launches a new instance in its place; otherwise desired capacity drops by one. */
|
||||
terminateAutoScalingInstance?(groupName: string, instanceId: string, replace: boolean): Promise<void>
|
||||
getCertificatePem?(certificateId: string): Promise<CertificatePem>
|
||||
createMountTarget?(fileSystemId: string, subnetId: string): Promise<CloudResource>
|
||||
deleteMountTarget?(fileSystemId: string, mountTargetId: string): Promise<CloudResource>
|
||||
createAccessPoint?(fileSystemId: string, input: AccessPointInput): Promise<CloudResource>
|
||||
deleteAccessPoint?(fileSystemId: string, accessPointId: string): Promise<CloudResource>
|
||||
/** Mounts one of the file system's access points into a Lambda function, as UpdateFunctionConfiguration does. */
|
||||
attachFileSystemToFunction?(fileSystemId: string, input: FileSystemAttachmentInput): Promise<CloudResource>
|
||||
detachFileSystemFromFunction?(fileSystemId: string, functionName: string): Promise<CloudResource>
|
||||
exportCertificate?(certificateId: string, passphrase: string): Promise<ExportedCertificate>
|
||||
revokeCertificate?(certificateId: string, reason: CertificateRevocationReason): Promise<CloudResource>
|
||||
updateUserPoolClientOAuth?(poolId: string, clientId: string, input: UpdateUserPoolClientOAuthInput): Promise<UserPoolClientSettings>
|
||||
|
||||
Reference in New Issue
Block a user