Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: release fix cr and test api #264

Merged
merged 8 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from apigateway.apis.web.resource_version.serializers import ResourceVersionInfoSLZ
from apigateway.apps.support.models import ResourceDoc, ResourceDocVersion
from apigateway.biz.releaser import BatchReleaser, ReleaseError
from apigateway.biz.releaser import ReleaseError, Releaser
from apigateway.biz.resource_version import ResourceVersionHandler
from apigateway.common.permissions import GatewayRelatedAppPermission
from apigateway.core.models import Release, ResourceVersion, Stage
Expand Down Expand Up @@ -118,7 +118,7 @@ def post(self, request, gateway_name: str, *args, **kwargs):
},
)

releaser = BatchReleaser(access_token=get_user_access_token_from_request(request))
releaser = Releaser(access_token=get_user_access_token_from_request(request))
try:
releaser.release(
request.gateway, data["stage_ids"], data["resource_version_id"], data["comment"], request.user.username
Expand Down
75 changes: 35 additions & 40 deletions src/dashboard/apigateway/apigateway/apis/web/release/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,23 @@
# We undertake not to change the open source license (MIT license) applicable
# to the current version of the project delivered to anyone in the future.
#
import json
from typing import List

from django.http import Http404
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers

from apigateway.biz.release import ReleaseHandler
from apigateway.common.fields import CurrentGatewayDefault, TimestampField
from apigateway.core.constants import PublishEventNameTypeEnum, PublishEventStatusEnum, ReleaseStatusEnum
from apigateway.core.models import ReleaseHistory, ResourceVersion, Stage
from apigateway.core.constants import (
PublishEventNameTypeEnum,
PublishEventStatusEnum,
)
from apigateway.core.models import PublishEvent, ReleaseHistory, ResourceVersion, Stage


class ReleaseInputSLZ(serializers.Serializer):
gateway = serializers.HiddenField(default=CurrentGatewayDefault())
stage_id = serializers.IntegerField(allow_null=True, required=True)
stage_id = serializers.IntegerField(required=True)
resource_version_id = serializers.IntegerField(required=True)

def validate_stage_id(self, value):
Expand All @@ -53,34 +56,36 @@ class ReleaseHistoryQueryInputSLZ(serializers.Serializer):
time_end = TimestampField(allow_null=True, required=False)


class ReleaseStageSLZ(serializers.Serializer):
id = serializers.IntegerField(read_only=True, help_text="环境id")
name = serializers.CharField(allow_blank=True, required=False, help_text="环境name")


class ReleaseHistoryOutputSLZ(serializers.Serializer):
publish_id = serializers.IntegerField(source="id", read_only=True, help_text="发布历史id")
stage_names = serializers.SerializerMethodField(read_only=True, help_text="发布环境列表")
id = serializers.IntegerField(read_only=True, help_text="发布历史id")
stage = ReleaseStageSLZ()
resource_version_display = serializers.SerializerMethodField(read_only=True, help_text="发布资源版本")
created_time = serializers.DateTimeField(read_only=True, help_text="发布创建事件")
created_by = serializers.CharField(read_only=True, help_text="发布人")
source = serializers.CharField(read_only=True, help_text="发布来源")
cost = serializers.SerializerMethodField(read_only=True, help_text="发布耗时")
duration = serializers.SerializerMethodField(read_only=True, help_text="发布耗时(s)")
status = serializers.SerializerMethodField(read_only=True, help_text="发布状态")
is_running = serializers.SerializerMethodField(read_only=True, help_text="是否正在发布")

def get_stage_names(self, obj: ReleaseHistory) -> List[str]:
return list(obj.stages.order_by("name").values_list("name", flat=True))

def get_resource_version_display(self, obj: ReleaseHistory) -> str:
return obj.resource_version.object_display

def get_status(self, obj: ReleaseHistory) -> str:
event = self.context["publish_events_map"].get(obj.id, None)
if event:
return f"{event.name} {event.status}"
event = self.context["release_history_events_map"].get(obj.id, None)
if not event:
# 兼容历史数据
return obj.status

# 兼容历史数据
return obj.message
# 通过最新的event获取release_history状态
return ReleaseHandler.get_status(event)

def get_cost(self, obj: ReleaseHistory) -> int:
def get_duration(self, obj: ReleaseHistory) -> int:
# 获取最新事件
event = self.context["publish_events_map"].get(obj.id, None)
event = self.context["release_history_events_map"].get(obj.id, None)
if not event:
return 0

Expand All @@ -89,38 +94,28 @@ def get_cost(self, obj: ReleaseHistory) -> int:
event.status != PublishEventStatusEnum.DOING.value
and event.name == PublishEventNameTypeEnum.LOAD_CONFIGURATION.value
):
return (event.created_time - obj.created_time).total_seconds()
return int((event.created_time - obj.created_time).total_seconds())

