Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: filemanager stack #180

Merged
merged 6 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions config/constants.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { OrcaBusStatefulConfig } from '../lib/workload/orcabus-stateful-stack';
import { AuroraPostgresEngineVersion } from 'aws-cdk-lib/aws-rds';
import {
FilemanagerDependencies,
OrcaBusStatelessConfig,
} from '../lib/workload/orcabus-stateless-stack';
import { OrcaBusStatelessConfig } from '../lib/workload/orcabus-stateless-stack';
import { Duration, RemovalPolicy } from 'aws-cdk-lib';
import { EventSourceProps } from '../lib/workload/stateful/event_source/component';
import { DbAuthType } from '../lib/workload/stateless/postgres_manager/function/type';
import { FilemanagerConfig } from '../lib/workload/stateless/filemanager/deploy/lib/filemanager';

const regName = 'OrcaBusSchemaRegistry';
const eventBusName = 'OrcaBusMain';
const lambdaSecurityGroupName = 'OrcaBusLambdaSecurityGroup';
const dbClusterIdentifier = 'orcabus-db';
const dbClusterResourceIdParameterName = '/orcabus/db-cluster-resource-id';

const eventSourceQueueName = 'orcabus-event-source-queue';
const devBucket = 'umccr-temp-dev';
const stgBucket = 'umccr-temp-stg';
const prodBucket = 'org.umccr.data.oncoanalyser';

// Note, this should not end with a hyphen and 6 characters, otherwise secrets manager won't be
// able to find the secret using a partial ARN.
const rdsMasterSecretName = 'orcabus/master-rds'; // pragma: allowlist secret
Expand Down Expand Up @@ -87,20 +90,24 @@ const orcaBusStatelessConfig = {
},
};

const eventSourceConfig: EventSourceProps = {
queueName: 'orcabus-event-source-queue',
maxReceiveCount: 3,
rules: [
{
bucket: 'umccr-temp-dev',
},
],
const eventSourceConfig = (bucket: string): EventSourceProps => {
return {
queueName: eventSourceQueueName,
maxReceiveCount: 3,
rules: [
{
bucket,
},
],
};
};

const filemanagerDependencies: FilemanagerDependencies = {
eventSourceBuckets: ['umccr-temp-dev'],
eventSourceQueueName: eventSourceConfig.queueName,
databaseSecretName: orcaBusStatefulConfig.databaseProps.masterSecretName,
const filemanagerConfig = (bucket: string): FilemanagerConfig => {
return {
eventSourceQueueName: eventSourceQueueName,
databaseSecretName: orcaBusStatefulConfig.databaseProps.masterSecretName,
eventSourceBuckets: [bucket],
};
};

interface EnvironmentConfig {
Expand Down Expand Up @@ -152,11 +159,11 @@ export const getEnvironmentConfig = (
securityGroupProps: {
...orcaBusStatefulConfig.securityGroupProps,
},
eventSourceProps: eventSourceConfig,
eventSourceProps: eventSourceConfig(devBucket),
},
orcaBusStatelessConfig: {
...orcaBusStatelessConfig,
filemanagerDependencies: filemanagerDependencies,
filemanagerConfig: filemanagerConfig(devBucket),
},
},
};
Expand Down Expand Up @@ -186,8 +193,12 @@ export const getEnvironmentConfig = (
securityGroupProps: {
...orcaBusStatefulConfig.securityGroupProps,
},
eventSourceProps: eventSourceConfig(stgBucket),
},
orcaBusStatelessConfig: {
...orcaBusStatelessConfig,
filemanagerConfig: filemanagerConfig(stgBucket),
},
orcaBusStatelessConfig: orcaBusStatelessConfig,
},
};
break;
Expand All @@ -214,8 +225,12 @@ export const getEnvironmentConfig = (
securityGroupProps: {
...orcaBusStatefulConfig.securityGroupProps,
},
eventSourceProps: eventSourceConfig(prodBucket),
},
orcaBusStatelessConfig: {
...orcaBusStatelessConfig,
filemanagerConfig: filemanagerConfig(prodBucket),
},
orcaBusStatelessConfig: orcaBusStatelessConfig,
},
};
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type FunctionName = {
* Function name.
*/
functionName: string;
}
};

