From 846dd5d29d1aa396f85636d84a909a1b918018d3 Mon Sep 17 00:00:00 2001 From: "wuqingfu.528" Date: Fri, 5 Sep 2025 20:39:51 +0800 Subject: [PATCH 1/5] feat: vefaas pipeline --- veadk/cli/cli.py | 2 + veadk/cli/cli_pipeline.py | 191 ++++++++ .../integrations/ve_code_pipeline/__init__.py | 13 + .../ve_code_pipeline/ve_code_pipeline.py | 416 ++++++++++++++++++ veadk/integrations/ve_faas/ve_faas.py | 131 ++++++ 5 files changed, 753 insertions(+) create mode 100644 veadk/cli/cli_pipeline.py create mode 100644 veadk/integrations/ve_code_pipeline/__init__.py create mode 100644 veadk/integrations/ve_code_pipeline/ve_code_pipeline.py diff --git a/veadk/cli/cli.py b/veadk/cli/cli.py index bb026637..9f39187e 100644 --- a/veadk/cli/cli.py +++ b/veadk/cli/cli.py @@ -19,6 +19,7 @@ from veadk.cli.cli_init import init from veadk.cli.cli_prompt import prompt from veadk.cli.cli_web import web +from veadk.cli.cli_pipeline import pipeline from veadk.version import VERSION @@ -35,6 +36,7 @@ def veadk(): veadk.add_command(init) veadk.add_command(prompt) veadk.add_command(web) +veadk.add_command(pipeline) if __name__ == "__main__": veadk() diff --git a/veadk/cli/cli_pipeline.py b/veadk/cli/cli_pipeline.py new file mode 100644 index 00000000..b48f9aff --- /dev/null +++ b/veadk/cli/cli_pipeline.py @@ -0,0 +1,191 @@ +# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import warnings + +import click +from veadk.config import getenv +from veadk.integrations.ve_code_pipeline.ve_code_pipeline import VeCodePipeline +from veadk.integrations.ve_faas.ve_faas import VeFaaS + +warnings.filterwarnings( + "ignore", category=UserWarning, module="pydantic._internal._fields" +) + + +def _render_volcengine_prompts() -> dict[str, str]: + volcengine_access_key = click.prompt( + "Volcengine Access Key", default="", show_default=False + ) + if not volcengine_access_key: + click.echo( + "No Volcengine Access Key provided, will try to get it from environment variable VOLCENGINE_ACCESS_KEY." + ) + volcengine_access_key = getenv("VOLCENGINE_ACCESS_KEY") + + volcengine_secret_key = click.prompt( + "Volcengine Secret Key", default="", show_default=False + ) + if not volcengine_secret_key: + click.echo( + "No Volcengine Secret Key provided, will try to get it from environment variable VOLCENGINE_SECRET_KEY." + ) + volcengine_secret_key = getenv("VOLCENGINE_SECRET_KEY") + + volcengine_region = click.prompt("Volcengine Region", default="cn-beijing") + return { + "volcengine_access_key": volcengine_access_key, + "volcengine_secret_key": volcengine_secret_key, + "volcengine_region": volcengine_region, + } + + +def _render_cr_prompts() -> dict[str, str] | None: + cr_domain, cr_namespace_name, cr_region, cr_instance_name, cr_repo = ( + "", + "", + "", + "", + "", + ) + cr_fields = [cr_domain, cr_namespace_name, cr_region, cr_instance_name, cr_repo] + filled_fields = [field for field in cr_fields if field.strip()] + + while len(filled_fields) < len(cr_fields): + click.echo( + "Please provide all the Container Registry (CR) information, " + "or press Enter to leave them all blank and let VeADK create the CR automatically." + ) + cr_domain = click.prompt( + "Container Registry domain", default="", show_default=False + ) + cr_namespace_name = click.prompt( + "Container Registry namespace name", default="", show_default=False + ) + cr_region = click.prompt( + "Container Registry region", default="", show_default=False + ) + cr_instance_name = click.prompt( + "Container Registry instance name", default="", show_default=False + ) + cr_repo = click.prompt( + "Container Registry repo", default="", show_default=False + ) + + cr_fields = [cr_domain, cr_namespace_name, cr_region, cr_instance_name, cr_repo] + filled_fields = [field for field in cr_fields if field.strip()] + + if len(filled_fields) == 0: + return None + + return { + "cr_domain": cr_domain, + "cr_namespace_name": cr_namespace_name, + "cr_region": cr_region, + "cr_instance_name": cr_instance_name, + "cr_repo": cr_repo, + } + + +@click.command() +def pipeline() -> None: + """Integrate a veadk project to volcengine pipeline for CI/CD""" + + click.echo( + "Welcome use VeADK to integrate your project to volcengine pipeline for CI/CD." + ) + + base_image_tag_options = ["preview", "0.0.1", "latest"] + base_image_tag = click.prompt( + "Choose a base image tag:", type=click.Choice(base_image_tag_options) + ) + + github_url = click.prompt("Github url", default="", show_default=False) + while not github_url: + click.echo("Please enter your github url.") + github_url = click.prompt("Github url", default="", show_default=False) + + github_branch = click.prompt("Github branch", default="main") + + github_token = click.prompt("Github token", default="", show_default=False) + while not github_token: + click.echo("Please enter your github token.") + github_token = click.prompt("Github token", default="", show_default=False) + + volcengine_settings = _render_volcengine_prompts() + + cr_settings = _render_cr_prompts() + + if cr_settings is None: + click.echo("No CR information provided, will auto-create one.") + # cr_settings = _auto_create_cr_config() # TODO + + # Using hardcoded values for demonstration + cr_settings = { + "cr_domain": "test-veadk-cn-beijing.cr.volces.com", + "cr_namespace_name": "veadk", + "cr_region": "cn-beijing", + "cr_instance_name": "test-veadk", + "cr_repo": "cicd-weather-test", + } + click.echo("Using the following auto-created CR configuration:") + click.echo(f"Container Registry domain: {cr_settings['cr_domain']}") + click.echo( + f"Container Registry namespace name: {cr_settings['cr_namespace_name']}" + ) + click.echo(f"Container Registry region: {cr_settings['cr_region']}") + click.echo( + f"Container Registry instance name: {cr_settings['cr_instance_name']}" + ) + click.echo(f"Container Registry repo: {cr_settings['cr_repo']}") + + function_id = click.prompt( + "Volcengine FaaS function ID", default="", show_default=False + ) + + if not function_id: + click.echo("Function ID not provided, will auto-create one.") + function_name = click.prompt( + "Function name", default="veadk-function", show_default=False + ) + vefaas_client = VeFaaS( + access_key=volcengine_settings["volcengine_access_key"], + secret_key=volcengine_settings["volcengine_secret_key"], + region=volcengine_settings["volcengine_region"], + ) + _, _, function_id = vefaas_client.deploy_image( + name=function_name, + image="veadk-cn-beijing.cr.volces.com/veadk/simple-fastapi:0.1", + ) + click.echo(f"Created function {function_name} with ID: {function_id}") + + client = VeCodePipeline( + volcengine_access_key=volcengine_settings["volcengine_access_key"], + volcengine_secret_key=volcengine_settings["volcengine_secret_key"], + region=volcengine_settings["volcengine_region"], + ) + client.deploy( + base_image_tag=base_image_tag, + github_url=github_url, + github_branch=github_branch, + github_token=github_token, + cr_domain=cr_settings["cr_domain"], + cr_namespace_name=cr_settings["cr_namespace_name"], + cr_region=cr_settings["cr_region"], + cr_instance_name=cr_settings["cr_instance_name"], + cr_repo=cr_settings["cr_repo"], + function_id=function_id, + ) + + click.echo("Pipeline has been created successfully.") diff --git a/veadk/integrations/ve_code_pipeline/__init__.py b/veadk/integrations/ve_code_pipeline/__init__.py new file mode 100644 index 00000000..7f463206 --- /dev/null +++ b/veadk/integrations/ve_code_pipeline/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py new file mode 100644 index 00000000..382e66f0 --- /dev/null +++ b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py @@ -0,0 +1,416 @@ +import json +from string import Template + +import requests +from veadk.config import getenv +from veadk.utils.logger import get_logger +from veadk.utils.misc import formatted_timestamp +from veadk.utils.volcengine_sign import ve_request + +logger = get_logger(__name__) + +SPEC = Template("""version: 1.0.0 +agentPool: public/prod-v2-public +sources: + - name: ${code_connection_name} + type: Github + url: ${github_url} + branch: ${github_branch} + branchingModel: false + credential: + type: serviceConnection + serviceConnectionId: ${code_connection_id} + cloneDepth: 1 +stages: + - stage: stage-1 + displayName: 函数构建 + tasks: + - task: task-1 + displayName: 函数构建 + timeout: 2h + steps: + - step: step-c1 + displayName: 镜像构建推送到镜像仓库服务 + component: build@2.0.0/buildkit-cr@3.0.0 + inputs: + buildParams: "" + compression: gzip + contextPath: . + crDomain: ${cr_domain} + crNamespace: ${cr_namespace_name} + crRegion: ${cr_region} + crRegistryInstance: ${cr_instance_name} + crRepo: ${cr_repo} + crTag: $(DATETIME) + disableSSLVerify: false + dockerfiles: + default: + content: |- + ${docker_file} + loginCredential: [] + useCache: false + outputs: + - imageOutput_step-c1 + workspace: + resources: + - ref: ${code_connection_name} + directory: $(CP_WORKSPACE) + resourcesPolicy: all + resources: + limits: + cpu: 1C + memory: 2Gi + - stage: stage-2 + displayName: 函数部署 + tasks: + - task: task-2 + displayName: 函数部署 + component: deploy@1.0.0/faas-deploy + inputs: + artifact: + mode: output + type: image + value: $(stages.stage-1.tasks.task-1.outputs.imageOutput_step-c1) + deployPolicy: + type: full + functionId: ${function_id} + functionVersion: 0 + region: cn-beijing + outputs: + - releaseId + - releaseStatus + workspace: {} +""") + + +def get_dockerfile(tag: str = "latest") -> str: + dockerfile = f"""FROM veadk-cn-beijing.cr.volces.com/veadk/veadk-python:{tag} + WORKDIR /app + COPY . . + RUN pip3 install --no-cache-dir -r requirements.txt + ENTRYPOINT ["bash", "./run.sh"]""" + return dockerfile + + +class VeCodePipeline: + def __init__( + self, + volcengine_access_key: str = getenv("VOLCENGINE_ACCESS_KEY"), + volcengine_secret_key: str = getenv("VOLCENGINE_SECRET_KEY"), + region: str = "cn-beijing", + ) -> None: + self.volcengine_access_key = volcengine_access_key + self.volcengine_secret_key = volcengine_secret_key + self.region = region + + self.service = "CP" + self.version = "2023-05-01" + self.host = "open.volcengineapi.com" + self.content_type = "application/json" + + def _create_code_connection( + self, github_token: str, github_url: str + ) -> tuple[str, str]: + logger.info("Creating code connection...") + + conn_name = f"veadk-conn-{formatted_timestamp()}" + res = ve_request( + request_body={ + "Id": f"VEADK_CONN_{formatted_timestamp()}", + "Name": conn_name, + "Description": "Created by Volcengine Agent Development Kit (VeADK)", + "Type": "Github", + "Credential": {"Token": github_token}, + "IsAllWsShared": True, + "URL": github_url, + }, + action="CreateServiceConnection", + ak=self.volcengine_access_key, + sk=self.volcengine_secret_key, + service=self.service, + version=self.version, + region=self.region, + host=self.host, + content_type=self.content_type, + ) + + try: + logger.info( + f"Code connection created successfully, code connection id {res['Result']['Id']}", + ) + return res["Result"]["Id"], conn_name + except KeyError: + raise Exception(f"Create code connection failed: {res}") + + def _get_default_workspace(self) -> str: + logger.info("Getting default workspace...") + + res = ve_request( + request_body={}, + action="GetDefaultWorkspaceInner", + ak=self.volcengine_access_key, + sk=self.volcengine_secret_key, + service=self.service, + version=self.version, + region=self.region, + host=self.host, + content_type=self.content_type, + ) + + try: + logger.info( + f"Default workspace retrieved successfully, workspace id {res['Result']['Id']}", + ) + return res["Result"]["Id"] + except KeyError: + raise Exception(f"Get default workspace failed: {res}") + + def _create_pipeline( + self, + workspace_id: str, + code_connection_id: str, + code_connection_name: str, + github_url: str, + github_branch: str, + cr_domain: str, + cr_namespace_name: str, + cr_region: str, + cr_instance_name: str, + cr_repo: str, + docker_file: str, + function_id: str, + ) -> str: + logger.info("Creating pipeline...") + + spec = SPEC.safe_substitute( + github_url=github_url, + github_branch=github_branch, + workspace_id=workspace_id, + code_connection_id=code_connection_id, + code_connection_name=code_connection_name, + cr_domain=cr_domain, + cr_namespace_name=cr_namespace_name, + cr_region=cr_region, + cr_instance_name=cr_instance_name, + cr_repo=cr_repo, + docker_file=docker_file, + function_id=function_id, + ) + + print(spec) + + res = ve_request( + request_body={ + "WorkspaceId": workspace_id, + "Name": f"veadk-pipeline-{formatted_timestamp()}", + "spec": spec, + }, + action="CreatePipeline", + ak=self.volcengine_access_key, + sk=self.volcengine_secret_key, + service="CP", + version="2023-05-01", + region="cn-beijing", + host="open.volcengineapi.com", + content_type="application/json", + ) + + try: + logger.info( + f"Pipeline created successfully, pipeline id {res['Result']['Id']}", + ) + return res["Result"]["Id"] + except KeyError: + raise Exception(f"Create pipeline failed: {res}") + + def _create_webhook_trigger(self, workspace_id: str, pipeline_id: str) -> str: + logger.info("Creating webhook trigger...") + + res = ve_request( + request_body={ + "WorkspaceId": workspace_id, + "PipelineId": pipeline_id, + "Type": "GitWebhook", + }, + action="CreatePipelineWebhookURL", + ak=self.volcengine_access_key, + sk=self.volcengine_secret_key, + service=self.service, + version=self.version, + region=self.region, + host=self.host, + content_type=self.content_type, + ) + + webhook_url = "" + try: + logger.info( + f"Webhook trigger created successfully, webhook trigger url {res['Result']['WebhookURL']}", + ) + webhook_url = res["Result"]["WebhookURL"] + except KeyError: + raise Exception(f"Create webhook trigger failed: {res}") + + # create a trigger with webhook url and pipeline id + + return webhook_url + + def _set_github_webhook( + self, webhook_url: str, github_url: str, github_token: str + ) -> None: + logger.info("Setting GitHub webhook...") + + github_url = github_url.replace("https://", "").replace("http://", "") + github_url_parts = [part for part in github_url.split("/") if part] + owner = github_url_parts[-2] + repo = github_url_parts[-1] + + logger.debug(f"Parsed GitHub URL, owner: {owner}, repo: {repo}") + + headers = { + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {github_token}", + "X-GitHub-Api-Version": "2022-11-28", + "Content-Type": "application/json", + } + + webhook_config = { + "name": "web", + "active": True, + "events": ["push"], + "config": {"url": webhook_url, "content_type": "json", "insecure_ssl": "1"}, + } + + try: + response = requests.post( + url=f"https://api.github.com/repos/{owner}/{repo}/hooks", + headers=headers, + data=json.dumps(webhook_config), + ) + + if response.status_code == 201: + logger.info("Create github Webhook successfully.") + result = response.json() + logger.info( + f"Webhook ID: {result['id']}, Webhook URL: {result['url']}, Listening events: {', '.join(result['events'])}" + ) + return result + else: + logger.error(f"Create Webhook failed: HTTP {response.status_code}") + logger.error(f"Error message: {response.text}") + return None + + except requests.exceptions.RequestException as e: + logger.error(f"Request exception: {e}") + return None + + def _create_trigger( + self, + workspace_id: str, + pipeline_id: str, + webhook_url: str, + code_connection_name: str, + github_branch: str, + ) -> None: + """Create and bind a trigger to pipeline instance with webhook url.""" + logger.info("Creating trigger and bind it to pipeline instance...") + + res = ve_request( + request_body={ + "WorkspaceId": workspace_id, + "PipelineId": pipeline_id, + "Name": f"veadk-event-trigger-{formatted_timestamp()}", + "Type": "GitWebhook", + "Configuration": { + "Webhook": { + "URL": webhook_url, + "Git": { + "SourceName": code_connection_name, + "Filters": [ + { + "EventType": "Push", + "Config": {"References": [github_branch]}, + }, + { + "EventType": "CreateTag", + "Config": {"References": []}, + }, + ], + "TriggerExecutionType": "AllEvents", + }, + } + }, + "Sources": [ + { + "SourceName": code_connection_name, + "Reference": "main", + } + ], + }, + action="CreateTrigger", + ak=self.volcengine_access_key, + sk=self.volcengine_secret_key, + service=self.service, + version=self.version, + region=self.region, + host=self.host, + content_type=self.content_type, + ) + + try: + logger.info( + f"Trigger created and bind successfully, result Id is {res['Result']['Id']}", + ) + except KeyError: + raise Exception(f"Create webhook trigger failed: {res}") + + def deploy( + self, + base_image_tag: str, + github_url: str, + github_branch: str, + github_token: str, + cr_domain: str, + cr_namespace_name: str, + cr_region: str, + cr_instance_name: str, + cr_repo: str, + function_id: str, + ) -> str: + workspace_id = self._get_default_workspace() + + code_connection_id, code_connection_name = self._create_code_connection( + github_token=github_token, github_url=github_url + ) + + pipeline_id = self._create_pipeline( + workspace_id=workspace_id, + code_connection_id=code_connection_id, + code_connection_name=code_connection_name, + github_url=github_url, + github_branch=github_branch, + cr_domain=cr_domain, + cr_namespace_name=cr_namespace_name, + cr_region=cr_region, + cr_repo=cr_repo, + docker_file=get_dockerfile(tag=base_image_tag), + function_id=function_id, + ) + + webhook_url = self._create_webhook_trigger( + workspace_id=workspace_id, pipeline_id=pipeline_id + ) + + self._set_github_webhook( + webhook_url=webhook_url, github_url=github_url, github_token=github_token + ) + + self._create_trigger( + workspace_id=workspace_id, + pipeline_id=pipeline_id, + webhook_url=webhook_url, + code_connection_name=code_connection_name, + github_branch=github_branch, + ) + + return pipeline_id diff --git a/veadk/integrations/ve_faas/ve_faas.py b/veadk/integrations/ve_faas/ve_faas.py index eb54a97b..8988baa5 100644 --- a/veadk/integrations/ve_faas/ve_faas.py +++ b/veadk/integrations/ve_faas/ve_faas.py @@ -411,3 +411,134 @@ def deploy( logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.") return url, app_id, function_id + + def _create_image_function(self, function_name: str, image: str): + """Create function using container image instead of code upload.""" + # Read environment variables from veadk configuration + envs = [] + for key, value in veadk.config.veadk_environments.items(): + envs.append(EnvForCreateFunctionInput(key=key, value=value)) + logger.info( + f"Fetch {len(envs)} environment variables for image function.", + ) + + # Create function with container image source configuration + res = self.client.create_function( + volcenginesdkvefaas.CreateFunctionRequest( + command="bash ./run.sh", # Custom startup command + name=function_name, + description="Created by VeADK (Volcengine Agent Development Kit)", + tags=[TagForCreateFunctionInput(key="provider", value="veadk")], + runtime="native/v1", # Native runtime required for container images + source_type="image", # Set source type to container image + source=image, # Container image URL + request_timeout=1800, # Request timeout in seconds + envs=envs, # Environment variables from configuration + ) + ) + + # Log function creation success without exposing sensitive information + logger.debug( + f"Function creation in {res.project_name} project with ID {res.id}" + ) + + function_id = res.id + logger.info( + f"Function {function_name} created with image {image} and ID {function_id}" + ) + + return function_name, function_id + + def deploy_image( + self, + name: str, + image: str, + gateway_name: str = "", + gateway_service_name: str = "", + gateway_upstream_name: str = "", + ) -> tuple[str, str, str]: + """Deploy application using container image. + + Args: + name (str): Application name. + image (str): Container image URL. + gateway_name (str, optional): Gateway name. Defaults to "". + gateway_service_name (str, optional): Gateway service name. Defaults to "". + gateway_upstream_name (str, optional): Gateway upstream name. Defaults to "". + + Returns: + tuple[str, str, str]: (url, app_id, function_id) + """ + # Validate application name format + if "_" in name: + raise ValueError("Function or Application name cannot contain '_'.") + + # Generate default gateway names with timestamp if not provided + if not gateway_name: + gateway_name = f"{name}-gw-{formatted_timestamp()}" + + # Check for existing serverless gateways to reuse + existing_gateways = self.apig_client.list_gateways() + for gateway_instance in existing_gateways.items: + if ( + gateway_instance.type == "serverless" + and gateway_instance.name != gateway_name + ): + logger.warning( + f"You have at least one serverless gateway {gateway_instance.name}, but not {gateway_name}. Using {gateway_instance.name} instead." + ) + gateway_name = gateway_instance.name + break + + # Set default gateway service and upstream names + if not gateway_service_name: + gateway_service_name = f"{name}-gw-svr-{formatted_timestamp()}" + if not gateway_upstream_name: + gateway_upstream_name = f"{name}-gw-us-{formatted_timestamp()}" + + function_name = f"{name}-fn" + + # Log deployment start with image information + logger.info( + f"Start to create VeFaaS function {function_name} with image {image}. Gateway: {gateway_name}, Gateway Service: {gateway_service_name}, Gateway Upstream: {gateway_upstream_name}." + ) + + # Create function using container image method + function_name, function_id = self._create_image_function(function_name, image) + logger.info(f"VeFaaS function {function_name} with ID {function_id} created.") + + # Create application using existing application creation logic + logger.info(f"Start to create VeFaaS application {name}.") + app_id = self._create_application( + name, + function_name, + gateway_name, + gateway_upstream_name, + gateway_service_name, + ) + + # Release application and get deployment URL + logger.info(f"VeFaaS application {name} with ID {app_id} created.") + logger.info(f"Start to release VeFaaS application {app_id}.") + # Release application with retry + max_attempts = 5 + attempt = 0 + while True: + try: + url = self._release_application(app_id) + logger.info(f"VeFaaS application {name} with ID {app_id} released.") + break + except Exception: + attempt += 1 + if attempt < max_attempts: + wait_time = 30 * attempt + logger.info( + f"Image sync still in progress. Waiting {wait_time} seconds before retry {attempt}/{max_attempts}." + ) + time.sleep(wait_time) + else: + raise + + logger.info(f"VeFaaS application {name} with ID {app_id} deployed on {url}.") + + return url, app_id, function_id From 8b9b5bfb798853e9281d9effc08d9ddd2cda3f61 Mon Sep 17 00:00:00 2001 From: "wuqingfu.528" Date: Fri, 5 Sep 2025 20:43:35 +0800 Subject: [PATCH 2/5] fix: add license header --- .../ve_code_pipeline/ve_code_pipeline.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py index 382e66f0..76f6bb93 100644 --- a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +++ b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py @@ -1,3 +1,17 @@ +# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import json from string import Template From 1411894e744197a5135912d26758b39cfb4f400f Mon Sep 17 00:00:00 2001 From: "wuqingfu.528" Date: Mon, 8 Sep 2025 15:48:55 +0800 Subject: [PATCH 3/5] fix: complete auto-creating cr --- veadk/cli/cli_pipeline.py | 256 +++++++++++------- .../ve_code_pipeline/ve_code_pipeline.py | 1 + veadk/integrations/ve_faas/ve_faas.py | 128 +++++++++ 3 files changed, 282 insertions(+), 103 deletions(-) diff --git a/veadk/cli/cli_pipeline.py b/veadk/cli/cli_pipeline.py index b48f9aff..e2991f48 100644 --- a/veadk/cli/cli_pipeline.py +++ b/veadk/cli/cli_pipeline.py @@ -15,81 +15,153 @@ import warnings import click +from veadk.version import VERSION from veadk.config import getenv from veadk.integrations.ve_code_pipeline.ve_code_pipeline import VeCodePipeline from veadk.integrations.ve_faas.ve_faas import VeFaaS +from veadk.integrations.ve_cr.ve_cr import VeCR +from veadk.consts import ( + DEFAULT_CR_INSTANCE_NAME, + DEFAULT_CR_NAMESPACE_NAME, + DEFAULT_CR_REPO_NAME, +) warnings.filterwarnings( "ignore", category=UserWarning, module="pydantic._internal._fields" ) -def _render_volcengine_prompts() -> dict[str, str]: - volcengine_access_key = click.prompt( - "Volcengine Access Key", default="", show_default=False +def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]): + vecr = VeCR( + access_key=volcengine_settings["volcengine_access_key"], + secret_key=volcengine_settings["volcengine_secret_key"], + region=volcengine_settings["volcengine_region"], ) - if not volcengine_access_key: - click.echo( - "No Volcengine Access Key provided, will try to get it from environment variable VOLCENGINE_ACCESS_KEY." + try: + vecr._create_instance(cr_settings["cr_instance_name"]) + except Exception as e: + click.echo(f"Failed to create CR instance: {e}") + raise + + try: + vecr._create_namespace( + instance_name=cr_settings["cr_instance_name"], + namespace_name=cr_settings["cr_namespace_name"], ) - volcengine_access_key = getenv("VOLCENGINE_ACCESS_KEY") - - volcengine_secret_key = click.prompt( - "Volcengine Secret Key", default="", show_default=False - ) - if not volcengine_secret_key: - click.echo( - "No Volcengine Secret Key provided, will try to get it from environment variable VOLCENGINE_SECRET_KEY." + except Exception as e: + click.echo(f"Failed to create CR namespace: {e}") + raise + + try: + vecr._create_repo( + instance_name=cr_settings["cr_instance_name"], + namespace_name=cr_settings["cr_namespace_name"], + repo_name=cr_settings["cr_repo"], ) - volcengine_secret_key = getenv("VOLCENGINE_SECRET_KEY") + except Exception as e: + click.echo(f"Failed to create CR repo: {e}") + raise - volcengine_region = click.prompt("Volcengine Region", default="cn-beijing") - return { - "volcengine_access_key": volcengine_access_key, - "volcengine_secret_key": volcengine_secret_key, - "volcengine_region": volcengine_region, - } +@click.command() +@click.option( + "--base-image-tag", + required=True, + help=f"Base VeADK image tag can be 'preview', 'latest', or a VeADK version (e.g., {VERSION}).", +) +@click.option( + "--github-url", + required=True, + help="The github url of your project", +) +@click.option( + "--github-branch", + default="main", + help="The github branch of your project, default is main", +) +@click.option( + "--github-token", + required=True, + help="The github token to manage your project", +) +@click.option( + "--access-key", + default=None, + help="Volcengine access key", +) +@click.option( + "--secret-key", + default=None, + help="Volcengine secret key", +) +@click.option( + "--region", + default="cn-beijing", + help="Volcengine region", +) +@click.option( + "--cr-domain", + default=None, + help="Container Registry domain", +) +@click.option( + "--cr-namespace-name", + default=None, + help="Container Registry namespace name", +) +@click.option( + "--cr-region", + default=None, + help="Container Registry region", +) +@click.option( + "--cr-instance-name", + default=None, + help="Container Registry instance name", +) +@click.option( + "--cr-repo", + default=None, + help="Container Registry repo", +) +@click.option( + "--function-id", + default=None, + help="Volcengine FaaS function ID", +) +def pipeline( + base_image_tag: str, + github_url: str, + github_branch: str, + github_token: str, + access_key: str, + secret_key: str, + region: str, + cr_domain: str, + cr_namespace_name: str, + cr_region: str, + cr_instance_name: str, + cr_repo: str, + function_id: str, +) -> None: + """Integrate a veadk project to volcengine pipeline for CI/CD""" -def _render_cr_prompts() -> dict[str, str] | None: - cr_domain, cr_namespace_name, cr_region, cr_instance_name, cr_repo = ( - "", - "", - "", - "", - "", + click.echo( + "Welcome use VeADK to integrate your project to volcengine pipeline for CI/CD." ) - cr_fields = [cr_domain, cr_namespace_name, cr_region, cr_instance_name, cr_repo] - filled_fields = [field for field in cr_fields if field.strip()] - - while len(filled_fields) < len(cr_fields): - click.echo( - "Please provide all the Container Registry (CR) information, " - "or press Enter to leave them all blank and let VeADK create the CR automatically." - ) - cr_domain = click.prompt( - "Container Registry domain", default="", show_default=False - ) - cr_namespace_name = click.prompt( - "Container Registry namespace name", default="", show_default=False - ) - cr_region = click.prompt( - "Container Registry region", default="", show_default=False - ) - cr_instance_name = click.prompt( - "Container Registry instance name", default="", show_default=False - ) - cr_repo = click.prompt( - "Container Registry repo", default="", show_default=False - ) - cr_fields = [cr_domain, cr_namespace_name, cr_region, cr_instance_name, cr_repo] - filled_fields = [field for field in cr_fields if field.strip()] + if not access_key: + access_key = getenv("VOLCENGINE_ACCESS_KEY") + if not secret_key: + secret_key = getenv("VOLCENGINE_SECRET_KEY") - if len(filled_fields) == 0: - return None + volcengine_settings = { + "volcengine_access_key": access_key, + "volcengine_secret_key": secret_key, + "volcengine_region": region, + } - return { + cr_settings = { "cr_domain": cr_domain, "cr_namespace_name": cr_namespace_name, "cr_region": cr_region, @@ -97,49 +169,28 @@ def _render_cr_prompts() -> dict[str, str] | None: "cr_repo": cr_repo, } + if not all(cr_settings.values()): + click.echo( + "Not all Container Registry (CR) information is specified; it will be auto-completed and created." + ) -@click.command() -def pipeline() -> None: - """Integrate a veadk project to volcengine pipeline for CI/CD""" - - click.echo( - "Welcome use VeADK to integrate your project to volcengine pipeline for CI/CD." - ) - - base_image_tag_options = ["preview", "0.0.1", "latest"] - base_image_tag = click.prompt( - "Choose a base image tag:", type=click.Choice(base_image_tag_options) - ) - - github_url = click.prompt("Github url", default="", show_default=False) - while not github_url: - click.echo("Please enter your github url.") - github_url = click.prompt("Github url", default="", show_default=False) - - github_branch = click.prompt("Github branch", default="main") - - github_token = click.prompt("Github token", default="", show_default=False) - while not github_token: - click.echo("Please enter your github token.") - github_token = click.prompt("Github token", default="", show_default=False) - - volcengine_settings = _render_volcengine_prompts() - - cr_settings = _render_cr_prompts() - - if cr_settings is None: - click.echo("No CR information provided, will auto-create one.") - # cr_settings = _auto_create_cr_config() # TODO - - # Using hardcoded values for demonstration - cr_settings = { - "cr_domain": "test-veadk-cn-beijing.cr.volces.com", - "cr_namespace_name": "veadk", - "cr_region": "cn-beijing", - "cr_instance_name": "test-veadk", - "cr_repo": "cicd-weather-test", - } - click.echo("Using the following auto-created CR configuration:") + for key, value in cr_settings.items(): + if key == "cr_domain" and value is None: + cr_settings[key] = ( + f"{DEFAULT_CR_INSTANCE_NAME}-cn-beijing.cr.volces.com" + ) + elif key == "cr_namespace_name" and value is None: + cr_settings[key] = DEFAULT_CR_NAMESPACE_NAME + elif key == "cr_region" and value is None: + cr_settings[key] = "cn-beijing" + elif key == "cr_instance_name" and value is None: + cr_settings[key] = DEFAULT_CR_INSTANCE_NAME + elif key == "cr_repo" and value is None: + cr_settings[key] = DEFAULT_CR_REPO_NAME + + _create_cr(volcengine_settings, cr_settings) + + click.echo("Using the following CR configuration:") click.echo(f"Container Registry domain: {cr_settings['cr_domain']}") click.echo( f"Container Registry namespace name: {cr_settings['cr_namespace_name']}" @@ -150,12 +201,10 @@ def pipeline() -> None: ) click.echo(f"Container Registry repo: {cr_settings['cr_repo']}") - function_id = click.prompt( - "Volcengine FaaS function ID", default="", show_default=False - ) - if not function_id: - click.echo("Function ID not provided, will auto-create one.") + click.echo( + "No Function ID specified. The system will create one automatically. Please specify a function name:" + ) function_name = click.prompt( "Function name", default="veadk-function", show_default=False ) @@ -167,6 +216,7 @@ def pipeline() -> None: _, _, function_id = vefaas_client.deploy_image( name=function_name, image="veadk-cn-beijing.cr.volces.com/veadk/simple-fastapi:0.1", + registry_name=cr_settings["cr_instance_name"], ) click.echo(f"Created function {function_name} with ID: {function_id}") diff --git a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py index 76f6bb93..05b09d26 100644 --- a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +++ b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py @@ -406,6 +406,7 @@ def deploy( cr_domain=cr_domain, cr_namespace_name=cr_namespace_name, cr_region=cr_region, + cr_instance_name=cr_instance_name, cr_repo=cr_repo, docker_file=get_dockerfile(tag=base_image_tag), function_id=function_id, diff --git a/veadk/integrations/ve_faas/ve_faas.py b/veadk/integrations/ve_faas/ve_faas.py index 8988baa5..415b1ac2 100644 --- a/veadk/integrations/ve_faas/ve_faas.py +++ b/veadk/integrations/ve_faas/ve_faas.py @@ -449,10 +449,134 @@ def _create_image_function(self, function_name: str, image: str): return function_name, function_id + def query_user_cr_vpc_tunnel( + self, registry_name: str, max_attempts: int = 6 + ) -> bool: + """Query and enable CR VPC tunnel for user registry access.""" + logger.info(f"Setting up CR VPC tunnel for registry: {registry_name}") + waiting_times = 30 + + try: + for attempt in range(max_attempts): + # Check current status + logger.info( + f"Checking tunnel status (attempt {attempt + 1}/{max_attempts})" + ) + query_resp = ve_request( + request_body={"Registry": registry_name}, + action="QueryUserCrVpcTunnel", + ak=self.ak, + sk=self.sk, + service="vefaas", + version="2021-03-03", + region="cn-beijing", + host="open.volcengineapi.com", + ) + + current_status = query_resp.get("Result", {}).get("Ready", False) + logger.info(f"Current tunnel status: {current_status}") + + # Always try to enable + logger.info("Enable VPC tunnel") + enable_resp = ve_request( + request_body={"Registry": registry_name}, + action="EnableUserCrVpcTunnel", + ak=self.ak, + sk=self.sk, + service="vefaas", + version="2021-03-03", + region="cn-beijing", + host="open.volcengineapi.com", + ) + + # Handle EnableUserCrVpcTunnel response correctly + enable_result = enable_resp.get("Result", {}) + enable_status = enable_result.get("Status", "") + enable_message = enable_result.get("Message", "") + + if enable_status == "success": + logger.info("Enable tunnel succeeded") + elif enable_status == "failed": + logger.warning(f"Enable tunnel failed: {enable_message}") + else: + logger.warning(f"Enable tunnel unknown status: {enable_status}") + + # Verify final status + logger.info("Verifying tunnel status") + verify_resp = ve_request( + request_body={"Registry": registry_name}, + action="QueryUserCrVpcTunnel", + ak=self.ak, + sk=self.sk, + service="vefaas", + version="2021-03-03", + region="cn-beijing", + host="open.volcengineapi.com", + ) + + final_status = verify_resp.get("Result", {}).get("Ready", False) + logger.info(f"Final tunnel status: {final_status}") + + if final_status: + logger.info( + f"CR VPC tunnel successfully enabled for {registry_name}" + ) + return True + + # If not ready and not last attempt, wait and retry + if attempt < max_attempts - 1: + logger.warning( + f"Tunnel not ready, waiting {waiting_times}s before retry" + ) + time.sleep(waiting_times) + + except Exception as e: + raise ValueError(f"Failed to setup CR VPC tunnel: {str(e)}") + + return False + + def _create_image_function(self, function_name: str, image: str): + """Create function using container image instead of code upload.""" + # Read environment variables from veadk configuration + envs = [] + for key, value in veadk.config.veadk_environments.items(): + envs.append(EnvForCreateFunctionInput(key=key, value=value)) + logger.info( + f"Fetch {len(envs)} environment variables for image function.", + ) + + # Create function with container image source configuration + res = self.client.create_function( + volcenginesdkvefaas.CreateFunctionRequest( + command="bash ./run.sh", # Custom startup command + name=function_name, + description="Created by VeADK (Volcengine Agent Development Kit)", + tags=[TagForCreateFunctionInput(key="provider", value="veadk")], + runtime="native/v1", # Native runtime required for container images + source_type="image", # Set source type to container image + source=image, # Container image URL + request_timeout=1800, # Request timeout in seconds + envs=envs, # Environment variables from configuration + ) + ) + + # Log function creation success without exposing sensitive information + logger.debug( + f"Function creation in {res.project_name} project with ID {res.id}" + ) + + function_id = res.id + logger.info( + f"Function {function_name} created with image {image} and ID {function_id}" + ) + + return function_name, function_id + def deploy_image( self, name: str, image: str, + registry_name: str, gateway_name: str = "", gateway_service_name: str = "", gateway_upstream_name: str = "", @@ -470,6 +594,10 @@ def deploy_image( tuple[str, str, str]: (url, app_id, function_id) """ # Validate application name format + is_ready = self.query_user_cr_vpc_tunnel(registry_name) + if not is_ready: + raise ValueError("CR VPC tunnel is not ready") + if "_" in name: raise ValueError("Function or Application name cannot contain '_'.") From 1ef524d4893d52cf466bccb83839c540673bdc78 Mon Sep 17 00:00:00 2001 From: "wuqingfu.528" Date: Mon, 8 Sep 2025 16:53:21 +0800 Subject: [PATCH 4/5] fix: click option --- veadk/cli/cli_pipeline.py | 94 +++++++++++++-------------------------- 1 file changed, 30 insertions(+), 64 deletions(-) diff --git a/veadk/cli/cli_pipeline.py b/veadk/cli/cli_pipeline.py index e2991f48..2b006aae 100644 --- a/veadk/cli/cli_pipeline.py +++ b/veadk/cli/cli_pipeline.py @@ -67,7 +67,7 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) @click.option( "--base-image-tag", required=True, - help=f"Base VeADK image tag can be 'preview', 'latest', or a VeADK version (e.g., {VERSION}).", + help=f"Base VeADK image tag can be 'preview', 'latest', or a VeADK version (e.g., {VERSION})", ) @click.option( "--github-url", @@ -86,48 +86,43 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) ) @click.option( "--access-key", - default=None, - help="Volcengine access key", + default=getenv("VOLCENGINE_ACCESS_KEY"), + help="Volcengine access key, if not set, will use the value of environment variable VOLCENGINE_ACCESS_KEY", ) @click.option( "--secret-key", - default=None, - help="Volcengine secret key", + default=getenv("VOLCENGINE_SECRET_KEY"), + help="Volcengine secret key, if not set, will use the value of environment variable VOLCENGINE_SECRET_KEY", ) @click.option( "--region", default="cn-beijing", - help="Volcengine region", + help="Volcengine region, default is cn-beijing", ) @click.option( - "--cr-domain", - default=None, - help="Container Registry domain", + "--cr-instance-name", + default=DEFAULT_CR_INSTANCE_NAME, + help="Container Registry instance name, default is veadk-user-instance", ) @click.option( "--cr-namespace-name", - default=None, - help="Container Registry namespace name", -) -@click.option( - "--cr-region", - default=None, - help="Container Registry region", + default=DEFAULT_CR_NAMESPACE_NAME, + help="Container Registry namespace name, default is veadk-user-namespace", ) @click.option( - "--cr-instance-name", - default=None, - help="Container Registry instance name", + "--cr-repo", + default=DEFAULT_CR_REPO_NAME, + help="Container Registry repo, default is veadk-user-repo", ) @click.option( - "--cr-repo", - default=None, - help="Container Registry repo", + "--cr-region", + default="cn-beijing", + help="Container Registry region, default is cn-beijing", ) @click.option( "--function-id", default=None, - help="Volcengine FaaS function ID", + help="Volcengine FaaS function ID, if not set, a new function will be created automatically", ) def pipeline( base_image_tag: str, @@ -137,11 +132,10 @@ def pipeline( access_key: str, secret_key: str, region: str, - cr_domain: str, - cr_namespace_name: str, - cr_region: str, cr_instance_name: str, + cr_namespace_name: str, cr_repo: str, + cr_region: str, function_id: str, ) -> None: """Integrate a veadk project to volcengine pipeline for CI/CD""" @@ -150,11 +144,6 @@ def pipeline( "Welcome use VeADK to integrate your project to volcengine pipeline for CI/CD." ) - if not access_key: - access_key = getenv("VOLCENGINE_ACCESS_KEY") - if not secret_key: - secret_key = getenv("VOLCENGINE_SECRET_KEY") - volcengine_settings = { "volcengine_access_key": access_key, "volcengine_secret_key": secret_key, @@ -162,44 +151,21 @@ def pipeline( } cr_settings = { - "cr_domain": cr_domain, - "cr_namespace_name": cr_namespace_name, - "cr_region": cr_region, + "cr_domain": f"{cr_instance_name}-{cr_region}.cr.volces.com", "cr_instance_name": cr_instance_name, + "cr_namespace_name": cr_namespace_name, "cr_repo": cr_repo, + "cr_region": cr_region, } - if not all(cr_settings.values()): - click.echo( - "Not all Container Registry (CR) information is specified; it will be auto-completed and created." - ) + _create_cr(volcengine_settings, cr_settings) - for key, value in cr_settings.items(): - if key == "cr_domain" and value is None: - cr_settings[key] = ( - f"{DEFAULT_CR_INSTANCE_NAME}-cn-beijing.cr.volces.com" - ) - elif key == "cr_namespace_name" and value is None: - cr_settings[key] = DEFAULT_CR_NAMESPACE_NAME - elif key == "cr_region" and value is None: - cr_settings[key] = "cn-beijing" - elif key == "cr_instance_name" and value is None: - cr_settings[key] = DEFAULT_CR_INSTANCE_NAME - elif key == "cr_repo" and value is None: - cr_settings[key] = DEFAULT_CR_REPO_NAME - - _create_cr(volcengine_settings, cr_settings) - - click.echo("Using the following CR configuration:") - click.echo(f"Container Registry domain: {cr_settings['cr_domain']}") - click.echo( - f"Container Registry namespace name: {cr_settings['cr_namespace_name']}" - ) - click.echo(f"Container Registry region: {cr_settings['cr_region']}") - click.echo( - f"Container Registry instance name: {cr_settings['cr_instance_name']}" - ) - click.echo(f"Container Registry repo: {cr_settings['cr_repo']}") + click.echo("Using the following CR configuration:") + click.echo(f"Container Registry domain: {cr_settings['cr_domain']}") + click.echo(f"Container Registry namespace name: {cr_settings['cr_namespace_name']}") + click.echo(f"Container Registry region: {cr_settings['cr_region']}") + click.echo(f"Container Registry instance name: {cr_settings['cr_instance_name']}") + click.echo(f"Container Registry repo: {cr_settings['cr_repo']}") if not function_id: click.echo( From 882dab829623635e477525f667558503f2a21a14 Mon Sep 17 00:00:00 2001 From: "wuqingfu.528" Date: Mon, 8 Sep 2025 17:14:06 +0800 Subject: [PATCH 5/5] fix: cr-repo-name --- veadk/cli/cli_pipeline.py | 14 +++++++------- .../ve_code_pipeline/ve_code_pipeline.py | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/veadk/cli/cli_pipeline.py b/veadk/cli/cli_pipeline.py index 2b006aae..66efe819 100644 --- a/veadk/cli/cli_pipeline.py +++ b/veadk/cli/cli_pipeline.py @@ -56,7 +56,7 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) vecr._create_repo( instance_name=cr_settings["cr_instance_name"], namespace_name=cr_settings["cr_namespace_name"], - repo_name=cr_settings["cr_repo"], + repo_name=cr_settings["cr_repo_name"], ) except Exception as e: click.echo(f"Failed to create CR repo: {e}") @@ -110,9 +110,9 @@ def _create_cr(volcengine_settings: dict[str, str], cr_settings: dict[str, str]) help="Container Registry namespace name, default is veadk-user-namespace", ) @click.option( - "--cr-repo", + "--cr-repo-name", default=DEFAULT_CR_REPO_NAME, - help="Container Registry repo, default is veadk-user-repo", + help="Container Registry repo name, default is veadk-user-repo", ) @click.option( "--cr-region", @@ -134,7 +134,7 @@ def pipeline( region: str, cr_instance_name: str, cr_namespace_name: str, - cr_repo: str, + cr_repo_name: str, cr_region: str, function_id: str, ) -> None: @@ -154,7 +154,7 @@ def pipeline( "cr_domain": f"{cr_instance_name}-{cr_region}.cr.volces.com", "cr_instance_name": cr_instance_name, "cr_namespace_name": cr_namespace_name, - "cr_repo": cr_repo, + "cr_repo_name": cr_repo_name, "cr_region": cr_region, } @@ -165,7 +165,7 @@ def pipeline( click.echo(f"Container Registry namespace name: {cr_settings['cr_namespace_name']}") click.echo(f"Container Registry region: {cr_settings['cr_region']}") click.echo(f"Container Registry instance name: {cr_settings['cr_instance_name']}") - click.echo(f"Container Registry repo: {cr_settings['cr_repo']}") + click.echo(f"Container Registry repo name: {cr_settings['cr_repo_name']}") if not function_id: click.echo( @@ -200,7 +200,7 @@ def pipeline( cr_namespace_name=cr_settings["cr_namespace_name"], cr_region=cr_settings["cr_region"], cr_instance_name=cr_settings["cr_instance_name"], - cr_repo=cr_settings["cr_repo"], + cr_repo_name=cr_settings["cr_repo_name"], function_id=function_id, ) diff --git a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py index 05b09d26..fd106912 100644 --- a/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py +++ b/veadk/integrations/ve_code_pipeline/ve_code_pipeline.py @@ -54,7 +54,7 @@ crNamespace: ${cr_namespace_name} crRegion: ${cr_region} crRegistryInstance: ${cr_instance_name} - crRepo: ${cr_repo} + crRepo: ${cr_repo_name} crTag: $(DATETIME) disableSSLVerify: false dockerfiles: @@ -190,7 +190,7 @@ def _create_pipeline( cr_namespace_name: str, cr_region: str, cr_instance_name: str, - cr_repo: str, + cr_repo_name: str, docker_file: str, function_id: str, ) -> str: @@ -206,7 +206,7 @@ def _create_pipeline( cr_namespace_name=cr_namespace_name, cr_region=cr_region, cr_instance_name=cr_instance_name, - cr_repo=cr_repo, + cr_repo_name=cr_repo_name, docker_file=docker_file, function_id=function_id, ) @@ -388,7 +388,7 @@ def deploy( cr_namespace_name: str, cr_region: str, cr_instance_name: str, - cr_repo: str, + cr_repo_name: str, function_id: str, ) -> str: workspace_id = self._get_default_workspace() @@ -407,7 +407,7 @@ def deploy( cr_namespace_name=cr_namespace_name, cr_region=cr_region, cr_instance_name=cr_instance_name, - cr_repo=cr_repo, + cr_repo_name=cr_repo_name, docker_file=get_dockerfile(tag=base_image_tag), function_id=function_id, )