# 0代表还没到达终态
return 0

def get_is_running(self, obj: ReleaseHistory) -> bool:
# 获取最新事件
event = self.context["publish_events_map"].get(obj.id, None)
if not event:
# 兼容老数据
return obj.status not in [ReleaseStatusEnum.SUCCESS.value, ReleaseStatusEnum.FAILURE.value]

# 最新事件是否是doing
return event.is_running


class PublishEventInfoSLZ(serializers.Serializer):
event_id = serializers.IntegerField(source="id", read_only=True, help_text="发布事件id")
publish_id = serializers.IntegerField(allow_null=False, help_text="发布历史id")
name = serializers.CharField(read_only=True, help_text="发布事件节点名称")
class ReleaseHistoryEventInfoSLZ(serializers.Serializer):
id = serializers.IntegerField(read_only=True, help_text="发布事件id")
release_history_id = serializers.IntegerField(source="publish_id", allow_null=False, help_text="发布历史id")
name = serializers.SerializerMethodField(read_only=True, help_text="发布事件节点名称")
step = serializers.IntegerField(read_only=True, help_text="发布事件节点所属步骤")
status = serializers.CharField(read_only=True, help_text="发布事件状态")
created_time = serializers.DateTimeField(read_only=True, help_text="发布节点事件创建时间")
detail = serializers.SerializerMethodField(read_only=True, help_text="发布日志")
detail = serializers.DictField(read_only=True, help_text="发布日志")

def get_detail(self, obj):
return json.dumps(obj.detail)
def get_name(self, obj: PublishEvent) -> str:
return _(obj.name)


class PublishEventQueryOutputSLZ(ReleaseHistoryOutputSLZ):
events = serializers.ListField(child=PublishEventInfoSLZ(), allow_empty=True, help_text="发布事件列表")
class ReleaseHistoryEventRetrieveOutputSLZ(ReleaseHistoryOutputSLZ):
events = serializers.ListField(child=ReleaseHistoryEventInfoSLZ(), allow_empty=True, help_text="发布事件列表")

def to_representation(self, obj):
obj.events = self.context["publish_events"]
obj.events = self.context["release_history_events"]
return super().to_representation(obj)
16 changes: 7 additions & 9 deletions src/dashboard/apigateway/apigateway/apis/web/release/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@
from django.urls import include, path

from .views import (
PublishEventsRetrieveAPI,
ReleaseAvailableResourceListApi,
ReleaseCreateApi,
ReleasedResourceRetrieveApi,
ReleaseHistoryListApi,
ReleaseHistoryRetrieveApi,
RelishHistoryEventsRetrieveAPI,
)

urlpatterns = [
path("", ReleaseCreateApi.as_view(), name="gateway.release.create"),
path(
"stages/<int:stage_id>/available_resources/",
"stages/<int:stage_id>/resources/",
ReleaseAvailableResourceListApi.as_view(),
name="gateway.releases.available_resources",
),
Expand All @@ -40,13 +39,12 @@
[
path("", ReleaseHistoryListApi.as_view(), name="gateway.release_histories.list"),
path("latest/", ReleaseHistoryRetrieveApi.as_view(), name="gateway.release_histories.retrieve_latest"),
path(
"<int:history_id>/events/",
RelishHistoryEventsRetrieveAPI.as_view(),
name="gateway.release_histories.events",
),
]
),
),
path(
"resource-versions/<int:resource_version_id>/resources/<int:resource_id>/",
ReleasedResourceRetrieveApi.as_view(),
name="gateway.releases.released-resource.detail",
),
path("publish/<int:publish_id>/events/", PublishEventsRetrieveAPI.as_view(), name="gateway.publish.events"),
]
68 changes: 20 additions & 48 deletions src/dashboard/apigateway/apigateway/apis/web/release/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,18 @@
from drf_yasg.utils import swagger_auto_schema
from rest_framework import generics, status

from apigateway.apps.support.models import ReleasedResourceDoc
from apigateway.biz.release import ReleaseHandler
from apigateway.biz.released_resource import ReleasedResourceData
from apigateway.biz.releaser import BatchReleaser, ReleaseError
from apigateway.biz.releaser import ReleaseError, Releaser
from apigateway.common.error_codes import error_codes
from apigateway.core.models import Release, ReleasedResource, ReleaseHistory
from apigateway.core.models import Release, ReleaseHistory
from apigateway.utils.access_token import get_user_access_token_from_request
from apigateway.utils.exception import LockTimeout
from apigateway.utils.redis_utils import Lock
from apigateway.utils.responses import FailJsonResponse, OKJsonResponse

