aws-genai-llm-chatbot
179 строк · 6.3 Кб
1import * as cdk from "aws-cdk-lib";
2import * as iam from "aws-cdk-lib/aws-iam";
3import * as lambda from "aws-cdk-lib/aws-lambda";
4import * as logs from "aws-cdk-lib/aws-logs";
5import * as sfn from "aws-cdk-lib/aws-stepfunctions";
6import * as tasks from "aws-cdk-lib/aws-stepfunctions-tasks";
7import { Construct } from "constructs";
8import * as path from "path";
9import { Shared } from "../../shared";
10import { SystemConfig } from "../../shared/types";
11import { AuroraPgVector } from "../aurora-pgvector";
12import { DataImport } from "../data-import";
13import { KendraRetrieval } from "../kendra-retrieval";
14import { OpenSearchVector } from "../opensearch-vector";
15import { RagDynamoDBTables } from "../rag-dynamodb-tables";
16import { RemovalPolicy } from "aws-cdk-lib";
17
18export interface DeleteWorkspaceProps {
19readonly config: SystemConfig;
20readonly shared: Shared;
21readonly dataImport: DataImport;
22readonly ragDynamoDBTables: RagDynamoDBTables;
23readonly auroraPgVector?: AuroraPgVector;
24readonly openSearchVector?: OpenSearchVector;
25readonly kendraRetrieval?: KendraRetrieval;
26}
27
28export class DeleteWorkspace extends Construct {
29public readonly stateMachine?: sfn.StateMachine;
30
31constructor(scope: Construct, id: string, props: DeleteWorkspaceProps) {
32super(scope, id);
33
34const deleteFunction = new lambda.Function(
35this,
36"DeleteWorkspaceFunction",
37{
38vpc: props.shared.vpc,
39code: props.shared.sharedCode.bundleWithLambdaAsset(
40path.join(__dirname, "./functions/delete-workspace-workflow/delete")
41),
42runtime: props.shared.pythonRuntime,
43architecture: props.shared.lambdaArchitecture,
44handler: "index.lambda_handler",
45layers: [props.shared.powerToolsLayer, props.shared.commonLayer],
46timeout: cdk.Duration.minutes(15),
47logRetention: logs.RetentionDays.ONE_WEEK,
48environment: {
49...props.shared.defaultEnvironmentVariables,
50AURORA_DB_SECRET_ID: props.auroraPgVector?.database.secret
51?.secretArn as string,
52UPLOAD_BUCKET_NAME: props.dataImport.uploadBucket.bucketName,
53PROCESSING_BUCKET_NAME: props.dataImport.processingBucket.bucketName,
54WORKSPACES_TABLE_NAME:
55props.ragDynamoDBTables.workspacesTable.tableName,
56WORKSPACES_BY_OBJECT_TYPE_INDEX_NAME:
57props.ragDynamoDBTables.workspacesByObjectTypeIndexName,
58DOCUMENTS_TABLE_NAME:
59props.ragDynamoDBTables?.documentsTable.tableName ?? "",
60DOCUMENTS_BY_COMPOUND_KEY_INDEX_NAME:
61props.ragDynamoDBTables?.documentsByCompoundKeyIndexName ?? "",
62DOCUMENTS_BY_STATUS_INDEX:
63props.ragDynamoDBTables.documentsByStatusIndexName ?? "",
64DEFAULT_KENDRA_S3_DATA_SOURCE_BUCKET_NAME:
65props.kendraRetrieval?.kendraS3DataSourceBucket?.bucketName ?? "",
66OPEN_SEARCH_COLLECTION_ENDPOINT:
67props.openSearchVector?.openSearchCollectionEndpoint ?? "",
68},
69}
70);
71
72if (props.auroraPgVector) {
73props.auroraPgVector.database.secret?.grantRead(deleteFunction);
74props.auroraPgVector.database.connections.allowDefaultPortFrom(
75deleteFunction
76);
77}
78
79if (props.openSearchVector) {
80deleteFunction.addToRolePolicy(
81new iam.PolicyStatement({
82actions: [
83"aoss:APIAccessAll",
84"aoss:DescribeIndex",
85"aoss:DeleteIndex",
86],
87resources: [props.openSearchVector.openSearchCollection.attrArn],
88})
89);
90
91props.openSearchVector.addToAccessPolicy(
92"delete-workspace",
93[deleteFunction.role?.roleArn],
94[
95"aoss:DeleteIndex",
96"aoss:DescribeIndex",
97"aoss:ReadDocument",
98"aoss:WriteDocument",
99]
100);
101}
102
103props.dataImport.uploadBucket.grantReadWrite(deleteFunction);
104props.dataImport.processingBucket.grantReadWrite(deleteFunction);
105props.kendraRetrieval?.kendraS3DataSourceBucket?.grantReadWrite(
106deleteFunction
107);
108props.ragDynamoDBTables.workspacesTable.grantReadWriteData(deleteFunction);
109props.ragDynamoDBTables.documentsTable.grantReadWriteData(deleteFunction);
110
111const handleError = new tasks.DynamoUpdateItem(this, "HandleError", {
112table: props.ragDynamoDBTables.workspacesTable,
113key: {
114workspace_id: tasks.DynamoAttributeValue.fromString(
115sfn.JsonPath.stringAt("$.workspace_id")
116),
117object_type: tasks.DynamoAttributeValue.fromString("workspace"),
118},
119updateExpression: "set #status = :error",
120expressionAttributeNames: {
121"#status": "status",
122},
123expressionAttributeValues: {
124":error": tasks.DynamoAttributeValue.fromString("error"),
125},
126}).next(
127new sfn.Fail(this, "Fail", {
128cause: "Workspace deletion failed",
129})
130);
131
132const setDeleting = new tasks.DynamoUpdateItem(this, "SetDeleting", {
133table: props.ragDynamoDBTables.workspacesTable,
134key: {
135workspace_id: tasks.DynamoAttributeValue.fromString(
136sfn.JsonPath.stringAt("$.workspace_id")
137),
138object_type: tasks.DynamoAttributeValue.fromString("workspace"),
139},
140updateExpression: "set #status=:statusValue",
141expressionAttributeNames: {
142"#status": "status",
143},
144expressionAttributeValues: {
145":statusValue": tasks.DynamoAttributeValue.fromString("deleting"),
146},
147resultPath: sfn.JsonPath.DISCARD,
148});
149
150const deleteTask = new tasks.LambdaInvoke(this, "Delete", {
151lambdaFunction: deleteFunction,
152resultPath: "$.deleteResult",
153}).addCatch(handleError, {
154errors: ["States.ALL"],
155resultPath: "$.deleteResult",
156});
157
158const workflow = setDeleting
159.next(deleteTask)
160.next(new sfn.Succeed(this, "Success"));
161
162const logGroup = new logs.LogGroup(this, "DeleteWorkspaceSMLogGroup", {
163removalPolicy: RemovalPolicy.DESTROY,
164});
165
166const stateMachine = new sfn.StateMachine(this, "DeleteWorkspace", {
167definitionBody: sfn.DefinitionBody.fromChainable(workflow),
168timeout: cdk.Duration.minutes(5),
169comment: "Delete Workspace Workflow",
170tracingEnabled: true,
171logs: {
172destination: logGroup,
173level: sfn.LogLevel.ALL,
174},
175});
176
177this.stateMachine = stateMachine;
178}
179}
180