Updated on 2025-03-13 GMT+08:00
Sample Code of deploy.py
# -*-coding:utf-8 -*- import os import sys import json import logging import subprocess from yaml import load from base64 import b64decode from Crypto.Cipher import AES # need: pip install pyyaml try: from yaml import CLoader as Loader, CDumper as Dumper except ImportError: from yaml import Loader, Dumper logging.basicConfig(level=logging.INFO, filename='function.log', filemode='a', format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s') def decrypt(json_input, key): # We assume that the key was securely shared beforehand try: b64 = json.loads(json_input) json_k = ['nonce', 'header', 'ciphertext', 'tag'] jv = {k: b64decode(b64[k]) for k in json_k} cipher = AES.new(key.encode(), AES.MODE_GCM, nonce=jv['nonce']) cipher.update(jv['header']) plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag']) return plaintext.decode() except (ValueError, KeyError) as e: raise e def generate_update_function_config_cmd(new_config, old_config, key): # Function handler handler = new_config['handler'] # Runtime (required and not modifiable) runtime = new_config['runtime'] # Memory memory_size = new_config['memorySize'] # Timeout timeout = new_config['timeout'] # Project ID project_id = new_config['projectID'] # Command for updating the function configuration update_cmd = f'hcloud FunctionGraph UpdateFunctionConfig' f' --cli-region="{region}"' f' --function_urn="{function_urn}"' f' --project_id="{project_id}"' f' --handler="{handler}"' f' --timeout={timeout}' f' --memory_size={memory_size}' f' --runtime="{runtime}"' f' --func_name="{function_name}"' # Environment variables # Environment variables are directly overwritten. Manually configured variables that are not updated to the cam.yaml file will be lost. user_data = new_config.get('userData', None) if user_data is not None: user_date_json_str = json.dumps(user_data) user_date_json_str = json.dumps(user_date_json_str) update_cmd = update_cmd + f' --user_data={user_date_json_str}' encrypted_user_data = new_config.get('encryptedUserData', None) if encrypted_user_data is not None: encrypted_user_data = decrypt(encrypted_user_data, key) encrypted_user_date_json_str = json.dumps(encrypted_user_data) update_cmd = update_cmd + f' --encrypted_user_data={encrypted_user_date_json_str}' # Keep this part if a VPC is used. vpc_config = old_config.get('func_vpc', None) if vpc_config is not None: update_cmd = update_cmd + f' --func_vpc.vpc_name={vpc_config["vpc_name"]}' f' --func_vpc.vpc_id={vpc_config["vpc_id"]}' f' --func_vpc.subnet_id={vpc_config["subnet_id"]}' f' --func_vpc.cidr={vpc_config["cidr"]}' f' --func_vpc.subnet_name={vpc_config["subnet_name"]}' f' --func_vpc.gateway={vpc_config["gateway"]}' # Keep "xrole": "function-admin" and "app_xrole": "function-admin" if an agency is specified. xrole_config = old_config.get('xrole', None) if xrole_config is not None: update_cmd = update_cmd + f' --xrole="{xrole_config}"' app_xrole_config = old_config.get('app_xrole', None) if app_xrole_config is not None: update_cmd = update_cmd + f' --app_xrole="{app_xrole_config}"' # Configure the initializer and initialization timeout. initializer_handler = new_config.get('initializerHandler', None) initializer_timeout = new_config.get('initializerTimeout', None) if initializer_handler is not None and initializer_timeout is not None: update_cmd = update_cmd + f' --initializer_handler="{initializer_handler}" ' f'--initializer_timeout={initializer_timeout}' # Concurrency settings strategy_config = new_config.get('strategyConfig', None) if strategy_config is not None: concurrency = strategy_config.get('concurrency', None) # Maximum number of concurrent requests per instance concurrent_num = strategy_config.get('concurrentNum', None) update_cmd = update_cmd + f' --strategy_config.concurrency="{concurrency}" ' f'--strategy_config.concurrent_num={concurrent_num}' # Keep this part if a file system is mounted to the function. mount_config = old_config.get('mount_config', None) if mount_config is not None: mount_user = mount_config["mount_user"] update_cmd = update_cmd + f' --mount_config.mount_user.user_id={mount_user["user_id"]}' f' --mount_config.mount_user.user_group_id={mount_user["user_group_id"]}' func_mounts = mount_config["func_mounts"] i = 1 for func_mount in func_mounts: update_cmd = update_cmd + f' --mount_config.func_mounts.{i}.mount_resource="{func_mount["mount_resource"]}"' f' --mount_config.func_mounts.{i}.mount_share_path="{func_mount["mount_share_path"]}"' f' --mount_config.func_mounts.{i}.mount_type="{func_mount["mount_type"]}"' f' --mount_config.func_mounts.{i}.local_mount_path="{func_mount["local_mount_path"]}"' i = i + 1 return update_cmd def exec_cmd(cmd): proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) outs, _ = proc.communicate() return outs.decode('UTF-8') def check_result(stage, exec_result): if "USE_ERROR" in exec_result: error_info = f"failed to {stage}: {exec_result}" logging.error(error_info) raise Exception(error_info) if "FSS.0409" in exec_result: error_info = f"failed to {stage}: {exec_result}" logging.error(error_info) # Return an error if the function code has no changes to update. return try: result_object = json.loads(exec_result) except Exception: error_info = f"failed to {stage}: {exec_result}" logging.error(error_info) raise Exception(error_info) if "error_code" in result_object: error_message = result_object["error_msg"] error_info = f"failed to {stage}: {error_message}" logging.error(error_info) raise Exception(error_info) def generate_update_function_code_cmd(): cmd = f'hcloud FunctionGraph UpdateFunctionCode --cli-region="{region}"' f' --function_urn="{function_urn}" --project_id="{project_id}"' f' --code_url="{code_url}" --func_code.link="" --func_code.file="" --code_type="obs" ' depend_list = old_function_code.get("depend_list", None) if depend_list is not None and len(depend_list) > 0: i = 1 for depend_id in depend_list: cmd = cmd + f'--depend_list.{i}="{depend_id}"' return cmd if __name__ == '__main__': deploy_function_path = sys.argv[1] key = sys.argv[2] f = open(os.path.join(deploy_function_path, "cam.yaml")) data = load(f, Loader=Loader) function_config = data['components'][0] function_name = function_config['name'] function_properties = function_config['properties'] region = function_properties['region'] code_url = function_properties['codeUri'] project_id = function_properties['projectID'] # Obtain the function URN. function_urn = "urn:fss:" + region + ":" + project_id + ":function:default:" + function_name + ":latest" logging.info(f"start to deploy functionURN:{function_urn}") # Query the function configuration. query_function_config_cmd = f'hcloud FunctionGraph ShowFunctionConfig --cli-region="{region}"' f' --function_urn="{function_urn}" --project_id="{project_id}"' result = exec_cmd(query_function_config_cmd) # Check whether a VPC and an agency have been configured for the function. If yes, they must be included during function updates. old_function_config = json.loads(result) check_result("query function config", result) # Query the function code. Keep this part if a dependency is bound to the function. query_function_code_cmd = f'hcloud FunctionGraph ShowFunctionCode --cli-region="{region}"' f' --function_urn="{function_urn}" --project_id="{project_id}"' result = exec_cmd(query_function_code_cmd) old_function_code = json.loads(result) logging.info("query function %s code result: %s", function_urn, result) check_result("query function code", result) # Update the function code. query_function_code_cmd = generate_update_function_code_cmd() result = exec_cmd(query_function_code_cmd) logging.info("update function %s code result: %s", function_urn, result) check_result("update function code", result) # Update the function configuration. update_function_config_cmd = generate_update_function_config_cmd( function_properties, old_function_config, key) result = exec_cmd(update_function_config_cmd) logging.info("update function %s config result: %s", function_urn, result) check_result("update function config", result) logging.info(f"succeed to deploy function {function_urn}")
Parent topic: Automated Deployment
Feedback
Was this page helpful?
Provide feedbackThank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
The system is busy. Please try again later.
For any further questions, feel free to contact us through the chatbot.
Chatbot