from .serializers import (
PublishEventQueryOutputSLZ,
ReleaseHistoryEventRetrieveOutputSLZ,
ReleaseHistoryOutputSLZ,
ReleaseHistoryQueryInputSLZ,
ReleaseInputSLZ,
Expand Down Expand Up @@ -97,39 +96,6 @@ def list(self, request, *args, **kwargs):
)


class ReleasedResourceRetrieveApi(generics.RetrieveAPIView):
lookup_field = "stage_id"

def get_queryset(self):
return Release.objects.filter(gateway=self.request.gateway)

@method_decorator(
name="get",
decorator=swagger_auto_schema(tags=["WebAPI.Release"]),
)
def get(self, request, *args, **kwargs):
try:
resource_version_id = request.query_params.get("resource_version_id")
resource_id = request.query_params.get("resource_id")
released_resource = ReleasedResource.objects.get(
gateway_id=request.gateway.id,
resource_version_id=resource_version_id,
resource_id=resource_id,
)
except ReleasedResource.DoesNotExist:
raise Http404

resource_data = released_resource.data
resource_data.update(
doc_updated_time=ReleasedResourceDoc.objects.get_doc_updated_time(
gateway_id=request.gateway.id,
resource_version_id=resource_version_id,
resource_id=resource_id,
)
)
return OKJsonResponse(data=resource_data)


@method_decorator(
name="post",
decorator=swagger_auto_schema(
Expand All @@ -153,7 +119,7 @@ def create(self, request, *args, **kwargs):
stage_id = slz.validated_data["stage_id"]
gateway_id = request.gateway.id

releaser = BatchReleaser(access_token=get_user_access_token_from_request(request))
releaser = Releaser(access_token=get_user_access_token_from_request(request))
try:
with Lock(
f"{gateway_id}_{stage_id}",
Expand All @@ -162,7 +128,7 @@ def create(self, request, *args, **kwargs):
):
history = releaser.release(
request.gateway,
[slz.validated_data["stage_id"]],
slz.validated_data["stage_id"],
slz.validated_data["resource_version_id"],
slz.validated_data.get("comment", ""),
request.user.username,
Expand All @@ -177,7 +143,9 @@ def create(self, request, *args, **kwargs):
slz = ReleaseHistoryOutputSLZ(
history,
context={
"publish_events_map": ReleaseHandler.get_publish_id_to_latest_publish_event_map([history.id]),
"release_history_events_map": ReleaseHandler.get_release_history_id_to_latest_publish_event_map(
[history.id]
),
},
)
return OKJsonResponse(data=slz.data)
Expand Down Expand Up @@ -219,7 +187,7 @@ def list(self, request, *args, **kwargs):
page,
many=True,
context={
"publish_events_map": ReleaseHandler.get_publish_id_to_latest_publish_event_map(
"release_history_events_map": ReleaseHandler.get_release_history_id_to_latest_publish_event_map(
[release_history.id for release_history in page]
),
},
Expand Down Expand Up @@ -248,7 +216,9 @@ def retrieve(self, request, *args, **kwargs):
slz = slz_class(
instance,
context={
"publish_events_map": ReleaseHandler.get_publish_id_to_latest_publish_event_map([instance.id]),
"release_history_events_map": ReleaseHandler.get_release_history_id_to_latest_publish_event_map(
[instance.id]
),
},
)
return OKJsonResponse(data=slz.data)
Expand All @@ -258,13 +228,13 @@ def retrieve(self, request, *args, **kwargs):
name="get",
decorator=swagger_auto_schema(
operation_description="查询发布事件(日志)",
responses={status.HTTP_200_OK: PublishEventQueryOutputSLZ()},
responses={status.HTTP_200_OK: ReleaseHistoryEventRetrieveOutputSLZ()},
tags=["WebAPI.Release"],
),
)
class PublishEventsRetrieveAPI(generics.RetrieveAPIView):
serializer_class = PublishEventQueryOutputSLZ
lookup_url_kwarg = "publish_id"
class RelishHistoryEventsRetrieveAPI(generics.RetrieveAPIView):
serializer_class = ReleaseHistoryEventRetrieveOutputSLZ
lookup_url_kwarg = "history_id"

def get_queryset(self):
return ReleaseHistory.objects.filter(gateway=self.request.gateway)
Expand All @@ -274,8 +244,10 @@ def retrieve(self, request, *args, **kwargs):
slz = self.get_serializer(
release_history,
context={
"publish_events": ReleaseHandler.list_publish_events_by_release_history_id(release_history.id),
"publish_events_map": ReleaseHandler.get_publish_id_to_latest_publish_event_map([release_history.id]),
"release_history_events": ReleaseHandler.list_publish_events_by_release_history_id(release_history.id),
"release_history_events_map": ReleaseHandler.get_release_history_id_to_latest_publish_event_map(
[release_history.id]
),
},
)
return OKJsonResponse(data=slz.data)
Loading