|
27 | 27 | ) |
28 | 28 |
|
29 | 29 | 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 | +) |
30 | 36 | from veadk.cli.services.veapig.apig import APIGateway |
31 | 37 | from veadk.utils.logger import get_logger |
32 | 38 | from veadk.utils.misc import formatted_timestamp |
@@ -299,3 +305,121 @@ def deploy( |
299 | 305 | logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.") |
300 | 306 |
|
301 | 307 | 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}") |
0 commit comments