veadk-python 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.whl
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.
Potentially problematic release.
This version of veadk-python might be problematic. Click here for more details.
- veadk/agent.py +29 -22
- veadk/agent_builder.py +94 -0
- veadk/auth/__init__.py +13 -0
- veadk/auth/base_auth.py +22 -0
- veadk/auth/veauth/__init__.py +13 -0
- veadk/auth/veauth/apmplus_veauth.py +65 -0
- veadk/auth/veauth/ark_veauth.py +77 -0
- veadk/auth/veauth/base_veauth.py +50 -0
- veadk/auth/veauth/cozeloop_veauth.py +13 -0
- veadk/auth/veauth/prompt_pilot_veauth.py +60 -0
- veadk/auth/veauth/vesearch_veauth.py +62 -0
- veadk/cli/cli.py +2 -0
- veadk/cli/cli_deploy.py +5 -2
- veadk/cli/cli_init.py +25 -6
- veadk/cli/cli_pipeline.py +220 -0
- veadk/cli/cli_prompt.py +4 -4
- veadk/config.py +45 -81
- veadk/configs/__init__.py +13 -0
- veadk/configs/database_configs.py +83 -0
- veadk/configs/model_configs.py +42 -0
- veadk/configs/tool_configs.py +42 -0
- veadk/configs/tracing_configs.py +110 -0
- veadk/consts.py +32 -1
- veadk/database/database_adapter.py +256 -3
- veadk/database/kv/redis_database.py +47 -0
- veadk/database/local_database.py +23 -4
- veadk/database/relational/mysql_database.py +58 -0
- veadk/database/vector/opensearch_vector_database.py +6 -3
- veadk/database/viking/viking_database.py +272 -36
- veadk/integrations/ve_code_pipeline/__init__.py +13 -0
- veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +431 -0
- veadk/integrations/ve_cozeloop/__init__.py +13 -0
- veadk/integrations/ve_cozeloop/ve_cozeloop.py +96 -0
- veadk/integrations/ve_cr/__init__.py +13 -0
- veadk/integrations/ve_cr/ve_cr.py +220 -0
- veadk/integrations/ve_faas/template/cookiecutter.json +3 -2
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/deploy.py +2 -2
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/agent.py +1 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/app.py +24 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/requirements.txt +3 -1
- veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/run.sh +1 -12
- veadk/integrations/ve_faas/ve_faas.py +352 -35
- veadk/integrations/ve_faas/web_template/cookiecutter.json +17 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/__init__.py +13 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/clean.py +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/config.yaml.example +2 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/deploy.py +41 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/Dockerfile +23 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/app.py +123 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/init_db.py +46 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/models.py +36 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/requirements.txt +4 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/run.sh +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/css/style.css +368 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/static/js/admin.js +0 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/dashboard.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/edit_post.html +24 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/login.html +21 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/admin/posts.html +53 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/base.html +45 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/index.html +29 -0
- veadk/integrations/ve_faas/web_template/{{cookiecutter.local_dir_name}}/src/templates/post.html +14 -0
- veadk/integrations/ve_prompt_pilot/ve_prompt_pilot.py +6 -3
- veadk/integrations/ve_tls/__init__.py +13 -0
- veadk/integrations/ve_tls/utils.py +117 -0
- veadk/integrations/ve_tls/ve_tls.py +208 -0
- veadk/integrations/ve_tos/ve_tos.py +128 -73
- veadk/knowledgebase/knowledgebase.py +116 -20
- veadk/memory/long_term_memory.py +20 -21
- veadk/memory/short_term_memory_processor.py +9 -4
- veadk/runner.py +213 -223
- veadk/tools/builtin_tools/vesearch.py +2 -2
- veadk/tools/builtin_tools/video_generate.py +27 -20
- veadk/tracing/telemetry/attributes/extractors/common_attributes_extractors.py +5 -0
- veadk/tracing/telemetry/attributes/extractors/llm_attributes_extractors.py +253 -129
- veadk/tracing/telemetry/attributes/extractors/types.py +15 -4
- veadk/tracing/telemetry/exporters/apmplus_exporter.py +158 -12
- veadk/tracing/telemetry/exporters/cozeloop_exporter.py +4 -9
- veadk/tracing/telemetry/exporters/tls_exporter.py +4 -10
- veadk/tracing/telemetry/opentelemetry_tracer.py +11 -5
- veadk/tracing/telemetry/telemetry.py +23 -5
- veadk/utils/logger.py +1 -1
- veadk/utils/misc.py +48 -0
- veadk/utils/volcengine_sign.py +6 -2
- veadk/version.py +1 -1
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/METADATA +2 -1
- veadk_python-0.2.7.dist-info/RECORD +172 -0
- veadk_python-0.2.5.dist-info/RECORD +0 -127
- /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/__init__.py +0 -0
- /veadk/integrations/ve_faas/template/{{cookiecutter.local_dir_name}}/src/{{{ cookiecutter.app_name|replace('-', '_') }} → {{ cookiecutter.app_name }}}/agent.py +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/WHEEL +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/entry_points.txt +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/licenses/LICENSE +0 -0
- {veadk_python-0.2.5.dist-info → veadk_python-0.2.7.dist-info}/top_level.txt +0 -0
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
+
import os
|
|
16
17
|
import time
|
|
17
18
|
|
|
18
19
|
import requests
|
|
19
|
-
import typer
|
|
20
20
|
import volcenginesdkcore
|
|
21
21
|
import volcenginesdkvefaas
|
|
22
22
|
from volcenginesdkvefaas.models.env_for_create_function_input import (
|
|
@@ -118,6 +118,7 @@ class VeFaaS:
|
|
|
118
118
|
runtime="native-python3.10/v1",
|
|
119
119
|
request_timeout=1800,
|
|
120
120
|
envs=envs,
|
|
121
|
+
memory_mb=2048,
|
|
121
122
|
)
|
|
122
123
|
)
|
|
123
124
|
|
|
@@ -141,6 +142,8 @@ class VeFaaS:
|
|
|
141
142
|
upstream_name: str,
|
|
142
143
|
service_name: str,
|
|
143
144
|
):
|
|
145
|
+
enable_key_auth = os.getenv("VEFAAS_ENABLE_KEY_AUTH", "true").lower() == "true"
|
|
146
|
+
|
|
144
147
|
response = ve_request(
|
|
145
148
|
request_body={
|
|
146
149
|
"Name": application_name,
|
|
@@ -152,6 +155,8 @@ class VeFaaS:
|
|
|
152
155
|
"GatewayName": gateway_name,
|
|
153
156
|
"ServiceName": service_name,
|
|
154
157
|
"UpstreamName": upstream_name,
|
|
158
|
+
"EnableKeyAuth": enable_key_auth,
|
|
159
|
+
"EnableMcpSession": True,
|
|
155
160
|
},
|
|
156
161
|
"TemplateId": self.template_id,
|
|
157
162
|
},
|
|
@@ -189,16 +194,27 @@ class VeFaaS:
|
|
|
189
194
|
time.sleep(10)
|
|
190
195
|
status, full_response = self._get_application_status(app_id)
|
|
191
196
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
if status == "deploy_success":
|
|
198
|
+
cloud_resource = full_response["Result"]["CloudResource"]
|
|
199
|
+
cloud_resource = json.loads(cloud_resource)
|
|
200
|
+
url = cloud_resource["framework"]["url"]["system_url"]
|
|
201
|
+
return url
|
|
202
|
+
else:
|
|
203
|
+
logger.error(
|
|
204
|
+
f"Release application failed. Application ID: {app_id}, Status: {status}"
|
|
205
|
+
)
|
|
206
|
+
import re
|
|
207
|
+
|
|
208
|
+
logs = "\n".join(self._get_application_logs(app_id=app_id))
|
|
209
|
+
log_text = re.sub(
|
|
210
|
+
r'([{"\']?(key|secret|token|pass|auth|credential|access|api|ak|sk|doubao|volces|coze)[^"\'\s]*["\']?\s*[:=]\s*)(["\']?)([^"\'\s]+)(["\']?)|([A-Za-z0-9+/=]{20,})',
|
|
211
|
+
lambda m: f"{m.group(1)}{m.group(3)}******{m.group(5)}"
|
|
212
|
+
if m.group(1)
|
|
213
|
+
else "******",
|
|
214
|
+
logs,
|
|
215
|
+
flags=re.IGNORECASE,
|
|
216
|
+
)
|
|
217
|
+
raise Exception(f"Release application failed. Logs:\n{log_text}")
|
|
202
218
|
|
|
203
219
|
def _get_application_status(self, app_id: str):
|
|
204
220
|
response = ve_request(
|
|
@@ -213,18 +229,51 @@ class VeFaaS:
|
|
|
213
229
|
)
|
|
214
230
|
return response["Result"]["Status"], response
|
|
215
231
|
|
|
216
|
-
def _list_application(self):
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
)
|
|
227
|
-
|
|
232
|
+
def _list_application(self, app_id: str = None, app_name: str = None):
|
|
233
|
+
# firt match app_id. if app_id is None,then match app_name and remove app_id
|
|
234
|
+
request_body = {
|
|
235
|
+
"OrderBy": {"Key": "CreateTime", "Ascend": False},
|
|
236
|
+
"FunctionId": app_id if app_id else None,
|
|
237
|
+
"Filters": [{"Item": {"Key": "Name", "Value": [app_name]}}]
|
|
238
|
+
if app_name and not app_id
|
|
239
|
+
else None,
|
|
240
|
+
}
|
|
241
|
+
# remove None
|
|
242
|
+
request_body = {k: v for k, v in request_body.items() if v is not None}
|
|
243
|
+
|
|
244
|
+
page_size = 50
|
|
245
|
+
page_number = 1
|
|
246
|
+
all_items = []
|
|
247
|
+
total_page = None
|
|
248
|
+
while True:
|
|
249
|
+
try:
|
|
250
|
+
request_body.update({"PageNumber": page_number, "PageSize": page_size})
|
|
251
|
+
response = ve_request(
|
|
252
|
+
request_body=request_body,
|
|
253
|
+
action="ListApplications",
|
|
254
|
+
ak=self.ak,
|
|
255
|
+
sk=self.sk,
|
|
256
|
+
service="vefaas",
|
|
257
|
+
version="2021-03-03",
|
|
258
|
+
region="cn-beijing",
|
|
259
|
+
host="open.volcengineapi.com",
|
|
260
|
+
)
|
|
261
|
+
result = response.get("Result", {})
|
|
262
|
+
items = result.get("Items", [])
|
|
263
|
+
all_items.extend(items)
|
|
264
|
+
|
|
265
|
+
if total_page is None:
|
|
266
|
+
total = result.get("Total", 0)
|
|
267
|
+
total_page = (total + page_size - 1) // page_size
|
|
268
|
+
|
|
269
|
+
if page_number >= total_page or not items:
|
|
270
|
+
break
|
|
271
|
+
page_number += 1
|
|
272
|
+
except Exception as e:
|
|
273
|
+
raise ValueError(
|
|
274
|
+
f"List application failed. Error: {str(e)}. Response: {response}."
|
|
275
|
+
)
|
|
276
|
+
return all_items
|
|
228
277
|
|
|
229
278
|
def _update_function_code(
|
|
230
279
|
self,
|
|
@@ -253,10 +302,6 @@ class VeFaaS:
|
|
|
253
302
|
|
|
254
303
|
# Get application status and extract function info
|
|
255
304
|
status, full_response = self._get_application_status(app_id)
|
|
256
|
-
if status == "deploy_fail":
|
|
257
|
-
raise ValueError(
|
|
258
|
-
f"Cannot update failed application. Current status: {status}"
|
|
259
|
-
)
|
|
260
305
|
|
|
261
306
|
# Extract function name from application config
|
|
262
307
|
cloud_resource = full_response["Result"]["CloudResource"]
|
|
@@ -300,7 +345,7 @@ class VeFaaS:
|
|
|
300
345
|
def get_application_details(self, app_id: str = None, app_name: str = None):
|
|
301
346
|
if not app_id and not app_name:
|
|
302
347
|
raise ValueError("app_id and app_name cannot be both empty.")
|
|
303
|
-
apps = self._list_application()
|
|
348
|
+
apps = self._list_application(app_id=app_id, app_name=app_name)
|
|
304
349
|
if app_id:
|
|
305
350
|
for app in apps:
|
|
306
351
|
if app["Id"] == app_id:
|
|
@@ -312,7 +357,7 @@ class VeFaaS:
|
|
|
312
357
|
return app
|
|
313
358
|
|
|
314
359
|
def find_app_id_by_name(self, name: str):
|
|
315
|
-
apps = self._list_application()
|
|
360
|
+
apps = self._list_application(app_name=name)
|
|
316
361
|
for app in apps:
|
|
317
362
|
if app["Name"] == name:
|
|
318
363
|
return app["Id"]
|
|
@@ -332,12 +377,7 @@ class VeFaaS:
|
|
|
332
377
|
host="open.volcengineapi.com",
|
|
333
378
|
)
|
|
334
379
|
except Exception as e:
|
|
335
|
-
|
|
336
|
-
typer.style(
|
|
337
|
-
f"Delete application failed. Response: {e}",
|
|
338
|
-
fg=typer.colors.BRIGHT_RED,
|
|
339
|
-
)
|
|
340
|
-
)
|
|
380
|
+
logger.error(f"Delete application failed. Response: {e}")
|
|
341
381
|
|
|
342
382
|
def deploy(
|
|
343
383
|
self,
|
|
@@ -409,3 +449,280 @@ class VeFaaS:
|
|
|
409
449
|
logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
|
|
410
450
|
|
|
411
451
|
return url, app_id, function_id
|
|
452
|
+
|
|
453
|
+
def _create_image_function(self, function_name: str, image: str):
|
|
454
|
+
"""Create function using container image instead of code upload."""
|
|
455
|
+
# Read environment variables from veadk configuration
|
|
456
|
+
envs = []
|
|
457
|
+
for key, value in veadk.config.veadk_environments.items():
|
|
458
|
+
envs.append(EnvForCreateFunctionInput(key=key, value=value))
|
|
459
|
+
logger.info(
|
|
460
|
+
f"Fetch {len(envs)} environment variables for image function.",
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
# Create function with container image source configuration
|
|
464
|
+
res = self.client.create_function(
|
|
465
|
+
volcenginesdkvefaas.CreateFunctionRequest(
|
|
466
|
+
command="bash ./run.sh", # Custom startup command
|
|
467
|
+
name=function_name,
|
|
468
|
+
description="Created by VeADK (Volcengine Agent Development Kit)",
|
|
469
|
+
tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
|
|
470
|
+
runtime="native/v1", # Native runtime required for container images
|
|
471
|
+
source_type="image", # Set source type to container image
|
|
472
|
+
source=image, # Container image URL
|
|
473
|
+
request_timeout=1800, # Request timeout in seconds
|
|
474
|
+
envs=envs, # Environment variables from configuration
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
# Log function creation success without exposing sensitive information
|
|
479
|
+
logger.debug(
|
|
480
|
+
f"Function creation in {res.project_name} project with ID {res.id}"
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
function_id = res.id
|
|
484
|
+
logger.info(
|
|
485
|
+
f"Function {function_name} created with image {image} and ID {function_id}"
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
return function_name, function_id
|
|
489
|
+
|
|
490
|
+
def query_user_cr_vpc_tunnel(
|
|
491
|
+
self, registry_name: str, max_attempts: int = 6
|
|
492
|
+
) -> bool:
|
|
493
|
+
"""Query and enable CR VPC tunnel for user registry access."""
|
|
494
|
+
logger.info(f"Setting up CR VPC tunnel for registry: {registry_name}")
|
|
495
|
+
waiting_times = 30
|
|
496
|
+
|
|
497
|
+
try:
|
|
498
|
+
for attempt in range(max_attempts):
|
|
499
|
+
# Check current status
|
|
500
|
+
logger.info(
|
|
501
|
+
f"Checking tunnel status (attempt {attempt + 1}/{max_attempts})"
|
|
502
|
+
)
|
|
503
|
+
query_resp = ve_request(
|
|
504
|
+
request_body={"Registry": registry_name},
|
|
505
|
+
action="QueryUserCrVpcTunnel",
|
|
506
|
+
ak=self.ak,
|
|
507
|
+
sk=self.sk,
|
|
508
|
+
service="vefaas",
|
|
509
|
+
version="2021-03-03",
|
|
510
|
+
region="cn-beijing",
|
|
511
|
+
host="open.volcengineapi.com",
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
current_status = query_resp.get("Result", {}).get("Ready", False)
|
|
515
|
+
logger.info(f"Current tunnel status: {current_status}")
|
|
516
|
+
|
|
517
|
+
# Always try to enable
|
|
518
|
+
logger.info("Enable VPC tunnel")
|
|
519
|
+
enable_resp = ve_request(
|
|
520
|
+
request_body={"Registry": registry_name},
|
|
521
|
+
action="EnableUserCrVpcTunnel",
|
|
522
|
+
ak=self.ak,
|
|
523
|
+
sk=self.sk,
|
|
524
|
+
service="vefaas",
|
|
525
|
+
version="2021-03-03",
|
|
526
|
+
region="cn-beijing",
|
|
527
|
+
host="open.volcengineapi.com",
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
# Handle EnableUserCrVpcTunnel response correctly
|
|
531
|
+
enable_result = enable_resp.get("Result", {})
|
|
532
|
+
enable_status = enable_result.get("Status", "")
|
|
533
|
+
enable_message = enable_result.get("Message", "")
|
|
534
|
+
|
|
535
|
+
if enable_status == "success":
|
|
536
|
+
logger.info("Enable tunnel succeeded")
|
|
537
|
+
elif enable_status == "failed":
|
|
538
|
+
logger.warning(f"Enable tunnel failed: {enable_message}")
|
|
539
|
+
else:
|
|
540
|
+
logger.warning(f"Enable tunnel unknown status: {enable_status}")
|
|
541
|
+
|
|
542
|
+
# Verify final status
|
|
543
|
+
logger.info("Verifying tunnel status")
|
|
544
|
+
verify_resp = ve_request(
|
|
545
|
+
request_body={"Registry": registry_name},
|
|
546
|
+
action="QueryUserCrVpcTunnel",
|
|
547
|
+
ak=self.ak,
|
|
548
|
+
sk=self.sk,
|
|
549
|
+
service="vefaas",
|
|
550
|
+
version="2021-03-03",
|
|
551
|
+
region="cn-beijing",
|
|
552
|
+
host="open.volcengineapi.com",
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
final_status = verify_resp.get("Result", {}).get("Ready", False)
|
|
556
|
+
logger.info(f"Final tunnel status: {final_status}")
|
|
557
|
+
|
|
558
|
+
if final_status:
|
|
559
|
+
logger.info(
|
|
560
|
+
f"CR VPC tunnel successfully enabled for {registry_name}"
|
|
561
|
+
)
|
|
562
|
+
return True
|
|
563
|
+
|
|
564
|
+
# If not ready and not last attempt, wait and retry
|
|
565
|
+
if attempt < max_attempts - 1:
|
|
566
|
+
logger.warning(
|
|
567
|
+
f"Tunnel not ready, waiting {waiting_times}s before retry"
|
|
568
|
+
)
|
|
569
|
+
time.sleep(waiting_times)
|
|
570
|
+
|
|
571
|
+
except Exception as e:
|
|
572
|
+
raise ValueError(f"Failed to setup CR VPC tunnel: {str(e)}")
|
|
573
|
+
|
|
574
|
+
return False
|
|
575
|
+
|
|
576
|
+
def _create_image_function(self, function_name: str, image: str):
|
|
577
|
+
"""Create function using container image instead of code upload."""
|
|
578
|
+
# Read environment variables from veadk configuration
|
|
579
|
+
envs = []
|
|
580
|
+
for key, value in veadk.config.veadk_environments.items():
|
|
581
|
+
envs.append(EnvForCreateFunctionInput(key=key, value=value))
|
|
582
|
+
logger.info(
|
|
583
|
+
f"Fetch {len(envs)} environment variables for image function.",
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
# Create function with container image source configuration
|
|
587
|
+
res = self.client.create_function(
|
|
588
|
+
volcenginesdkvefaas.CreateFunctionRequest(
|
|
589
|
+
command="bash ./run.sh", # Custom startup command
|
|
590
|
+
name=function_name,
|
|
591
|
+
description="Created by VeADK (Volcengine Agent Development Kit)",
|
|
592
|
+
tags=[TagForCreateFunctionInput(key="provider", value="veadk")],
|
|
593
|
+
runtime="native/v1", # Native runtime required for container images
|
|
594
|
+
source_type="image", # Set source type to container image
|
|
595
|
+
source=image, # Container image URL
|
|
596
|
+
request_timeout=1800, # Request timeout in seconds
|
|
597
|
+
envs=envs, # Environment variables from configuration
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
# Log function creation success without exposing sensitive information
|
|
602
|
+
logger.debug(
|
|
603
|
+
f"Function creation in {res.project_name} project with ID {res.id}"
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
function_id = res.id
|
|
607
|
+
logger.info(
|
|
608
|
+
f"Function {function_name} created with image {image} and ID {function_id}"
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
return function_name, function_id
|
|
612
|
+
|
|
613
|
+
def deploy_image(
|
|
614
|
+
self,
|
|
615
|
+
name: str,
|
|
616
|
+
image: str,
|
|
617
|
+
registry_name: str,
|
|
618
|
+
gateway_name: str = "",
|
|
619
|
+
gateway_service_name: str = "",
|
|
620
|
+
gateway_upstream_name: str = "",
|
|
621
|
+
) -> tuple[str, str, str]:
|
|
622
|
+
"""Deploy application using container image.
|
|
623
|
+
|
|
624
|
+
Args:
|
|
625
|
+
name (str): Application name.
|
|
626
|
+
image (str): Container image URL.
|
|
627
|
+
gateway_name (str, optional): Gateway name. Defaults to "".
|
|
628
|
+
gateway_service_name (str, optional): Gateway service name. Defaults to "".
|
|
629
|
+
gateway_upstream_name (str, optional): Gateway upstream name. Defaults to "".
|
|
630
|
+
|
|
631
|
+
Returns:
|
|
632
|
+
tuple[str, str, str]: (url, app_id, function_id)
|
|
633
|
+
"""
|
|
634
|
+
# Validate application name format
|
|
635
|
+
is_ready = self.query_user_cr_vpc_tunnel(registry_name)
|
|
636
|
+
if not is_ready:
|
|
637
|
+
raise ValueError("CR VPC tunnel is not ready")
|
|
638
|
+
|
|
639
|
+
if "_" in name:
|
|
640
|
+
raise ValueError("Function or Application name cannot contain '_'.")
|
|
641
|
+
|
|
642
|
+
# Generate default gateway names with timestamp if not provided
|
|
643
|
+
if not gateway_name:
|
|
644
|
+
gateway_name = f"{name}-gw-{formatted_timestamp()}"
|
|
645
|
+
|
|
646
|
+
# Check for existing serverless gateways to reuse
|
|
647
|
+
existing_gateways = self.apig_client.list_gateways()
|
|
648
|
+
for gateway_instance in existing_gateways.items:
|
|
649
|
+
if (
|
|
650
|
+
gateway_instance.type == "serverless"
|
|
651
|
+
and gateway_instance.name != gateway_name
|
|
652
|
+
):
|
|
653
|
+
logger.warning(
|
|
654
|
+
f"You have at least one serverless gateway {gateway_instance.name}, but not {gateway_name}. Using {gateway_instance.name} instead."
|
|
655
|
+
)
|
|
656
|
+
gateway_name = gateway_instance.name
|
|
657
|
+
break
|
|
658
|
+
|
|
659
|
+
# Set default gateway service and upstream names
|
|
660
|
+
if not gateway_service_name:
|
|
661
|
+
gateway_service_name = f"{name}-gw-svr-{formatted_timestamp()}"
|
|
662
|
+
if not gateway_upstream_name:
|
|
663
|
+
gateway_upstream_name = f"{name}-gw-us-{formatted_timestamp()}"
|
|
664
|
+
|
|
665
|
+
function_name = f"{name}-fn"
|
|
666
|
+
|
|
667
|
+
# Log deployment start with image information
|
|
668
|
+
logger.info(
|
|
669
|
+
f"Start to create VeFaaS function {function_name} with image {image}. Gateway: {gateway_name}, Gateway Service: {gateway_service_name}, Gateway Upstream: {gateway_upstream_name}."
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
# Create function using container image method
|
|
673
|
+
function_name, function_id = self._create_image_function(function_name, image)
|
|
674
|
+
logger.info(f"VeFaaS function {function_name} with ID {function_id} created.")
|
|
675
|
+
|
|
676
|
+
# Create application using existing application creation logic
|
|
677
|
+
logger.info(f"Start to create VeFaaS application {name}.")
|
|
678
|
+
app_id = self._create_application(
|
|
679
|
+
name,
|
|
680
|
+
function_name,
|
|
681
|
+
gateway_name,
|
|
682
|
+
gateway_upstream_name,
|
|
683
|
+
gateway_service_name,
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
# Release application and get deployment URL
|
|
687
|
+
logger.info(f"VeFaaS application {name} with ID {app_id} created.")
|
|
688
|
+
logger.info(f"Start to release VeFaaS application {app_id}.")
|
|
689
|
+
# Release application with retry
|
|
690
|
+
max_attempts = 5
|
|
691
|
+
attempt = 0
|
|
692
|
+
while True:
|
|
693
|
+
try:
|
|
694
|
+
url = self._release_application(app_id)
|
|
695
|
+
logger.info(f"VeFaaS application {name} with ID {app_id} released.")
|
|
696
|
+
break
|
|
697
|
+
except Exception:
|
|
698
|
+
attempt += 1
|
|
699
|
+
if attempt < max_attempts:
|
|
700
|
+
wait_time = 30 * attempt
|
|
701
|
+
logger.info(
|
|
702
|
+
f"Image sync still in progress. Waiting {wait_time} seconds before retry {attempt}/{max_attempts}."
|
|
703
|
+
)
|
|
704
|
+
time.sleep(wait_time)
|
|
705
|
+
else:
|
|
706
|
+
raise
|
|
707
|
+
|
|
708
|
+
logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
|
|
709
|
+
|
|
710
|
+
return url, app_id, function_id
|
|
711
|
+
|
|
712
|
+
def _get_application_logs(self, app_id: str) -> list[str]:
|
|
713
|
+
response = _ = ve_request(
|
|
714
|
+
request_body={"Id": app_id, "Limit": 99999, "RevisionNumber": 1},
|
|
715
|
+
action="GetApplicationRevisionLog",
|
|
716
|
+
ak=self.ak,
|
|
717
|
+
sk=self.sk,
|
|
718
|
+
service="vefaas",
|
|
719
|
+
version="2021-03-03",
|
|
720
|
+
region="cn-beijing",
|
|
721
|
+
host="open.volcengineapi.com",
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
try:
|
|
725
|
+
logs = response["Result"]["LogLines"]
|
|
726
|
+
return logs
|
|
727
|
+
except Exception as _:
|
|
728
|
+
raise ValueError(f"Get application log failed. Response: {response}")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"local_dir_name": "veadk_vefaas_web_proj",
|
|
3
|
+
"app_name": "simple-blog",
|
|
4
|
+
"vefaas_application_name": "simple-blog",
|
|
5
|
+
"veapig_instance_name": "",
|
|
6
|
+
"veapig_service_name": "",
|
|
7
|
+
"veapig_upstream_name": "",
|
|
8
|
+
"use_adk_web": false,
|
|
9
|
+
"veadk_version": "",
|
|
10
|
+
"_copy_without_render": [
|
|
11
|
+
"*.html",
|
|
12
|
+
"*.css",
|
|
13
|
+
"*.js",
|
|
14
|
+
"static/**/*",
|
|
15
|
+
"templates/**/*"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from veadk.cloud.cloud_app import CloudApp
|
|
16
|
+
|
|
17
|
+
def main() -> None:
|
|
18
|
+
cloud_app = CloudApp(vefaas_application_name="{{cookiecutter.vefaas_application_name}}")
|
|
19
|
+
cloud_app.delete_self()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from veadk.cloud.cloud_agent_engine import CloudAgentEngine
|
|
19
|
+
|
|
20
|
+
async def main():
|
|
21
|
+
engine = CloudAgentEngine()
|
|
22
|
+
|
|
23
|
+
cloud_app = engine.deploy(
|
|
24
|
+
path=str(Path(__file__).parent / "src"),
|
|
25
|
+
application_name="{{cookiecutter.vefaas_application_name}}",
|
|
26
|
+
gateway_name="{{cookiecutter.veapig_instance_name}}",
|
|
27
|
+
gateway_service_name="{{cookiecutter.veapig_service_name}}",
|
|
28
|
+
gateway_upstream_name="{{cookiecutter.veapig_upstream_name}}",
|
|
29
|
+
use_adk_web={{cookiecutter.use_adk_web}},
|
|
30
|
+
local_test=False, # Set to True for local testing before deploy to VeFaaS
|
|
31
|
+
)
|
|
32
|
+
print(f"VeFaaS application ID: {cloud_app.vefaas_application_id}")
|
|
33
|
+
|
|
34
|
+
if {{cookiecutter.use_adk_web}}:
|
|
35
|
+
print(f"Web is running at: {cloud_app.vefaas_endpoint}")
|
|
36
|
+
else:
|
|
37
|
+
print(f"Web template does not support use_adk_web=False")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 使用官方Python镜像作为基础镜像
|
|
2
|
+
FROM python:3.9-slim
|
|
3
|
+
|
|
4
|
+
# 设置工作目录
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
# 复制依赖文件并安装依赖
|
|
8
|
+
COPY requirements.txt .
|
|
9
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
10
|
+
|
|
11
|
+
# 复制项目文件
|
|
12
|
+
COPY . .
|
|
13
|
+
|
|
14
|
+
# 设置环境变量
|
|
15
|
+
ENV FLASK_APP=app.py
|
|
16
|
+
ENV FLASK_ENV=production
|
|
17
|
+
ENV PYTHONUNBUFFERED=1
|
|
18
|
+
|
|
19
|
+
# 暴露端口
|
|
20
|
+
EXPOSE 8000
|
|
21
|
+
|
|
22
|
+
# 启动命令
|
|
23
|
+
CMD ["bash", "run.sh"]
|