aws-genai-llm-chatbot
170 строк · 5.5 Кб
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 oss from "aws-cdk-lib/aws-opensearchserverless";
6import * as sfn from "aws-cdk-lib/aws-stepfunctions";
7import * as tasks from "aws-cdk-lib/aws-stepfunctions-tasks";
8import { Construct } from "constructs";
9import * as path from "path";
10import { Shared } from "../../shared";
11import { SystemConfig } from "../../shared/types";
12import { RagDynamoDBTables } from "../rag-dynamodb-tables";
13import { RemovalPolicy } from "aws-cdk-lib";
14
15export interface CreateOpenSearchWorkspaceProps {
16readonly config: SystemConfig;
17readonly shared: Shared;
18readonly ragDynamoDBTables: RagDynamoDBTables;
19readonly openSearchCollectionName: string;
20readonly openSearchCollection: oss.CfnCollection;
21readonly collectionEndpoint: string;
22}
23
24export class CreateOpenSearchWorkspace extends Construct {
25public readonly stateMachine: sfn.StateMachine;
26public readonly createWorkspaceRole?: iam.IRole;
27
28constructor(
29scope: Construct,
30id: string,
31props: CreateOpenSearchWorkspaceProps
32) {
33super(scope, id);
34
35const createFunction = new lambda.Function(
36this,
37"CreateOpenSearchWorkspaceFunction",
38{
39vpc: props.shared.vpc,
40code: props.shared.sharedCode.bundleWithLambdaAsset(
41path.join(__dirname, "./functions/create-workflow/create")
42),
43runtime: props.shared.pythonRuntime,
44architecture: props.shared.lambdaArchitecture,
45handler: "index.lambda_handler",
46layers: [props.shared.powerToolsLayer, props.shared.commonLayer],
47timeout: cdk.Duration.minutes(5),
48logRetention: logs.RetentionDays.ONE_WEEK,
49environment: {
50...props.shared.defaultEnvironmentVariables,
51WORKSPACES_TABLE_NAME:
52props.ragDynamoDBTables.workspacesTable.tableName,
53WORKSPACES_BY_OBJECT_TYPE_INDEX_NAME:
54props.ragDynamoDBTables.workspacesByObjectTypeIndexName,
55OPEN_SEARCH_COLLECTION_NAME: props.openSearchCollectionName,
56OPEN_SEARCH_COLLECTION_ENDPOINT: props.collectionEndpoint,
57OPEN_SEARCH_COLLECTION_ENDPOINT_PORT: "443",
58},
59}
60);
61
62props.ragDynamoDBTables.workspacesTable.grantReadWriteData(createFunction);
63createFunction.addToRolePolicy(
64new iam.PolicyStatement({
65actions: [
66"aoss:APIAccessAll",
67"aoss:DescribeIndex",
68"aoss:CreateIndex",
69],
70resources: [props.openSearchCollection.attrArn],
71})
72);
73
74const handleError = new tasks.DynamoUpdateItem(this, "HandleError", {
75table: props.ragDynamoDBTables.workspacesTable,
76key: {
77workspace_id: tasks.DynamoAttributeValue.fromString(
78sfn.JsonPath.stringAt("$.workspace_id")
79),
80object_type: tasks.DynamoAttributeValue.fromString("workspace"),
81},
82updateExpression: "set #status = :error",
83expressionAttributeNames: {
84"#status": "status",
85},
86expressionAttributeValues: {
87":error": tasks.DynamoAttributeValue.fromString("error"),
88},
89}).next(
90new sfn.Fail(this, "Fail", {
91cause: "Workspace creation failed",
92})
93);
94
95const setCreating = new tasks.DynamoUpdateItem(this, "SetCreating", {
96table: props.ragDynamoDBTables.workspacesTable,
97key: {
98workspace_id: tasks.DynamoAttributeValue.fromString(
99sfn.JsonPath.stringAt("$.workspace_id")
100),
101object_type: tasks.DynamoAttributeValue.fromString("workspace"),
102},
103updateExpression: "set #status=:statusValue",
104expressionAttributeNames: {
105"#status": "status",
106},
107expressionAttributeValues: {
108":statusValue": tasks.DynamoAttributeValue.fromString("creating"),
109},
110resultPath: sfn.JsonPath.DISCARD,
111});
112
113const setReady = new tasks.DynamoUpdateItem(this, "SetReady", {
114table: props.ragDynamoDBTables.workspacesTable,
115key: {
116workspace_id: tasks.DynamoAttributeValue.fromString(
117sfn.JsonPath.stringAt("$.workspace_id")
118),
119object_type: tasks.DynamoAttributeValue.fromString("workspace"),
120},
121updateExpression: "set #status=:statusValue",
122expressionAttributeNames: {
123"#status": "status",
124},
125expressionAttributeValues: {
126":statusValue": tasks.DynamoAttributeValue.fromString("ready"),
127},
128resultPath: sfn.JsonPath.DISCARD,
129});
130
131const createTask = new tasks.LambdaInvoke(this, "Create", {
132lambdaFunction: createFunction,
133resultPath: "$.createResult",
134}).addCatch(handleError, {
135errors: ["States.ALL"],
136resultPath: "$.createResult",
137});
138
139const workflow = setCreating
140.next(createTask)
141.next(setReady)
142.next(new sfn.Succeed(this, "Success"));
143
144const logGroup = new logs.LogGroup(
145this,
146"CreateOpenSearchWorkspaceSMLogGroup",
147{
148removalPolicy: RemovalPolicy.DESTROY,
149}
150);
151
152const stateMachine = new sfn.StateMachine(
153this,
154"CreateOpenSearchWorkspace",
155{
156definitionBody: sfn.DefinitionBody.fromChainable(workflow),
157timeout: cdk.Duration.minutes(5),
158comment: "Create OpenSearch Workspace Workflow",
159tracingEnabled: true,
160logs: {
161destination: logGroup,
162level: sfn.LogLevel.ALL,
163},
164}
165);
166
167this.stateMachine = stateMachine;
168this.createWorkspaceRole = createFunction.role;
169}
170}
171