Skip to content

Commit

Permalink
feat: 流程跨业务复制 TencentBlueKing#7626
Browse files Browse the repository at this point in the history
  • Loading branch information
guohelu committed Dec 6, 2024
1 parent 88d4c52 commit 39204d0
Show file tree
Hide file tree
Showing 14 changed files with 134 additions and 82 deletions.
10 changes: 6 additions & 4 deletions config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"gcloud.contrib.develop",
"gcloud.contrib.collection",
"gcloud.contrib.operate_record",
"gcloud.contrib.template_maker",
"gcloud.contrib.template_market",
"gcloud.apigw",
"gcloud.common_template",
"gcloud.label",
Expand Down Expand Up @@ -886,7 +886,9 @@ def check_engine_admin_permission(request, *args, **kwargs):
print(f"BROKER_URL: {BROKER_URL}")


# 共享模板开关
# 流程商店
ENABLE_TEMPLATE_MARKET = env.ENABLE_TEMPLATE_MARKET
# SRE 商店路由
FLOW_MARKET_API_URL = env.FLOW_MARKET_API_URL
# 流程商店 API 地址
TEMPLATE_MARKET_API_URL = env.TEMPLATE_MARKET_API_URL
# 流程跨业务复制
ENABLE_APIGW_COPY_TEMPLATE = env.ENABLE_APIGW_COPY_TEMPLATE
2 changes: 1 addition & 1 deletion config/urls_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
url(r"^plugin_service/", include("plugin_service.urls")),
url(r"^mako_operations/", include("gcloud.mako_template_helper.urls")),
url(r"^engine_admin/", include("pipeline.contrib.engine_admin.urls")),
url(r"^template_maker/", include("gcloud.contrib.template_maker.urls")),
url(r"^template_market/", include("gcloud.contrib.template_market.urls")),
]

