Skip to content

Commit 34c70b5

Browse files
committed
feat(vefaas): vefaas update function
1 parent ef59a10 commit 34c70b5

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

veadk/cli/services/vefaas/vefaas.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
)
2828

2929
import veadk.config
30+
from volcenginesdkvefaas.models.env_for_update_function_input import (
31+
EnvForUpdateFunctionInput,
32+
)
33+
from volcenginesdkvefaas.models.tag_for_update_function_input import (
34+
TagForUpdateFunctionInput,
35+
)
3036
from veadk.cli.services.veapig.apig import APIGateway
3137
from veadk.utils.logger import get_logger
3238
from veadk.utils.misc import formatted_timestamp
@@ -299,3 +305,121 @@ def deploy(
299305
logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
300306

301307
return url, app_id, function_id
308+
309+
def update(
310+
self,
311+
name: str, # application name
312+
path: str,
313+
) -> tuple[str, str, str]:
314+
"""Update existing application function code while preserving URL.
315+
316+
Args:
317+
name (str): Application name to update.
318+
path (str): Local project path.
319+
320+
Returns:
321+
tuple[str, str, str]: URL, app_id, function_id
322+
"""
323+
# Naming check
324+
if "_" in name:
325+
raise ValueError("Function or Application name cannot contain '_'.")
326+
327+
# Find existing application
328+
app_id = self.find_app_id_by_name(name)
329+
if not app_id:
330+
raise ValueError(
331+
f"Application '{name}' not found. Use deploy() for new applications."
332+
)
333+
334+
# Get application status and extract function info
335+
status, full_response = self._get_application_status(app_id)
336+
if status == "deploy_fail":
337+
raise ValueError(
338+
f"Cannot update failed application. Current status: {status}"
339+
)
340+
341+
# Extract function name from application config
342+
cloud_resource = full_response["Result"]["CloudResource"]
343+
cloud_resource = json.loads(cloud_resource)
344+
function_name = cloud_resource["framework"]["function"]["Name"]
345+
# existing_url = cloud_resource["framework"]["url"]["system_url"]
346+
function_id = cloud_resource["framework"]["function"]["Id"]
347+
if not function_id:
348+
raise ValueError(f"Function '{function_name}' not found for update")
349+
350+
logger.info(
351+
f"Start to update VeFaaS function {function_name} with path {path}."
352+
)
353+
354+
# Update function with new code
355+
self._update_function_code(function_id, path)
356+
357+
logger.info(f"VeFaaS function {function_name} with ID {function_id} updated.")
358+
359+
logger.info(f"Start to release VeFaaS application {app_id}.")
360+
361+
# Release the application to apply changes
362+
url = self._release_application(app_id)
363+
364+
logger.info(f"VeFaaS application {name} with ID {app_id} released.")
365+
366+
logger.info(f"VeFaaS application {name} with ID {app_id} updated on {url}.")
367+
368+
return url, app_id, function_id
369+
370+
def _update_function_code(self, function_id: str, path: str):
371+
"""Update function code by copying deploy process and using update_function.
372+
373+
Args:
374+
function_id (str): Target function ID to update.
375+
path (str): Local project path.
376+
"""
377+
# 1. Read envs
378+
envs = []
379+
for key, value in veadk.config.veadk_environments.items():
380+
envs.append(EnvForUpdateFunctionInput(key=key, value=value))
381+
logger.info(
382+
f"Fetch {len(envs)} environment variables.",
383+
)
384+
385+
# 2. Get a temp bucket to store code
386+
code_zip_data, code_zip_size, error = zip_and_encode_folder(path)
387+
logger.info(
388+
f"Zipped project size: {code_zip_size / 1024 / 1024:.2f} MB",
389+
)
390+
391+
# 3. Upload code to VeFaaS temp bucket
392+
req = volcenginesdkvefaas.GetCodeUploadAddressRequest(
393+
function_id=function_id, content_length=code_zip_size
394+
)
395+
response = self.client.get_code_upload_address(req)
396+
upload_url = response.upload_address
397+
398+
headers = {
399+
"Content-Type": "application/zip",
400+
}
401+
response = requests.put(url=upload_url, data=code_zip_data, headers=headers)
402+
if not (200 <= response.status_code < 300):
403+
error_message = f"Upload failed to {upload_url} with status code {response.status_code}: {response.text}"
404+
raise ValueError(error_message)
405+
406+
# 4. Mount the TOS bucket to function instance
407+
_ = signed_request(
408+
ak=self.ak,
409+
sk=self.sk,
410+
target="CodeUploadCallback",
411+
body={"FunctionId": function_id},
412+
)
413+
414+
# 5. Use update_function client method to apply changes
415+
_ = self.client.update_function(
416+
volcenginesdkvefaas.UpdateFunctionRequest(
417+
id=function_id,
418+
description="Updated by VeADK (Volcengine Agent Development Kit)",
419+
tags=[TagForUpdateFunctionInput(key="provider", value="veadk")],
420+
request_timeout=1800, # Keep same timeout as deploy
421+
envs=envs,
422+
)
423+
)
424+
425+
logger.info(f"Function updated successfully: {function_id}")

veadk/cloud/cloud_agent_engine.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,67 @@ def remove(self, app_name: str):
167167
else:
168168
app_id = self._vefaas_service.find_app_id_by_name(app_name)
169169
self._vefaas_service.delete(app_id)
170+
171+
def update(
172+
self,
173+
application_name: str,
174+
path: str,
175+
use_studio: bool = False,
176+
use_adk_web: bool = False,
177+
) -> CloudApp:
178+
"""Update existing agent project code while keeping the same URL.
179+
180+
Args:
181+
application_name (str): Existing application name to update.
182+
path (str): Local agent project path.
183+
use_studio (bool): Whether to use studio mode.
184+
use_adk_web (bool): Whether to use ADK web mode.
185+
186+
Returns:
187+
CloudApp: Updated cloud app with same endpoint.
188+
"""
189+
assert not (use_studio and use_adk_web), (
190+
"use_studio and use_adk_web can not be True at the same time."
191+
)
192+
193+
# prevent deepeval writing operations
194+
import veadk.config
195+
196+
veadk.config.veadk_environments["DEEPEVAL_TELEMETRY_OPT_OUT"] = "YES"
197+
198+
if use_studio:
199+
veadk.config.veadk_environments["USE_STUDIO"] = "True"
200+
else:
201+
import veadk.config
202+
203+
veadk.config.veadk_environments["USE_STUDIO"] = "False"
204+
205+
if use_adk_web:
206+
import veadk.config
207+
208+
veadk.config.veadk_environments["USE_ADK_WEB"] = "True"
209+
else:
210+
import veadk.config
211+
212+
veadk.config.veadk_environments["USE_ADK_WEB"] = "False"
213+
214+
# convert `path` to absolute path
215+
path = str(Path(path).resolve())
216+
self._prepare(path, application_name)
217+
218+
try:
219+
vefaas_application_url, app_id, function_id = self._vefaas_service.update(
220+
name=application_name,
221+
path=path,
222+
)
223+
_ = function_id # for future use
224+
225+
return CloudApp(
226+
vefaas_application_name=application_name,
227+
vefaas_endpoint=vefaas_application_url,
228+
vefaas_application_id=app_id,
229+
)
230+
except Exception as e:
231+
raise ValueError(
232+
f"Failed to update agent project on Volcengine FaaS platform. Error: {e}"
233+
)

0 commit comments

Comments
 (0)