Repository: awslabs/cdk-serverless-clamscan (language: python)

Issue:
feature : allow user to choose the EFS performance mode
Currently the EFS created by this utility uses General Performance mode. Given the reliance on EFS and file operations there should be a choice for the user to use max i/o mode for non latency sensitive use-cases.

### cdk-serverless-clamscan version
2.1.26

### Language
Python




Discussion / hints:
Agreed! We can add a parameter that lets the user select the EFS mode that defaults to general performance if not provided.

Happy to take a PR off of the main branch!
Sounds good, will submit a PR soon.

Fix patch:
diff --git a/API.md b/API.md
index 7d145fbd..505e8d6a 100644
--- a/API.md
+++ b/API.md
@@ -66,8 +66,9 @@ new ServerlessClamscan(scope: Construct, id: string, props: ServerlessClamscanPr
 * **props** (<code>[ServerlessClamscanProps](#cdk-serverless-clamscan-serverlessclamscanprops)</code>)  A `ServerlessClamscanProps` interface.
   * **acceptResponsibilityForUsingImportedBucket** (<code>boolean</code>)  Allows the use of imported buckets. __*Optional*__
   * **buckets** (<code>Array<[aws_s3.IBucket](#aws-cdk-lib-aws-s3-ibucket)></code>)  An optional list of S3 buckets to configure for ClamAV Virus Scanning; __*Optional*__
-  * **defsBucketAccessLogsConfig** (<code>[ServerlessClamscanLoggingProps](#cdk-serverless-clamscan-serverlessclamscanloggingprops)</code>)  Whether or not to enable Access Logging for the Virus Definitions bucket, you can specify an existing bucket and prefix (Default: Creates a new S3 Bucket for access logs ). __*Optional*__
+  * **defsBucketAccessLogsConfig** (<code>[ServerlessClamscanLoggingProps](#cdk-serverless-clamscan-serverlessclamscanloggingprops)</code>)  Whether or not to enable Access Logging for the Virus Definitions bucket, you can specify an existing bucket and prefix (Default: Creates a new S3 Bucket for access logs). __*Optional*__
   * **efsEncryption** (<code>boolean</code>)  Whether or not to enable encryption on EFS filesystem (Default: enabled). __*Optional*__
+  * **efsPerformanceMode** (<code>[aws_efs.PerformanceMode](#aws-cdk-lib-aws-efs-performancemode)</code>)  Set the performance mode of the EFS file system (Default: GENERAL_PURPOSE). __*Optional*__
   * **onError** (<code>[aws_lambda.IDestination](#aws-cdk-lib-aws-lambda-idestination)</code>)  The Lambda Destination for files that fail to scan and are marked 'ERROR' or stuck 'IN PROGRESS' due to a Lambda timeout (Default: Creates and publishes to a new SQS queue if unspecified). __*Optional*__
   * **onResult** (<code>[aws_lambda.IDestination](#aws-cdk-lib-aws-lambda-idestination)</code>)  The Lambda Destination for files marked 'CLEAN' or 'INFECTED' based on the ClamAV Virus scan or 'N/A' for scans triggered by S3 folder creation events marked (Default: Creates and publishes to a new Event Bridge Bus if unspecified). __*Optional*__
   * **reservedConcurrency** (<code>number</code>)  Optionally set a reserved concurrency for the virus scanning Lambda. __*Optional*__
@@ -133,7 +134,7 @@ Interface for ServerlessClamscan Virus Definitions S3 Bucket Logging.
 
 Name | Type | Description 
 -----|------|-------------
-**logsBucket**? | <code>boolean &#124; [aws_s3.IBucket](#aws-cdk-lib-aws-s3-ibucket)</code> | Destination bucket for the server access logs (Default: Creates a new S3 Bucket for access logs ).<br/>__*Optional*__
+**logsBucket**? | <code>boolean &#124; [aws_s3.IBucket](#aws-cdk-lib-aws-s3-ibucket)</code> | Destination bucket for the server access logs (Default: Creates a new S3 Bucket for access logs).<br/>__*Optional*__
 **logsPrefix**? | <code>string</code> | Optional log file prefix to use for the bucket's access logs, option is ignored if logs_bucket is set to false.<br/>__*Optional*__
 
 
@@ -149,8 +150,9 @@ Name | Type | Description
 -----|------|-------------
 **acceptResponsibilityForUsingImportedBucket**? | <code>boolean</code> | Allows the use of imported buckets.<br/>__*Optional*__
 **buckets**? | <code>Array<[aws_s3.IBucket](#aws-cdk-lib-aws-s3-ibucket)></code> | An optional list of S3 buckets to configure for ClamAV Virus Scanning;<br/>__*Optional*__
-**defsBucketAccessLogsConfig**? | <code>[ServerlessClamscanLoggingProps](#cdk-serverless-clamscan-serverlessclamscanloggingprops)</code> | Whether or not to enable Access Logging for the Virus Definitions bucket, you can specify an existing bucket and prefix (Default: Creates a new S3 Bucket for access logs ).<br/>__*Optional*__
+**defsBucketAccessLogsConfig**? | <code>[ServerlessClamscanLoggingProps](#cdk-serverless-clamscan-serverlessclamscanloggingprops)</code> | Whether or not to enable Access Logging for the Virus Definitions bucket, you can specify an existing bucket and prefix (Default: Creates a new S3 Bucket for access logs).<br/>__*Optional*__
 **efsEncryption**? | <code>boolean</code> | Whether or not to enable encryption on EFS filesystem (Default: enabled).<br/>__*Optional*__
+**efsPerformanceMode**? | <code>[aws_efs.PerformanceMode](#aws-cdk-lib-aws-efs-performancemode)</code> | Set the performance mode of the EFS file system (Default: GENERAL_PURPOSE).<br/>__*Optional*__
 **onError**? | <code>[aws_lambda.IDestination](#aws-cdk-lib-aws-lambda-idestination)</code> | The Lambda Destination for files that fail to scan and are marked 'ERROR' or stuck 'IN PROGRESS' due to a Lambda timeout (Default: Creates and publishes to a new SQS queue if unspecified).<br/>__*Optional*__
 **onResult**? | <code>[aws_lambda.IDestination](#aws-cdk-lib-aws-lambda-idestination)</code> | The Lambda Destination for files marked 'CLEAN' or 'INFECTED' based on the ClamAV Virus scan or 'N/A' for scans triggered by S3 folder creation events marked (Default: Creates and publishes to a new Event Bridge Bus if unspecified).<br/>__*Optional*__
 **reservedConcurrency**? | <code>number</code> | Optionally set a reserved concurrency for the virus scanning Lambda.<br/>__*Optional*__
diff --git a/src/index.ts b/src/index.ts
index 6b0d867d..93ae7347 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -40,7 +40,7 @@ import { Construct } from 'constructs';
  */
 export interface ServerlessClamscanLoggingProps {
   /**
-   * Destination bucket for the server access logs (Default: Creates a new S3 Bucket for access logs ).
+   * Destination bucket for the server access logs (Default: Creates a new S3 Bucket for access logs).
    */
   readonly logsBucket?: boolean | IBucket;
   /**
@@ -75,7 +75,11 @@ export interface ServerlessClamscanProps {
    */
   readonly efsEncryption?: boolean;
   /**
-   * Whether or not to enable Access Logging for the Virus Definitions bucket, you can specify an existing bucket and prefix (Default: Creates a new S3 Bucket for access logs ).
+   * Set the performance mode of the EFS file system (Default: GENERAL_PURPOSE).
+   */
+  readonly efsPerformanceMode?: PerformanceMode;
+  /**
+   * Whether or not to enable Access Logging for the Virus Definitions bucket, you can specify an existing bucket and prefix (Default: Creates a new S3 Bucket for access logs).
    */
   readonly defsBucketAccessLogsConfig?: ServerlessClamscanLoggingProps;
 
@@ -161,7 +165,7 @@ export class ServerlessClamscan extends Construct {
   public readonly defsAccessLogsBucket?: IBucket;
 
   /**
-    Conditional: When true, the user accepted the responsibility for using imported buckets
+    Conditional: When true, the user accepted the responsibility for using imported buckets.
    */
   public readonly useImportedBuckets?: boolean;
 
@@ -265,7 +269,7 @@ export class ServerlessClamscan extends Construct {
       vpc: vpc,
       encrypted: props.efsEncryption === false ? false : true,
       lifecyclePolicy: LifecyclePolicy.AFTER_7_DAYS,
-      performanceMode: PerformanceMode.GENERAL_PURPOSE,
+      performanceMode: props.efsPerformanceMode ?? PerformanceMode.GENERAL_PURPOSE,
       removalPolicy: RemovalPolicy.DESTROY,
       securityGroup: new SecurityGroup(this, 'ScanFileSystemSecurityGroup', {
         vpc: vpc,


Test patch:
diff --git a/test/ServerlessClamscan.test.ts b/test/ServerlessClamscan.test.ts
index 8fbf053b..ba5e108d 100644
--- a/test/ServerlessClamscan.test.ts
+++ b/test/ServerlessClamscan.test.ts
@@ -3,6 +3,7 @@
 
 import { ABSENT, anything, arrayWith, stringLike } from '@aws-cdk/assert';
 import { Stack } from 'aws-cdk-lib';
+import { PerformanceMode } from 'aws-cdk-lib/aws-efs';
 import { EventBus } from 'aws-cdk-lib/aws-events';
 import { SqsDestination, EventBridgeDestination } from 'aws-cdk-lib/aws-lambda-destinations';
 import { Bucket } from 'aws-cdk-lib/aws-s3';
@@ -785,4 +786,27 @@ test('Check EFS existence and Lambda Configuration ', () => {
   });
 });
 
+test('expect EFS performance mode to default to General Purpose', () => {
+  const stack = new Stack();
+  new ServerlessClamscan(stack, 'default', {});
+  expect(stack).toCountResources('AWS::EFS::FileSystem', 1);
+  expect(stack).toHaveResourceLike('AWS::EFS::FileSystem', {
+    PerformanceMode: 'generalPurpose',
+  });
+});
 
+test('expect EFS performance mode to be set as configured', () => {
+  const stack1 = new Stack();
+  new ServerlessClamscan(stack1, 'rMaxIoEfs', { efsPerformanceMode: PerformanceMode.MAX_IO });
+  expect(stack1).toCountResources('AWS::EFS::FileSystem', 1);
+  expect(stack1).toHaveResourceLike('AWS::EFS::FileSystem', {
+    PerformanceMode: 'maxIO',
+  });
+
+  const stack2 = new Stack();
+  new ServerlessClamscan(stack2, 'rGeneralPurposeEfs', { efsPerformanceMode: PerformanceMode.GENERAL_PURPOSE });
+  expect(stack2).toCountResources('AWS::EFS::FileSystem', 1);
+  expect(stack2).toHaveResourceLike('AWS::EFS::FileSystem', {
+    PerformanceMode: 'generalPurpose',
+  });
+});