Skip to content

Commit 38ebda7

Browse files
committed
feat(vefaas): vefaas update function
1 parent ef59a10 commit 38ebda7

2 files changed

Lines changed: 180 additions & 0 deletions

File tree

veadk/cli/services/vefaas/vefaas.py

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

2929
import veadk.config
30+
from volcenginesdkvefaas.models.env_for_update_function_input import EnvForUpdateFunctionInput
31+
from volcenginesdkvefaas.models.tag_for_update_function_input import TagForUpdateFunctionInput
3032
from veadk.cli.services.veapig.apig import APIGateway
3133
from veadk.utils.logger import get_logger
3234
from veadk.utils.misc import formatted_timestamp
@@ -299,3 +301,117 @@ def deploy(
299301
logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.")
300302

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