Skip to content

Commit 2cf77c3

Browse files
committed
Merge remote-tracking branch 'origin/main' into delete_old_stacks_on_merge
2 parents 74aa535 + 6cab8d4 commit 2cf77c3

File tree

7 files changed

+235
-18
lines changed

7 files changed

+235
-18
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ jobs:
8080
PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
8181
DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
8282
REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
83-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
84-
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
83+
SLACK_BOT_TOKEN: ${{ secrets.DEV_SLACK_BOT_TOKEN }}
84+
SLACK_SIGNING_SECRET: ${{ secrets.DEV_SLACK_SIGNING_SECRET }}
8585

8686
release_qa:
8787
needs: [tag_release, package_code, release_dev]
@@ -109,5 +109,5 @@ jobs:
109109
PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
110110
DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
111111
REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
112-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
113-
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
112+
SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_BOT_TOKEN }}
113+
SLACK_SIGNING_SECRET: ${{ secrets.QA_SLACK_SIGNING_SECRET }}

.github/workflows/pull_request.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,5 @@ jobs:
104104
PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
105105
DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
106106
REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
107-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
108-
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
107+
SLACK_BOT_TOKEN: ${{ secrets.DEV_SLACK_BOT_TOKEN }}
108+
SLACK_SIGNING_SECRET: ${{ secrets.DEV_SLACK_SIGNING_SECRET }}

.github/workflows/release.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ jobs:
8484
PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
8585
DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
8686
REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
87-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
88-
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
87+
SLACK_BOT_TOKEN: ${{ secrets.DEV_SLACK_BOT_TOKEN }}
88+
SLACK_SIGNING_SECRET: ${{ secrets.DEV_SLACK_SIGNING_SECRET }}
8989

9090
release_qa:
9191
needs: [tag_release, package_code, release_dev]
@@ -113,8 +113,8 @@ jobs:
113113
PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
114114
DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
115115
REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
116-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
117-
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
116+
SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_BOT_TOKEN }}
117+
SLACK_SIGNING_SECRET: ${{ secrets.QA_SLACK_SIGNING_SECRET }}
118118

119119
release_int:
120120
needs: [tag_release, package_code, release_qa]
@@ -142,8 +142,8 @@ jobs:
142142
PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
143143
DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
144144
REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
145-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
146-
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
145+
SLACK_BOT_TOKEN: ${{ secrets.INT_SLACK_BOT_TOKEN }}
146+
SLACK_SIGNING_SECRET: ${{ secrets.INT_SLACK_SIGNING_SECRET }}
147147