/**
* Props for the resource invoke construct.
Expand Down Expand Up @@ -101,7 +101,7 @@ export class CdkResourceInvoke<P, F extends InvokeFunction> extends Construct {
action: 'invoke',
parameters: {
FunctionName: this.function.functionName,
...(props.payload && { Payload: props.payload })
...(props.payload && { Payload: props.payload }),
},
physicalResourceId: PhysicalResourceId.of(
`${id}-AwsSdkCall-${this.function.currentVersion + this.hashValue(props.payload)}`
Expand All @@ -111,13 +111,10 @@ export class CdkResourceInvoke<P, F extends InvokeFunction> extends Construct {
const role = new Role(this, 'AwsCustomResourceRole', {
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
});
const lambdaResource = `arn:aws:lambda:${stack.region}:${stack.account}:function:${stackHash}-ResourceInvokeFunction-${props.id}`;
role.addToPolicy(
new PolicyStatement({
resources: [
// This needs to have permissions to run any `ResourceInvokeFunction` because it is deployed as a
// singleton Lambda function.
`arn:aws:lambda:${stack.region}:${stack.account}:function:${stackHash}-ResourceInvokeFunction-*`,
],
resources: [lambdaResource],
actions: ['lambda:InvokeFunction'],
})
);
Expand All @@ -128,11 +125,12 @@ export class CdkResourceInvoke<P, F extends InvokeFunction> extends Construct {

this._customResource = new AwsCustomResource(this, 'AwsCustomResource', {
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
resources: [lambdaResource],
}),
onUpdate: sdkCall,
role: role,
vpc: props.vpc,
installLatestAwsSdk: true,
vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
});

Expand Down
45 changes: 8 additions & 37 deletions lib/workload/orcabus-stateless-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Construct } from 'constructs';
import { getVpc } from './stateful/vpc/component';
import { MultiSchemaConstructProps } from './stateless/schema/component';
import { IVpc, ISecurityGroup, SecurityGroup } from 'aws-cdk-lib/aws-ec2';
import { Filemanager } from './stateless/filemanager/deploy/lib/filemanager';
import { Filemanager, FilemanagerConfig } from './stateless/filemanager/deploy/lib/filemanager';
import { Queue } from 'aws-cdk-lib/aws-sqs';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';
import {
Expand All @@ -20,22 +20,7 @@ export interface OrcaBusStatelessConfig {
lambdaSecurityGroupName: string;
rdsMasterSecretName: string;
postgresManagerConfig: PostgresManagerConfig;
filemanagerDependencies?: FilemanagerDependencies;
}

export interface FilemanagerDependencies {
/**
* Queue name used by the EventSource construct.
*/
eventSourceQueueName: string;
/**
* Buckets defined by the EventSource construct.
*/
eventSourceBuckets: string[];
/**
* Database secret name for the filemanager.
*/
databaseSecretName: string;
filemanagerConfig: FilemanagerConfig;
}

export class OrcaBusStatelessStack extends cdk.Stack {
Expand Down Expand Up @@ -70,13 +55,7 @@ export class OrcaBusStatelessStack extends cdk.Stack {

this.microserviceStackArray.push(this.createSequenceRunManager(props));
this.microserviceStackArray.push(this.createPostgresManager(props.postgresManagerConfig));

if (props.filemanagerDependencies) {
this.createFilemanager({
...props.filemanagerDependencies,
lambdaSecurityGroupName: props.lambdaSecurityGroupName,
});
}
this.microserviceStackArray.push(this.createFilemanager(props.filemanagerConfig));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woo ho ho! Welcome to the nag club! 🤭

}

private createSequenceRunManager(props: cdk.StackProps) {
Expand All @@ -96,38 +75,30 @@ export class OrcaBusStatelessStack extends cdk.Stack {
});
}

private createFilemanager(
dependencies: FilemanagerDependencies & { lambdaSecurityGroupName: string }
) {
private createFilemanager(config: FilemanagerConfig) {
// Opting to reconstruct the dependencies here, and pass them into the service as constructs.
const queue = Queue.fromQueueArn(
this,
'FilemanagerQueue',
Arn.format(
{
resource: dependencies.eventSourceQueueName,
resource: config.eventSourceQueueName,
service: 'sqs',
},
this
)
);
const databaseSecurityGroup = SecurityGroup.fromLookupByName(
this,
'FilemanagerDatabaseSecurityGroup',
dependencies.lambdaSecurityGroupName,
this.vpc
);
const databaseSecret = Secret.fromSecretNameV2(
this,
'FilemanagerDatabaseSecret',
dependencies.databaseSecretName
config.databaseSecretName
);

return new Filemanager(this, 'Filemanager', {
buckets: dependencies.eventSourceBuckets,
buckets: config.eventSourceBuckets,
buildEnvironment: {},
databaseSecret,
databaseSecurityGroup,
databaseSecurityGroup: this.lambdaSecurityGroup,
eventSources: [queue],
migrateDatabase: true,
vpc: this.vpc,
Expand Down
3 changes: 2 additions & 1 deletion lib/workload/stateful/event_source/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ export class EventSource extends Construct {
constructor(scope: Construct, id: string, props: EventSourceProps) {
super(scope, id);

this.deadLetterQueue = new Queue(this, 'DeadLetterQueue');
this.deadLetterQueue = new Queue(this, 'DeadLetterQueue', { enforceSSL: true });
this.queue = new Queue(this, 'Queue', {
queueName: props.queueName,
enforceSSL: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

deadLetterQueue: {
maxReceiveCount: props.maxReceiveCount,
queue: this.deadLetterQueue,
Expand Down
Loading
Loading