@aws/nx-plugin 0.45.1 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +3669 -0
- package/src/py/fast-api/generator.js +57 -50
- package/src/py/fast-api/generator.js.map +1 -1
- package/src/py/fast-api/schema.d.ts +1 -0
- package/src/py/fast-api/schema.json +8 -0
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +590 -0
- package/src/py/mcp-server/generator.js +4 -18
- package/src/py/mcp-server/generator.js.map +1 -1
- package/src/py/mcp-server/schema.d.ts +1 -0
- package/src/py/mcp-server/schema.json +8 -0
- package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +590 -0
- package/src/py/strands-agent/generator.js +4 -18
- package/src/py/strands-agent/generator.js.map +1 -1
- package/src/py/strands-agent/schema.d.ts +1 -0
- package/src/py/strands-agent/schema.json +8 -0
- package/src/terraform/project/generator.js +23 -7
- package/src/terraform/project/generator.js.map +1 -1
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +3669 -0
- package/src/trpc/backend/generator.js +6 -17
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/backend/schema.d.ts +1 -0
- package/src/trpc/backend/schema.json +8 -0
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +590 -0
- package/src/ts/mcp-server/generator.js +4 -18
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/mcp-server/schema.d.ts +1 -0
- package/src/ts/mcp-server/schema.json +8 -0
- package/src/ts/nx-plugin/generator.js +1 -0
- package/src/ts/nx-plugin/generator.js.map +1 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +11 -5
- package/src/utils/agent-core-constructs/agent-core-constructs.js +51 -10
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +46 -0
- package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +536 -0
- package/src/utils/api-constructs/api-constructs.d.ts +4 -4
- package/src/utils/api-constructs/api-constructs.js +45 -5
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +382 -0
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +508 -0
- package/src/utils/api-constructs/files/terraform/core/api/http/http-api/http-api.tf.template +250 -0
- package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +150 -0
- package/src/utils/files/terraform/src/metrics/metrics.tf.template +3 -2
- package/src/utils/py.d.ts +5 -0
- package/src/utils/py.js +9 -1
- package/src/utils/py.js.map +1 -1
- package/src/utils/shared-constructs-constants.d.ts +2 -0
- package/src/utils/shared-constructs-constants.js +3 -1
- package/src/utils/shared-constructs-constants.js.map +1 -1
- package/src/utils/shared-constructs.js +2 -2
- package/src/utils/shared-constructs.js.map +1 -1
- package/src/utils/versions.d.ts +3 -1
- package/src/utils/versions.js +2 -0
- package/src/utils/versions.js.map +1 -1
- /package/src/utils/agent-core-constructs/files/{app → cdk/app}/agent-core/__nameKebabCase__/Dockerfile.template +0 -0
- /package/src/utils/agent-core-constructs/files/{app → cdk/app}/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +0 -0
- /package/src/utils/agent-core-constructs/files/{core → cdk/core}/agent-core/runtime.ts.template +0 -0
- /package/src/utils/api-constructs/files/{app → cdk/app}/apis/http/__apiNameKebabCase__.ts.template +0 -0
- /package/src/utils/api-constructs/files/{app → cdk/app}/apis/rest/__apiNameKebabCase__.ts.template +0 -0
- /package/src/utils/api-constructs/files/{core → cdk/core}/api/http/http-api.ts.template +0 -0
- /package/src/utils/api-constructs/files/{core → cdk/core}/api/rest/rest-api.ts.template +0 -0
- /package/src/utils/api-constructs/files/{core → cdk/core}/api/trpc/trpc-utils.ts.template +0 -0
- /package/src/utils/api-constructs/files/{core → cdk/core}/api/utils/utils.ts.template +0 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
terraform {
|
|
2
|
+
required_version = ">= 1.0"
|
|
3
|
+
|
|
4
|
+
required_providers {
|
|
5
|
+
aws = {
|
|
6
|
+
source = "hashicorp/aws"
|
|
7
|
+
version = ">= 6.0"
|
|
8
|
+
}
|
|
9
|
+
null = {
|
|
10
|
+
source = "hashicorp/null"
|
|
11
|
+
version = ">= 3.0"
|
|
12
|
+
}
|
|
13
|
+
local = {
|
|
14
|
+
source = "hashicorp/local"
|
|
15
|
+
version = ">= 2.0"
|
|
16
|
+
}
|
|
17
|
+
random = {
|
|
18
|
+
source = "hashicorp/random"
|
|
19
|
+
version = ">= 3.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Variables
|
|
25
|
+
variable "agent_runtime_name" {
|
|
26
|
+
description = "Name of the agent runtime"
|
|
27
|
+
type = string
|
|
28
|
+
validation {
|
|
29
|
+
condition = can(regex("^[a-zA-Z][a-zA-Z0-9_]{0,42}$", var.agent_runtime_name))
|
|
30
|
+
error_message = "Value must start with a letter and contain only letters, numbers, and underscores (1-43 characters)."
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
variable "server_protocol" {
|
|
35
|
+
description = "Whether this is an Agent (HTTP) or MCP Server (MCP)"
|
|
36
|
+
type = string
|
|
37
|
+
validation {
|
|
38
|
+
condition = contains(["MCP", "HTTP"], var.server_protocol)
|
|
39
|
+
error_message = "Protocol type must be either 'MCP' or 'HTTP'."
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
variable "customJWTAuthorizer" {
|
|
44
|
+
description = "Custom JWTAuthorizer Configuration"
|
|
45
|
+
type = object({
|
|
46
|
+
discoveryUrl = optional(string)
|
|
47
|
+
allowedAudience = optional(list(string))
|
|
48
|
+
allowedClients = optional(list(string))
|
|
49
|
+
})
|
|
50
|
+
default = null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
variable "docker_image_tag" {
|
|
54
|
+
description = "Name of the docker image tag to use as the agent core runtime"
|
|
55
|
+
type = string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
variable "env" {
|
|
59
|
+
description = "Environment variables to pass to the agent core runtime"
|
|
60
|
+
type = map(string)
|
|
61
|
+
default = {}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
variable "additional_iam_policy_statements" {
|
|
65
|
+
description = "Additional IAM policy statements to attach to the agent core runtime role"
|
|
66
|
+
type = list(object({
|
|
67
|
+
Effect = string
|
|
68
|
+
Action = list(string)
|
|
69
|
+
Resource = list(string)
|
|
70
|
+
}))
|
|
71
|
+
default = []
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
variable "tags" {
|
|
75
|
+
description = "Tags to apply to resources"
|
|
76
|
+
type = map(string)
|
|
77
|
+
default = {}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Data sources
|
|
81
|
+
data "aws_caller_identity" "current" {}
|
|
82
|
+
data "aws_region" "current" {}
|
|
83
|
+
|
|
84
|
+
locals {
|
|
85
|
+
aws_account_id = data.aws_caller_identity.current.account_id
|
|
86
|
+
aws_region = data.aws_region.current.name
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Random ID for bucket suffix to ensure uniqueness
|
|
90
|
+
resource "random_id" "unique_suffix" {
|
|
91
|
+
byte_length = 4
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# ECR Repository
|
|
95
|
+
resource "aws_ecr_repository" "agent_core_repository" {
|
|
96
|
+
#checkov:skip=CKV_AWS_136:AES256 encryption is sufficient for ECR repositories
|
|
97
|
+
name = "${lower(var.agent_runtime_name)}_repository_${random_id.unique_suffix.hex}"
|
|
98
|
+
|
|
99
|
+
#checkov:skip=CKV_AWS_51:Image tag is reused for latest deployments
|
|
100
|
+
image_tag_mutability = "MUTABLE"
|
|
101
|
+
force_delete = true
|
|
102
|
+
|
|
103
|
+
image_scanning_configuration {
|
|
104
|
+
scan_on_push = true
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
tags = var.tags
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# ECR Repository Policy
|
|
111
|
+
resource "aws_ecr_repository_policy" "agent_core_ecr_policy" {
|
|
112
|
+
repository = aws_ecr_repository.agent_core_repository.name
|
|
113
|
+
|
|
114
|
+
policy = jsonencode({
|
|
115
|
+
Version = "2012-10-17"
|
|
116
|
+
Statement = [
|
|
117
|
+
{
|
|
118
|
+
Sid = "AllowPushPull"
|
|
119
|
+
Effect = "Allow"
|
|
120
|
+
Principal = {
|
|
121
|
+
AWS = "arn:aws:iam::${local.aws_account_id}:root"
|
|
122
|
+
}
|
|
123
|
+
Action = [
|
|
124
|
+
"ecr:GetDownloadUrlForLayer",
|
|
125
|
+
"ecr:BatchGetImage",
|
|
126
|
+
"ecr:BatchCheckLayerAvailability",
|
|
127
|
+
"ecr:PutImage",
|
|
128
|
+
"ecr:InitiateLayerUpload",
|
|
129
|
+
"ecr:UploadLayerPart",
|
|
130
|
+
"ecr:CompleteLayerUpload"
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
# IAM Role for Agent Core Runtime
|
|
138
|
+
resource "aws_iam_role" "agent_core_runtime_role" {
|
|
139
|
+
name = "${var.agent_runtime_name}-AgentCoreRuntimeRole-${random_id.unique_suffix.hex}"
|
|
140
|
+
|
|
141
|
+
assume_role_policy = jsonencode({
|
|
142
|
+
Version = "2012-10-17"
|
|
143
|
+
Statement = [
|
|
144
|
+
{
|
|
145
|
+
Sid = "AgentCoreAssumeRolePolicy"
|
|
146
|
+
Effect = "Allow"
|
|
147
|
+
Principal = {
|
|
148
|
+
Service = "bedrock-agentcore.amazonaws.com"
|
|
149
|
+
}
|
|
150
|
+
Action = "sts:AssumeRole"
|
|
151
|
+
Condition = {
|
|
152
|
+
StringEquals = {
|
|
153
|
+
"aws:SourceAccount" = local.aws_account_id
|
|
154
|
+
}
|
|
155
|
+
ArnLike = {
|
|
156
|
+
"aws:SourceArn" = "arn:aws:bedrock-agentcore:${local.aws_region}:${local.aws_account_id}:*"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
tags = var.tags
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# IAM Policy for Query Agent with restricted Athena permissions
|
|
167
|
+
resource "aws_iam_policy" "agent_core_runtime_policy" {
|
|
168
|
+
name = "${var.agent_runtime_name}-QueryAgentPolicy-${random_id.unique_suffix.hex}"
|
|
169
|
+
description = "Restricted policy for Agent"
|
|
170
|
+
|
|
171
|
+
policy = jsonencode({
|
|
172
|
+
Version = "2012-10-17"
|
|
173
|
+
Statement = concat([
|
|
174
|
+
{
|
|
175
|
+
Sid = "ECRImageAccess"
|
|
176
|
+
Effect = "Allow"
|
|
177
|
+
Action = [
|
|
178
|
+
"ecr:BatchGetImage",
|
|
179
|
+
"ecr:GetDownloadUrlForLayer"
|
|
180
|
+
]
|
|
181
|
+
Resource = [
|
|
182
|
+
"arn:aws:ecr:${local.aws_region}:${local.aws_account_id}:repository/*"
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
Sid = "ECRTokenAccess"
|
|
187
|
+
Effect = "Allow"
|
|
188
|
+
Action = [
|
|
189
|
+
"ecr:GetAuthorizationToken"
|
|
190
|
+
]
|
|
191
|
+
Resource = [
|
|
192
|
+
"*"
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"Effect" : "Allow",
|
|
197
|
+
"Action" : [
|
|
198
|
+
"logs:DescribeLogStreams",
|
|
199
|
+
"logs:CreateLogGroup"
|
|
200
|
+
],
|
|
201
|
+
"Resource" : [
|
|
202
|
+
"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:log-group:/aws/bedrock-agentcore/runtimes/*"
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"Effect" : "Allow",
|
|
207
|
+
"Action" : [
|
|
208
|
+
"logs:DescribeLogGroups"
|
|
209
|
+
],
|
|
210
|
+
"Resource" : [
|
|
211
|
+
"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:log-group:*"
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"Effect" : "Allow",
|
|
216
|
+
"Action" : [
|
|
217
|
+
"logs:CreateLogStream",
|
|
218
|
+
"logs:PutLogEvents"
|
|
219
|
+
],
|
|
220
|
+
"Resource" : [
|
|
221
|
+
"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*"
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"Effect" : "Allow",
|
|
226
|
+
"Action" : [
|
|
227
|
+
"xray:PutTraceSegments",
|
|
228
|
+
"xray:PutTelemetryRecords",
|
|
229
|
+
"xray:GetSamplingRules",
|
|
230
|
+
"xray:GetSamplingTargets"
|
|
231
|
+
],
|
|
232
|
+
"Resource" : ["*"]
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"Effect" : "Allow",
|
|
236
|
+
"Resource" : "*",
|
|
237
|
+
"Action" : "cloudwatch:PutMetricData",
|
|
238
|
+
"Condition" : {
|
|
239
|
+
"StringEquals" : {
|
|
240
|
+
"cloudwatch:namespace" : "bedrock-agentcore"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"Sid" : "GetAgentAccessToken",
|
|
246
|
+
"Effect" : "Allow",
|
|
247
|
+
"Action" : [
|
|
248
|
+
"bedrock-agentcore:GetWorkloadAccessToken",
|
|
249
|
+
"bedrock-agentcore:GetWorkloadAccessTokenForJWT",
|
|
250
|
+
"bedrock-agentcore:GetWorkloadAccessTokenForUserId"
|
|
251
|
+
],
|
|
252
|
+
"Resource" : [
|
|
253
|
+
"arn:aws:bedrock-agentcore:${local.aws_region}:${local.aws_account_id}:workload-identity-directory/default",
|
|
254
|
+
"arn:aws:bedrock-agentcore:${local.aws_region}:${local.aws_account_id}:workload-identity-directory/default/workload-identity/*"
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
{ "Sid" : "BedrockModelInvocation",
|
|
258
|
+
"Effect" : "Allow",
|
|
259
|
+
"Action" : [
|
|
260
|
+
"bedrock:InvokeModel",
|
|
261
|
+
"bedrock:InvokeModelWithResponseStream"
|
|
262
|
+
],
|
|
263
|
+
"Resource" : [
|
|
264
|
+
"arn:aws:bedrock:*::foundation-model/*",
|
|
265
|
+
"arn:aws:bedrock:${local.aws_region}:${local.aws_account_id}:*"
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
], var.additional_iam_policy_statements)
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
tags = var.tags
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
# Attach the restricted policy to the role
|
|
275
|
+
resource "aws_iam_role_policy_attachment" "agent_core_policy" {
|
|
276
|
+
role = aws_iam_role.agent_core_runtime_role.name
|
|
277
|
+
policy_arn = aws_iam_policy.agent_core_runtime_policy.arn
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
data "external" "docker_digest" {
|
|
281
|
+
program = ["sh", "-c", "echo '{\"digest\":\"'$(docker inspect ${var.docker_image_tag} --format '{{.Descriptor.digest}}')'\"}' "]
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
# Null resource for Docker publish
|
|
285
|
+
resource "null_resource" "docker_publish" {
|
|
286
|
+
triggers = {
|
|
287
|
+
# Trigger rebuild when the image changes
|
|
288
|
+
docker_digest = data.external.docker_digest.result.digest
|
|
289
|
+
|
|
290
|
+
repository_url = aws_ecr_repository.agent_core_repository.repository_url
|
|
291
|
+
docker_image_tag = var.docker_image_tag
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
provisioner "local-exec" {
|
|
295
|
+
command = <<-EOT
|
|
296
|
+
# Get ECR login token
|
|
297
|
+
aws ecr get-login-password --region ${local.aws_region} | docker login --username AWS --password-stdin ${self.triggers.repository_url}
|
|
298
|
+
|
|
299
|
+
# Tag the image
|
|
300
|
+
docker tag ${self.triggers.docker_image_tag} ${self.triggers.repository_url}:latest
|
|
301
|
+
|
|
302
|
+
# Push the image
|
|
303
|
+
docker push ${self.triggers.repository_url}:latest
|
|
304
|
+
EOT
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
depends_on = [aws_ecr_repository_policy.agent_core_ecr_policy]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Null resource for agent core deployment with proper lifecycle management
|
|
311
|
+
resource "null_resource" "agent_core_runtime_deployment" {
|
|
312
|
+
triggers = {
|
|
313
|
+
container_uri = "${aws_ecr_repository.agent_core_repository.repository_url}:latest"
|
|
314
|
+
role_arn = aws_iam_role.agent_core_runtime_role.arn
|
|
315
|
+
config_hash = md5(join("", [jsonencode(var.customJWTAuthorizer), var.server_protocol]))
|
|
316
|
+
env_hash = md5(jsonencode(var.env))
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
provisioner "local-exec" {
|
|
320
|
+
command = <<-EOT
|
|
321
|
+
uv run --with boto3 python -c '
|
|
322
|
+
import boto3
|
|
323
|
+
import json
|
|
324
|
+
import sys
|
|
325
|
+
|
|
326
|
+
# Create the client
|
|
327
|
+
client = boto3.client("bedrock-agentcore-control", region_name="${local.aws_region}")
|
|
328
|
+
|
|
329
|
+
# Environment variables for QueryAgentConfig
|
|
330
|
+
environment_variables = json.loads("""${jsonencode(var.env)}""")
|
|
331
|
+
agent_name = "${var.agent_runtime_name}_${random_id.unique_suffix.hex}"
|
|
332
|
+
authorization_config = json.loads("""{"customJWTAuthorizer": ${jsonencode(var.customJWTAuthorizer != null ? {
|
|
333
|
+
for k, v in var.customJWTAuthorizer : k => v if v != null
|
|
334
|
+
} : {})}}""")
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
# First, check if an agent runtime with this name already exists
|
|
338
|
+
existing_agent_runtime_id = None
|
|
339
|
+
try:
|
|
340
|
+
list_response = client.list_agent_runtimes()
|
|
341
|
+
for runtime in list_response.get("agentRuntimes", []):
|
|
342
|
+
if runtime.get("agentRuntimeName") == agent_name:
|
|
343
|
+
existing_agent_runtime_id = runtime.get("agentRuntimeId")
|
|
344
|
+
print(f"Found existing agent runtime with ID: {existing_agent_runtime_id}")
|
|
345
|
+
break
|
|
346
|
+
except Exception as e:
|
|
347
|
+
print(f"Error listing agent runtimes: {e}")
|
|
348
|
+
|
|
349
|
+
if existing_agent_runtime_id:
|
|
350
|
+
# Update the existing agent runtime
|
|
351
|
+
try:
|
|
352
|
+
update_response = client.update_agent_runtime(
|
|
353
|
+
agentRuntimeId=existing_agent_runtime_id,
|
|
354
|
+
agentRuntimeArtifact={
|
|
355
|
+
"containerConfiguration": {
|
|
356
|
+
"containerUri": "${aws_ecr_repository.agent_core_repository.repository_url}:latest"
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
environmentVariables=environment_variables,
|
|
360
|
+
networkConfiguration={"networkMode": "PUBLIC"},
|
|
361
|
+
protocolConfiguration={"serverProtocol": "${var.server_protocol}"},
|
|
362
|
+
${var.customJWTAuthorizer == null ? "" : "authorizerConfiguration=authorization_config,"}
|
|
363
|
+
roleArn="${aws_iam_role.agent_core_runtime_role.arn}"
|
|
364
|
+
)
|
|
365
|
+
agent_runtime_id = existing_agent_runtime_id
|
|
366
|
+
print(f"Agent runtime updated successfully: {agent_runtime_id}")
|
|
367
|
+
except Exception as e:
|
|
368
|
+
print(f"Error updating agent runtime: {e}")
|
|
369
|
+
# If update fails, try to create a new one
|
|
370
|
+
existing_agent_runtime_id = None
|
|
371
|
+
|
|
372
|
+
if not existing_agent_runtime_id:
|
|
373
|
+
# Agent runtime doesn"t exist or update failed, create it
|
|
374
|
+
response = client.create_agent_runtime(
|
|
375
|
+
agentRuntimeName=agent_name,
|
|
376
|
+
agentRuntimeArtifact={
|
|
377
|
+
"containerConfiguration": {
|
|
378
|
+
"containerUri": "${aws_ecr_repository.agent_core_repository.repository_url}:latest"
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
environmentVariables=environment_variables,
|
|
382
|
+
networkConfiguration={"networkMode": "PUBLIC"},
|
|
383
|
+
protocolConfiguration={"serverProtocol": "${var.server_protocol}"},
|
|
384
|
+
${var.customJWTAuthorizer == null ? "" : "authorizerConfiguration=authorization_config,"}
|
|
385
|
+
roleArn="${aws_iam_role.agent_core_runtime_role.arn}"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
agent_runtime_id = response.get("agentRuntimeId", "")
|
|
389
|
+
print(f"Agent runtime created successfully with ID: {agent_runtime_id}")
|
|
390
|
+
|
|
391
|
+
except Exception as e:
|
|
392
|
+
print(f"Error managing agent runtime: {str(e)}")
|
|
393
|
+
sys.exit(1)
|
|
394
|
+
'
|
|
395
|
+
EOT
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
depends_on = [
|
|
399
|
+
null_resource.docker_publish,
|
|
400
|
+
aws_iam_role_policy_attachment.agent_core_policy
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
# Null resource for cleanup/destroy
|
|
406
|
+
resource "null_resource" "agent_core_cleanup" {
|
|
407
|
+
triggers = {
|
|
408
|
+
aws_region = local.aws_region
|
|
409
|
+
agent_name = var.agent_runtime_name
|
|
410
|
+
unique_suffix = random_id.unique_suffix.hex
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
provisioner "local-exec" {
|
|
414
|
+
when = destroy
|
|
415
|
+
command = <<-EOT
|
|
416
|
+
uv run --with boto3 python -c "
|
|
417
|
+
import boto3
|
|
418
|
+
import json
|
|
419
|
+
import os
|
|
420
|
+
|
|
421
|
+
# Create the client
|
|
422
|
+
client = boto3.client('bedrock-agentcore-control', region_name='${self.triggers.aws_region}')
|
|
423
|
+
|
|
424
|
+
agent_name = '${self.triggers.agent_name}_${self.triggers.unique_suffix}'
|
|
425
|
+
|
|
426
|
+
try:
|
|
427
|
+
# Find the agent runtime by name
|
|
428
|
+
agent_runtime_id = None
|
|
429
|
+
try:
|
|
430
|
+
list_response = client.list_agent_runtimes()
|
|
431
|
+
for runtime in list_response.get('agentRuntimes', []):
|
|
432
|
+
if runtime.get('agentRuntimeName') == agent_name:
|
|
433
|
+
agent_runtime_id = runtime.get('agentRuntimeId')
|
|
434
|
+
print(f'Found agent runtime to delete: {agent_name} (ID: {agent_runtime_id})')
|
|
435
|
+
break
|
|
436
|
+
except Exception as e:
|
|
437
|
+
print(f'Error listing agent runtimes: {e}')
|
|
438
|
+
|
|
439
|
+
if not agent_runtime_id:
|
|
440
|
+
print(f'No agent runtime found with name: {agent_name}')
|
|
441
|
+
exit(0)
|
|
442
|
+
|
|
443
|
+
# Delete the agent runtime using the found ID
|
|
444
|
+
response = client.delete_agent_runtime(
|
|
445
|
+
agentRuntimeId=agent_runtime_id
|
|
446
|
+
)
|
|
447
|
+
print(f'Agent runtime {agent_name} (ID: {agent_runtime_id}) deleted successfully:', json.dumps(response, indent=2, default=str))
|
|
448
|
+
|
|
449
|
+
except client.exceptions.ResourceNotFoundException:
|
|
450
|
+
print(f'Agent runtime {agent_name} not found, may have been already deleted')
|
|
451
|
+
except Exception as e:
|
|
452
|
+
print(f'Error deleting agent runtime {agent_name}:', str(e))
|
|
453
|
+
# Don't exit with error code during destroy to avoid blocking cleanup
|
|
454
|
+
"
|
|
455
|
+
EOT
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
depends_on = [null_resource.agent_core_runtime_deployment]
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
# Data source to find the agent runtime by name and get its ID
|
|
462
|
+
data "external" "agent_runtime_lookup" {
|
|
463
|
+
program = ["uv", "run", "--with", "boto3", "python", "-c", <<-EOT
|
|
464
|
+
import boto3
|
|
465
|
+
import json
|
|
466
|
+
import sys
|
|
467
|
+
|
|
468
|
+
# Create the client
|
|
469
|
+
client = boto3.client("bedrock-agentcore-control", region_name="${local.aws_region}")
|
|
470
|
+
|
|
471
|
+
agent_name = "${var.agent_runtime_name}_${random_id.unique_suffix.hex}"
|
|
472
|
+
|
|
473
|
+
try:
|
|
474
|
+
# Find the agent runtime by name
|
|
475
|
+
list_response = client.list_agent_runtimes()
|
|
476
|
+
for runtime in list_response.get("agentRuntimes", []):
|
|
477
|
+
if runtime.get("agentRuntimeName") == agent_name:
|
|
478
|
+
agent_runtime_id = runtime.get("agentRuntimeId")
|
|
479
|
+
runtime_arn = f"arn:aws:bedrock-agentcore:${local.aws_region}:${local.aws_account_id}:runtime/{agent_runtime_id}"
|
|
480
|
+
|
|
481
|
+
result = {
|
|
482
|
+
"agent_runtime_id": agent_runtime_id,
|
|
483
|
+
"agent_runtime_arn": runtime_arn,
|
|
484
|
+
"agent_name": agent_name
|
|
485
|
+
}
|
|
486
|
+
print(json.dumps(result))
|
|
487
|
+
sys.exit(0)
|
|
488
|
+
|
|
489
|
+
# If not found, return empty values
|
|
490
|
+
result = {
|
|
491
|
+
"agent_runtime_id": "",
|
|
492
|
+
"agent_runtime_arn": "",
|
|
493
|
+
"agent_name": agent_name
|
|
494
|
+
}
|
|
495
|
+
print(json.dumps(result))
|
|
496
|
+
|
|
497
|
+
except Exception as e:
|
|
498
|
+
print(f"Error looking up agent runtime: {str(e)}", file=sys.stderr)
|
|
499
|
+
# Return empty values on error to avoid breaking Terraform
|
|
500
|
+
result = {
|
|
501
|
+
"agent_runtime_id": "",
|
|
502
|
+
"agent_runtime_arn": "",
|
|
503
|
+
"agent_name": agent_name
|
|
504
|
+
}
|
|
505
|
+
print(json.dumps(result))
|
|
506
|
+
EOT
|
|
507
|
+
]
|
|
508
|
+
|
|
509
|
+
depends_on = [null_resource.agent_core_runtime_deployment]
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
# Outputs
|
|
513
|
+
output "agent_core_runtime_role_arn" {
|
|
514
|
+
description = "ARN of the Agent Core Runtime IAM role"
|
|
515
|
+
value = aws_iam_role.agent_core_runtime_role.arn
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
output "agent_core_runtime_role_name" {
|
|
519
|
+
description = "Name of the Agent Core Runtime IAM role"
|
|
520
|
+
value = aws_iam_role.agent_core_runtime_role.name
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
output "agent_runtime_name" {
|
|
524
|
+
description = "Name of the deployed agent runtime"
|
|
525
|
+
value = "${var.agent_runtime_name}-${random_id.unique_suffix.hex}"
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
output "agent_core_runtime_arn" {
|
|
529
|
+
description = "ARN of the Bedrock Agent Core runtime"
|
|
530
|
+
value = data.external.agent_runtime_lookup.result.agent_runtime_arn
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
output "agent_runtime_id" {
|
|
534
|
+
description = "ID of the Bedrock Agent Core runtime"
|
|
535
|
+
value = data.external.agent_runtime_lookup.result.agent_runtime_id
|
|
536
|
+
}
|
|
@@ -17,14 +17,14 @@ export interface FastApiBackendOptions extends BackendOptions {
|
|
|
17
17
|
dir: string;
|
|
18
18
|
}
|
|
19
19
|
export interface AddApiGatewayConstructOptions {
|
|
20
|
+
apiProjectName: string;
|
|
20
21
|
apiNameClassName: string;
|
|
21
22
|
apiNameKebabCase: string;
|
|
22
23
|
constructType: 'http' | 'rest';
|
|
23
24
|
backend: TrpcBackendOptions | FastApiBackendOptions;
|
|
24
25
|
auth: 'IAM' | 'Cognito' | 'None';
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export declare const addApiGatewayConstruct: (tree: Tree, options: AddApiGatewayConstructOptions) => void;
|
|
27
|
+
export declare const addApiGatewayInfra: (tree: Tree, options: AddApiGatewayConstructOptions & {
|
|
28
|
+
iacProvider: "CDK" | "Terraform";
|
|
29
|
+
}) => void;
|
|
30
30
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.addApiGatewayInfra = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
6
6
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -8,12 +8,40 @@ exports.addApiGatewayConstruct = void 0;
|
|
|
8
8
|
const devkit_1 = require("@nx/devkit");
|
|
9
9
|
const shared_constructs_constants_1 = require("../shared-constructs-constants");
|
|
10
10
|
const ast_1 = require("../ast");
|
|
11
|
+
const addApiGatewayInfra = (tree, options) => {
|
|
12
|
+
if (options.iacProvider === 'CDK') {
|
|
13
|
+
addApiGatewayCdkConstructs(tree, options);
|
|
14
|
+
}
|
|
15
|
+
else if (options.iacProvider === 'Terraform') {
|
|
16
|
+
addApiGatewayTerraformModules(tree, options);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
throw new Error(`Unsupported iacProvider ${options.iacProvider}`);
|
|
20
|
+
}
|
|
21
|
+
(0, devkit_1.updateJson)(tree, (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, options.iacProvider === 'CDK'
|
|
22
|
+
? shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR
|
|
23
|
+
: shared_constructs_constants_1.SHARED_TERRAFORM_DIR, 'project.json'), (config) => {
|
|
24
|
+
var _a;
|
|
25
|
+
if (!config.targets) {
|
|
26
|
+
config.targets = {};
|
|
27
|
+
}
|
|
28
|
+
if (!config.targets.build) {
|
|
29
|
+
config.targets.build = {};
|
|
30
|
+
}
|
|
31
|
+
config.targets.build.dependsOn = [
|
|
32
|
+
...((_a = config.targets.build.dependsOn) !== null && _a !== void 0 ? _a : []),
|
|
33
|
+
`${options.apiProjectName}:build`,
|
|
34
|
+
];
|
|
35
|
+
return config;
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
exports.addApiGatewayInfra = addApiGatewayInfra;
|
|
11
39
|
/**
|
|
12
40
|
* Add an API CDK construct, and update the Runtime Config type to export its url
|
|
13
41
|
*/
|
|
14
|
-
const
|
|
42
|
+
const addApiGatewayCdkConstructs = (tree, options) => {
|
|
15
43
|
const generateCoreApiFile = (name) => {
|
|
16
|
-
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', 'core', 'api', name), (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'src', 'core', 'api'), {}, {
|
|
44
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', 'cdk', 'core', 'api', name), (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'src', 'core', 'api'), {}, {
|
|
17
45
|
overwriteStrategy: devkit_1.OverwriteStrategy.KeepExisting,
|
|
18
46
|
});
|
|
19
47
|
};
|
|
@@ -24,12 +52,24 @@ const addApiGatewayConstruct = (tree, options) => {
|
|
|
24
52
|
generateCoreApiFile('trpc');
|
|
25
53
|
}
|
|
26
54
|
// Generate app specific CDK construct
|
|
27
|
-
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', 'app', 'apis', options.constructType), (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'src', 'app', 'apis'), options, {
|
|
55
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', 'cdk', 'app', 'apis', options.constructType), (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'src', 'app', 'apis'), options, {
|
|
28
56
|
overwriteStrategy: devkit_1.OverwriteStrategy.KeepExisting,
|
|
29
57
|
});
|
|
30
58
|
// Export app specific CDK construct
|
|
31
59
|
(0, ast_1.addStarExport)(tree, (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'src', 'app', 'apis', 'index.ts'), `./${options.apiNameKebabCase}.js`);
|
|
32
60
|
(0, ast_1.addStarExport)(tree, (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_CONSTRUCTS_DIR, 'src', 'app', 'index.ts'), './apis/index.js');
|
|
33
61
|
};
|
|
34
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Add an API terraform module, and update the Runtime Config type to export its url
|
|
64
|
+
*/
|
|
65
|
+
const addApiGatewayTerraformModules = (tree, options) => {
|
|
66
|
+
// Generate core terraform module
|
|
67
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', 'terraform', 'core', 'api', options.constructType), (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_TERRAFORM_DIR, 'src', 'core', 'api'), {}, {
|
|
68
|
+
overwriteStrategy: devkit_1.OverwriteStrategy.KeepExisting,
|
|
69
|
+
});
|
|
70
|
+
// Generate app specific terraform module
|
|
71
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', 'terraform', 'app', 'apis', options.constructType), (0, devkit_1.joinPathFragments)(shared_constructs_constants_1.PACKAGES_DIR, shared_constructs_constants_1.SHARED_TERRAFORM_DIR, 'src', 'app', 'apis'), options, {
|
|
72
|
+
overwriteStrategy: devkit_1.OverwriteStrategy.KeepExisting,
|
|
73
|
+
});
|
|
74
|
+
};
|
|
35
75
|
//# sourceMappingURL=api-constructs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-constructs.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/utils/api-constructs/api-constructs.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"api-constructs.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/utils/api-constructs/api-constructs.ts"],"names":[],"mappings":"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"}
|