148148
# TODO: uncomment when ready to release to prod
149149
# release_prod:
@@ -171,8 +171,8 @@ jobs:
171171
# PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE: ${{ secrets.PROD_CLOUD_FORMATION_CHECK_VERSION_ROLE }}
172172
# DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE: ${{ secrets.DEV_CLOUD_FORMATION_EXECUTE_LAMBDA_ROLE }}
173173
# REGRESSION_TESTS_PEM: ${{ secrets.REGRESSION_TESTS_PEM }}
174-
# SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
175-
# SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
174+
# SLACK_BOT_TOKEN: ${{ secrets.PROD_SLACK_BOT_TOKEN }}
175+
# SLACK_SIGNING_SECRET: ${{ secrets.PROD_SLACK_SIGNING_SECRET }}
176176
#
177177
# create_release_notes:
178178
# needs: [tag_release, package_code, get_commit_id, release_int, release_prod]
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import {Construct} from "constructs"
2+
import {Duration, CustomResource} from "aws-cdk-lib"
3+
import {Function, Runtime, Code} from "aws-cdk-lib/aws-lambda"
4+
import {Role, ServicePrincipal, ManagedPolicy} from "aws-cdk-lib/aws-iam"
5+
import {Provider} from "aws-cdk-lib/custom-resources"
6+
7+
export interface DelayResourceProps {
8+
/**
9+
* The delay time in seconds (default: 30 seconds)
10+
*/
11+
readonly delaySeconds?: number
12+
13+
/**
14+
* Optional description for the delay resource
15+
*/
16+
readonly description?: string
17+
}
18+
19+
/**
20+
* a fix for an annoying time sync issue that adds a configurable delay
21+
* to ensure AWS resources are fully available before dependent resources are created
22+
*/
23+
export class DelayResource extends Construct {
24+
public readonly customResource: CustomResource
25+
public readonly delaySeconds: number
26+
27+
constructor(scope: Construct, id: string, props: DelayResourceProps = {}) {
28+
super(scope, id)
29+
30+
this.delaySeconds = props.delaySeconds || 30
31+
32+
// create IAM role for the delay Lambda function
33+
const lambdaExecutionRole = new Role(this, "LambdaExecutionRole", {
34+
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
35+
description: "Execution role for delay custom resource Lambda function",
36+
managedPolicies: [
37+
ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")
38+
]
39+
})
40+
41+
// create the delay Lambda function with inline Python code
42+
const delayFunction = new Function(this, "DelayFunction", {
43+
runtime: Runtime.PYTHON_3_12,
44+
handler: "index.handler",
45+
role: lambdaExecutionRole,
46+
timeout: Duration.minutes(15), // max Lambda timeout to handle long delays
47+
description: props.description || `Delay resource for ${this.delaySeconds} seconds`,
48+
code: Code.fromInline(`
49+
from time import sleep
50+
import json
51+
import cfnresponse
52+
import uuid
53+
54+
def handler(event, context):
55+
wait_seconds = 0
56+
id = str(uuid.uuid1())
57+
58+
print(f"Received event: {json.dumps(event, default=str)}")
59+
60+
try:
61+
if event["RequestType"] in ["Create", "Update"]:
62+
wait_seconds = int(event["ResourceProperties"].get("WaitSeconds", 0))
63+
print(f"Waiting for {wait_seconds} seconds...")
64+
sleep(wait_seconds)
65+
print(f"Wait complete")
66+
67+
response = {
68+
"TimeWaited": wait_seconds,
69+
"Id": id,
70+
"Status": "SUCCESS"
71+
}
72+
73+
cfnresponse.send(event, context, cfnresponse.SUCCESS, response, f"Waiter-{id}")
74+
75+
except Exception as e:
76+
print(f"Error: {str(e)}")
77+
cfnresponse.send(event, context, cfnresponse.FAILED, {"Error": str(e)}, f"Waiter-{id}")
78+
`)
79+
})
80+
81+
// create the custom resource provider
82+
const provider = new Provider(this, "DelayProvider", {
83+
onEventHandler: delayFunction
84+
})
85+
86+
// create the custom resource that triggers the delay
87+
this.customResource = new CustomResource(this, "DelayCustomResource", {
88+
serviceToken: provider.serviceToken,
89+
properties: {
90+
WaitSeconds: this.delaySeconds,
91+
Description: props.description || `Delay for ${this.delaySeconds} seconds`,
92+
// timestamp to ensure updates trigger when properties change
93+
Timestamp: Date.now()
94+
}
95+
})
96+
}
97+
98+
}

packages/cdk/nagSuppressions.ts

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-len */
12

23
import {Stack} from "aws-cdk-lib"
34
import {NagPackSuppression, NagSuppressions} from "cdk-nag"
@@ -160,7 +161,8 @@ export const nagSuppressions = (stack: Stack) => {
160161
})
161162

162163
const logRetentionHandlers = stack.node.findAll().filter(node =>
163-
node.node.id.startsWith("LogRetention")
164+
node.node.id.startsWith("LogRetention") &&
165+
!node.node.path.includes("DelayProvider")
164166
)
165167

166168
logRetentionHandlers.forEach(handler => {
@@ -187,6 +189,97 @@ export const nagSuppressions = (stack: Stack) => {
187189
)
188190
})
189191