schema_view = get_schema_view(
Expand Down
8 changes: 5 additions & 3 deletions env.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@
BK_AUDIT_ENDPOINT = os.getenv("BK_AUDIT_ENDPOINT", None)
BK_AUDIT_DATA_TOKEN = os.getenv("BK_AUDIT_DATA_TOKEN", None)

# 共享模板开关
# 流程商店
ENABLE_TEMPLATE_MARKET = False if os.getenv("ENABLE_TEMPLATE_MARKET") is None else True
# SRE 商店路由
FLOW_MARKET_API_URL = os.getenv("FLOW_MARKET_API_URL", "")
# 流程商店 API 地址
TEMPLATE_MARKET_API_URL = os.getenv("TEMPLATE_MARKET_API_URL", "")
# 流程跨业务复制
ENABLE_APIGW_COPY_TEMPLATE = False if os.getenv("ENABLE_APIGW_COPY_TEMPLATE") is None else True
2 changes: 2 additions & 0 deletions gcloud/apigw/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from gcloud.apigw.views.register_project import register_project
from gcloud.apigw.views.set_periodic_task_enabled import set_periodic_task_enabled
from gcloud.apigw.views.start_task import start_task
from gcloud.apigw.views.copy_template_across_biz import copy_template_across_biz

urlpatterns = [
url(r"^dispatch_plugin_query/$", dispatch_plugin_query),
Expand Down Expand Up @@ -129,4 +130,5 @@
url(r"^create_clocked_task/(?P<template_id>\d+)/(?P<project_id>\d+)/$", create_clocked_task),
url(r"^get_mini_app_list/(?P<project_id>\d+)/$", get_mini_app_list),
url(r"^get_task_count/(?P<project_id>\d+)/$", get_task_count),
url(r"^copy_template_across_biz/(?P<project_id>\d+)/$", copy_template_across_biz),
]
78 changes: 78 additions & 0 deletions gcloud/apigw/views/copy_template_across_biz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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 ujson as json
from apigw_manager.apigw.decorators import apigw_require
from blueapps.account.decorators import login_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST

from gcloud import err_code
from gcloud.apigw.decorators import (
mark_request_whether_is_trust,
project_inject,
return_json_response,
)

from gcloud.conf import settings
from gcloud.apigw.views.utils import logger
from gcloud.tasktmpl3.models import TaskTemplate
from gcloud.template_base.utils import format_import_result_to_response_data


@login_exempt
@csrf_exempt
@require_POST
@apigw_require
@return_json_response
@project_inject
@mark_request_whether_is_trust
def copy_template_across_biz(request, project_id):
if not request.is_trust or not settings.ENABLE_APIGW_COPY_TEMPLATE:
return {
"result": False,
"message": "you have no permission to call this api.",
"code": err_code.REQUEST_FORBIDDEN_INVALID.code,
}

params_data = json.loads(request.body)
new_project_id = params_data.get("new_project_id")
template_id = params_data.get("template_id")
template_id_list = [template_id] if template_id is not None else []

if not new_project_id or not template_id_list:
return {
"result": False,
"message": "missing or invalid parameter",
"code": err_code.REQUEST_PARAM_INVALID.code,
}

try:
export_data = TaskTemplate.objects.export_templates(
template_id_list, is_full=False, project_id=request.project.id
)
import_result = TaskTemplate.objects.import_templates(
template_data=export_data,
override=False,
project_id=new_project_id,
operator=request.user.username,
)
except Exception as e:
logger.exception("[API] copy common tempalte error: {}".format(e))
return {
"result": False,
"message": "invalid flow data or error occur, please contact administrator",
"code": err_code.UNKNOWN_ERROR.code,
}

return format_import_result_to_response_data(import_result)
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from django.contrib import admin

from gcloud.contrib.template_maker import models
from gcloud.contrib.template_market import models


@admin.register(models.TemplateSharedRecord)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

class TemplatemakerConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "gcloud.contrib.template_maker"
name = "gcloud.contrib.template_market"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 3.2.15 on 2024-12-05 07:07
# Generated by Django 3.2.15 on 2024-12-06 06:47

from django.db import migrations, models

Expand All @@ -16,9 +16,9 @@ class Migration(migrations.Migration):
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("project_id", models.IntegerField(default=-1, help_text="项目 ID", verbose_name="项目 ID")),
("template_id", models.IntegerField(db_index=True, help_text="模版 ID", verbose_name="模版 ID")),
("creator", models.CharField(help_text="执行者", max_length=128, verbose_name="执行者")),
("creator", models.CharField(default="", max_length=32, verbose_name="创建者")),
("create_at", models.DateTimeField(auto_now_add=True, verbose_name="创建时间")),
("extra_info", models.TextField(blank=True, null=True, verbose_name="额外信息")),
("extra_info", models.JSONField(blank=True, null=True, verbose_name="额外信息")),
],
options={
"verbose_name": "模板共享记录 TemplateSharedRecord",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
class TemplateSharedRecord(models.Model):
project_id = models.IntegerField(_("项目 ID"), default=-1, help_text="项目 ID")
template_id = models.IntegerField(_("模版 ID"), db_index=True, help_text="模版 ID")
creator = models.CharField(_("执行者"), max_length=128, help_text="执行者")
creator = models.CharField(_("创建者"), max_length=32, default="")
create_at = models.DateTimeField(_("创建时间"), auto_now_add=True)
extra_info = models.TextField(_("额外信息"), blank=True, null=True)
extra_info = models.JSONField(_("额外信息"), blank=True, null=True)

class Meta:
verbose_name = _("模板共享记录 TemplateSharedRecord")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,18 @@
"""

from rest_framework import serializers
from gcloud.contrib.template_maker.models import TemplateSharedRecord

from gcloud.constants import DATETIME_FORMAT
from gcloud.contrib.template_market.models import TemplateSharedRecord


class TemplateSharedRecordSerializer(serializers.ModelSerializer):
template_id = serializers.CharField(required=True, help_text="模板id")
project_id = serializers.CharField(required=True, help_text="项目id")
creator = serializers.CharField(required=False, max_length=32, help_text="创建者")
create_at = serializers.DateTimeField(required=False, help_text="创建时间", format=DATETIME_FORMAT)
extra_info = serializers.JSONField(required=False, allow_null=True, help_text="额外信息")

class Meta:
model = TemplateSharedRecord
fields = "__all__"

def validate(self, attrs):
project_id = attrs.get("project_id")
template_id = attrs.get("template_id")

if not project_id or not template_id:
raise serializers.ValidationError("Project ID and Template ID cannot be empty.")

if TemplateSharedRecord.objects.filter(project_id=project_id, template_id=template_id).exists():
raise serializers.ValidationError("The template has been shared")

return attrs
fields = ["project_id", "template_id", "creator", "create_at", "extra_info"]
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@

from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter
from gcloud.contrib.template_maker.viewsets import TemplateMarketViewSet, SharedTemplateViewSet
from gcloud.contrib.template_market.viewsets import StoreTemplateViewSet, SharedProcessTemplateViewSet


drf_api = DefaultRouter()
drf_api.register(r"template", TemplateMarketViewSet)
drf_api.register(r"shared", SharedTemplateViewSet)
drf_api.register(r"store_templates", StoreTemplateViewSet)
drf_api.register(r"shared_process_templates", SharedProcessTemplateViewSet)

urlpatterns = [
url(r"^api/", include(drf_api.urls)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,26 @@
"""

import logging
import requests

from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import permissions

from gcloud.conf import settings
from gcloud import err_code
from gcloud.contrib.template_maker.serializers import TemplateSharedRecordSerializer
from gcloud.contrib.template_maker.models import TemplateSharedRecord
from gcloud.core.apis.drf.serilaziers.task_template import TaskTemplateSerializer, TaskTemplateListSerializer
from gcloud.contrib.template_market.serializers import TemplateSharedRecordSerializer
from gcloud.contrib.template_market.models import TemplateSharedRecord
from gcloud.core.apis.drf.serilaziers.task_template import TaskTemplateSerializer
from gcloud.taskflow3.models import TaskTemplate
from gcloud.core.apis.drf.viewsets.base import GcloudModelViewSet


class TemplateMarkerPermission(permissions.BasePermission):
class StoreTemplatePermission(permissions.BasePermission):
def has_permission(self, request, view):
template_id = view.kwargs.get("pk")
project_id = request.GET.get("project_id")

if not template_id or not project_id:
logging.warning("template_id is required.")
logging.warning("Missing required parameters.")
return False
try:
TemplateSharedRecord.objects.get(template_id=template_id, project_id=project_id)
Expand All @@ -43,58 +41,45 @@ def has_permission(self, request, view):
return True


class SharedTemplatePermission(permissions.BasePermission):
class SharedProcessTemplatePermission(permissions.BasePermission):
def has_permission(self, request, view):
if not settings.ENABLE_TEMPLATE_MARKET:
return False
return True


class TemplateMarketViewSet(GcloudModelViewSet):
class StoreTemplateViewSet(viewsets.ViewSet):
queryset = TaskTemplate.objects.filter(pipeline_template__isnull=False, is_deleted=False)
permission_classes = [permissions.IsAuthenticated, TemplateMarkerPermission]

def get_serializer_class(self):
if self.action == "list":
return TaskTemplateListSerializer
return TaskTemplateSerializer
serializer_class = TaskTemplateSerializer
permission_classes = [permissions.IsAuthenticated, StoreTemplatePermission]

def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
instance = self.queryset.get(id=kwargs["pk"], project_id=request.GET.get("project_id"))
serializer = self.serializer_class(instance)

return Response(serializer.data)


class SharedTemplateViewSet(viewsets.ModelViewSet):
class SharedProcessTemplateViewSet(viewsets.ModelViewSet):
queryset = TemplateSharedRecord.objects.all()
serializer_class = TemplateSharedRecordSerializer
permission_classes = [permissions.IsAuthenticated, SharedTemplatePermission]
permission_classes = [permissions.IsAuthenticated, SharedProcessTemplatePermission]

def _get_market_routing(self, market_url):
return f"{settings.FLOW_MARKET_API_URL}/{market_url}"
return f"{settings.TEMPLATE_MARKET_API_URL}/{market_url}"

def retrieve(self, request, *args, **kwargs):
project_id = kwargs.get("pk")
template_id = request.GET.get("template_id")
serializer = self.get_serializer(data=request.GET)
serializer.is_valid(raise_exception=True)

url = self._get_market_routing("market/details/")
data = {"project_id": project_id, "template_id": template_id}
project_id = serializer.validated_data.get("project_id")
template_id = serializer.validated_data.get("template_id")

# 根据业务id和模板id从第三方接口获取模板详情
result = requests.post(url, data=data)
data = {"project_id": project_id, "template_id": template_id}

if not result or result.status_code != 200:
logging.exception("Get market template details from third party fails")
return Response(
{
"result": False,
"message": "Get market template details from third party fails",
"code": err_code.OPERATION_FAIL.code,
}
)
# todo: 调用第三方接口查询信息

return Response(result.json())
return Response({"result": True, "data": data, "code": err_code.SUCCESS.code})

def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
Expand All @@ -109,20 +94,7 @@ def create(self, request, *args, **kwargs):
logging.warning(f"Template with project_id {project_id} and template_id {template_id} not found.")
return Response({"result": False, "message": "Template not found", "code": err_code.OPERATION_FAIL.code})

# 执行第三方接口调用
url = self._get_market_routing("prod/api/")
data = {}
headers = None
result = requests.post(url, headers=headers, data=data)
if not result:
logging.exception("Sharing template to SRE store fails")
return Response(
{
"result": False,
"message": "Sharing template to SRE store fails",
"code": err_code.OPERATION_FAIL.code,
},
)
# todo: 调用第三方接口实现共享

self.perform_create(serializer)

Expand Down

0 comments on commit 39204d0

Please sign in to comment.