192+
// Suppress DelayResource IAM and runtime issues
193+
safeAddNagSuppression(
194+
stack,
195+
"/EpsAssistMeStack/VectorIndex/PolicySyncWait/LambdaExecutionRole/Resource",
196+
[
197+
{
198+
id: "AwsSolutions-IAM4",
199+
reason: "DelayResource Lambda uses AWS managed policy for basic Lambda execution role."
200+
}
201+
]
202+
)
203+
204+
safeAddNagSuppression(
205+
stack,
206+
"/EpsAssistMeStack/VectorIndex/IndexReadyWait/LambdaExecutionRole/Resource",
207+
[
208+
{
209+
id: "AwsSolutions-IAM4",
210+
reason: "DelayResource Lambda uses AWS managed policy for basic Lambda execution role."
211+
}
212+
]
213+
)
214+
215+
// Suppress DelayProvider framework ServiceRole issues
216+
safeAddNagSuppression(
217+
stack,
218+
"/EpsAssistMeStack/VectorIndex/PolicySyncWait/DelayProvider/framework-onEvent/ServiceRole/Resource",
219+
[
220+
{
221+
id: "AwsSolutions-IAM4",
222+
reason: "Auto-generated CDK Provider role uses AWS managed policy for Lambda execution."
223+
}
224+
]
225+
)
226+
227+
safeAddNagSuppression(
228+
stack,
229+
"/EpsAssistMeStack/VectorIndex/PolicySyncWait/DelayProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource",
230+
[
231+
{
232+
id: "AwsSolutions-IAM5",
233+
reason: "Auto-generated CDK Provider role requires wildcard permissions for Lambda invocation."
234+
}
235+
]
236+
)
237+
238+
safeAddNagSuppression(
239+
stack,
240+
"/EpsAssistMeStack/VectorIndex/IndexReadyWait/DelayProvider/framework-onEvent/ServiceRole/Resource",
241+
[
242+
{
243+
id: "AwsSolutions-IAM4",
244+
reason: "Auto-generated CDK Provider role uses AWS managed policy for Lambda execution."
245+
}
246+
]
247+
)
248+
249+
safeAddNagSuppression(
250+
stack,
251+
"/EpsAssistMeStack/VectorIndex/IndexReadyWait/DelayProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource",
252+
[
253+
{
254+
id: "AwsSolutions-IAM5",
255+
reason: "Auto-generated CDK Provider role requires wildcard permissions for Lambda invocation."
256+
}
257+
]
258+
)
259+
260+
// Suppress DelayFunction runtime version warnings
261+
safeAddNagSuppression(
262+
stack,
263+
"/EpsAssistMeStack/VectorIndex/PolicySyncWait/DelayFunction/Resource",
264+
[
265+
{
266+
id: "AwsSolutions-L1",
267+
reason: "DelayResource uses Python 3.12 which is the latest stable runtime available for the delay functionality."
268+
}
269+
]
270+
)
271+
272+
safeAddNagSuppression(
273+
stack,
274+
"/EpsAssistMeStack/VectorIndex/IndexReadyWait/DelayFunction/Resource",
275+
[
276+
{
277+
id: "AwsSolutions-L1",
278+
reason: "DelayResource uses Python 3.12 which is the latest stable runtime available for the delay functionality."
279+
}
280+
]
281+
)
282+
190283
}
191284

192285
const safeAddNagSuppression = (stack: Stack, path: string, suppressions: Array<NagPackSuppression>) => {

packages/cdk/resources/VectorIndex.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Construct} from "constructs"
22
import {CfnIndex} from "aws-cdk-lib/aws-opensearchserverless"
33
import {VectorCollection} from "@cdklabs/generative-ai-cdk-constructs/lib/cdk-lib/opensearchserverless"
44
import {RemovalPolicy} from "aws-cdk-lib"
5+
import {DelayResource} from "../constructs/DelayResource"
56

67
export interface VectorIndexProps {
78
readonly stackName: string
@@ -11,6 +12,8 @@ export interface VectorIndexProps {
1112
export class VectorIndex extends Construct {
1213
public readonly cfnIndex: CfnIndex
1314
public readonly indexName: string
15+
public readonly policySyncWait: DelayResource
16+
public readonly indexReadyWait: DelayResource
1417

1518
constructor(scope: Construct, id: string, props: VectorIndexProps) {
1619
super(scope, id)
@@ -64,8 +67,31 @@ export class VectorIndex extends Construct {
6467
}
6568
})
6669

67-
this.cfnIndex = cfnIndex
70+
// a fix for an annoying time sync issue that adds a small delay
71+
// to ensure data access policies are synced before index creation
72+
const policySyncWait = new DelayResource(this, "PolicySyncWait", {
73+
delaySeconds: 15,
74+
description: "Wait for OpenSearch data access policies to sync"
75+
})
76+
77+
policySyncWait.customResource.node.addDependency(props.collection.dataAccessPolicy)
78+
79+
// Index depends on policy sync wait instead of directly on dataAccessPolicy
80+
cfnIndex.node.addDependency(policySyncWait.customResource)
81+
82+
cfnIndex.applyRemovalPolicy(RemovalPolicy.DESTROY)
6883

69-
this.cfnIndex.applyRemovalPolicy(RemovalPolicy.DESTROY)
84+
// a fix for an annoying time sync issue that adds a small delay
85+
// to ensure index is actually available for Bedrock
86+
const indexReadyWait = new DelayResource(this, "IndexReadyWait", {
87+
delaySeconds: 30,
88+
description: "Wait for OpenSearch index to be fully available"
89+
})
90+
91+
indexReadyWait.customResource.node.addDependency(cfnIndex)
92+
93+
this.cfnIndex = cfnIndex
94+
this.policySyncWait = policySyncWait
95+
this.indexReadyWait = indexReadyWait
7096
}
7197
}

packages/cdk/stacks/EpsAssistMeStack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export class EpsAssistMeStack extends Stack {
105105
account
106106
})
107107

108-
vectorKB.knowledgeBase.node.addDependency(vectorIndex.cfnIndex)
108+
vectorKB.knowledgeBase.node.addDependency(vectorIndex.indexReadyWait.customResource)
109109

110110
// Create runtime policies with resource dependencies
111111
const runtimePolicies = new RuntimePolicies(this, "RuntimePolicies", {

0 commit comments

Comments
 (0)