diff --git a/spug_api/apps/app/models.py b/spug_api/apps/app/models.py index d874626..8a81564 100644 --- a/spug_api/apps/app/models.py +++ b/spug_api/apps/app/models.py @@ -6,11 +6,26 @@ import json class App(models.Model, ModelMixin): + name = models.CharField(max_length=50) + key = models.CharField(max_length=50) + desc = models.CharField(max_length=255, null=True) + created_at = models.CharField(max_length=20, default=human_datetime) + created_by = models.ForeignKey(User, on_delete=models.PROTECT) + + def __repr__(self): + return f'' + + class Meta: + db_table = 'apps' + ordering = ('-id',) + + +class Deploy(models.Model, ModelMixin): EXTENDS = ( ('1', '常规发布'), ('2', '自定义发布'), ) - name = models.CharField(max_length=50) + app = models.ForeignKey(App, on_delete=models.PROTECT) env = models.ForeignKey(Environment, on_delete=models.PROTECT) host_ids = models.TextField() extend = models.CharField(max_length=2, choices=EXTENDS) @@ -23,31 +38,26 @@ class App(models.Model, ModelMixin): @property def extend_obj(self): - cls = AppExtend1 if self.extend == '1' else AppExtend2 - return cls.objects.filter(app=self).first() + cls = DeployExtend1 if self.extend == '1' else DeployExtend2 + return cls.objects.filter(deploy=self).first() def to_dict(self, *args, **kwargs): - app = super().to_dict(*args, **kwargs) - app['host_ids'] = json.loads(self.host_ids) - app.update(self.extend_obj.to_dict()) - return app + deploy = super().to_dict(*args, **kwargs) + deploy['host_ids'] = json.loads(self.host_ids) + deploy.update(self.extend_obj.to_dict()) + return deploy def __repr__(self): - return '' % self.name + return '' % self.app_id class Meta: - db_table = 'apps' + db_table = 'deploys' ordering = ('-id',) -class AppExtend1(models.Model, ModelMixin): - GIT_TYPES = ( - ('tag', 'tag'), - ('branch', 'branch') - ) - app = models.OneToOneField(App, primary_key=True, on_delete=models.CASCADE) +class DeployExtend1(models.Model, ModelMixin): + deploy = models.OneToOneField(Deploy, primary_key=True, on_delete=models.CASCADE) git_repo = models.CharField(max_length=255) - git_type = models.CharField(max_length=10, choices=GIT_TYPES) dst_dir = models.CharField(max_length=255) dst_repo = models.CharField(max_length=255) versions = models.IntegerField() @@ -65,14 +75,14 @@ class AppExtend1(models.Model, ModelMixin): return tmp def __repr__(self): - return '' % self.app_id + return '' % self.deploy_id class Meta: - db_table = 'app_extend1' + db_table = 'deploy_extend1' -class AppExtend2(models.Model, ModelMixin): - app = models.OneToOneField(App, primary_key=True, on_delete=models.CASCADE) +class DeployExtend2(models.Model, ModelMixin): + deploy = models.OneToOneField(Deploy, primary_key=True, on_delete=models.CASCADE) server_actions = models.TextField() host_actions = models.TextField() @@ -83,7 +93,7 @@ class AppExtend2(models.Model, ModelMixin): return tmp def __repr__(self): - return '' % self.app_id + return '' % self.deploy_id class Meta: - db_table = 'app_extend2' + db_table = 'deploy_extend2' diff --git a/spug_api/apps/app/urls.py b/spug_api/apps/app/urls.py index 3095888..4ea56a4 100644 --- a/spug_api/apps/app/urls.py +++ b/spug_api/apps/app/urls.py @@ -4,5 +4,6 @@ from .views import * urlpatterns = [ path('', AppView.as_view()), - path('/versions/', get_versions), + path('deploy/', DeployView.as_view()), + path('deploy//versions/', get_versions), ] diff --git a/spug_api/apps/app/utils.py b/spug_api/apps/app/utils.py index 2c4cf40..cbc6d99 100644 --- a/spug_api/apps/app/utils.py +++ b/spug_api/apps/app/utils.py @@ -1,5 +1,5 @@ from django.conf import settings -from apps.app.models import App +from apps.app.models import Deploy from libs.gitlib import Git import os @@ -15,7 +15,7 @@ def parse_envs(text): return data -def fetch_versions(app: App): - git_repo = app.extend_obj.git_repo - repo_dir = os.path.join(settings.REPOS_DIR, str(app.id)) +def fetch_versions(deploy: Deploy): + git_repo = deploy.extend_obj.git_repo + repo_dir = os.path.join(settings.REPOS_DIR, str(deploy.id)) return Git(git_repo, repo_dir).fetch_branches_tags() diff --git a/spug_api/apps/app/views.py b/spug_api/apps/app/views.py index 6ff9a1d..da9b842 100644 --- a/spug_api/apps/app/views.py +++ b/spug_api/apps/app/views.py @@ -1,6 +1,7 @@ from django.views.generic import View from libs import JsonParser, Argument, json_response -from apps.app.models import App, AppExtend1, AppExtend2 +from apps.app.models import App, Deploy, DeployExtend1, DeployExtend2 +from apps.config.models import Config from apps.app.utils import parse_envs, fetch_versions import json @@ -13,18 +14,59 @@ class AppView(View): def post(self, request): form, error = JsonParser( Argument('id', type=int, required=False), - Argument('name', help='请输入应用名称'), + Argument('name', help='请输入服务名称'), + Argument('key', help='请输入唯一标识符'), + Argument('desc', required=False) + ).parse(request.body) + if error is None: + app = App.objects.filter(key=form.key).first() + if app and app.id != form.id: + return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试') + if form.id: + App.objects.filter(pk=form.id).update(**form) + else: + App.objects.create(created_by=request.user, **form) + return json_response(error=error) + + def delete(self, request): + form, error = JsonParser( + Argument('id', type=int, help='请指定操作对象') + ).parse(request.GET) + if error is None: + if Deploy.objects.filter(app_id=form.id).exists(): + return json_response(error='该应用已存在关联的发布配置,请删除相关配置后再尝试删除') + if Config.objects.filter(type='app', o_id=form.id).exists(): + return json_response(error='该应用在配置中心已存在关联的配置信息,请删除相关配置后再尝试删除') + App.objects.filter(pk=form.id).delete() + return json_response(error=error) + + +class DeployView(View): + def get(self, request): + form, error = JsonParser( + Argument('id', type=int, help='参数错误') + ).parse(request.GET) + if error is None: + deploys = Deploy.objects.filter(app_id=form.id).all() + return json_response(deploys) + return json_response(error=error) + + def post(self, request): + form, error = JsonParser( + Argument('id', type=int, required=False), + Argument('app_id', type=int, help='请选择应用'), Argument('env_id', type=int, help='请选择环境'), Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择要部署的主机'), - Argument('extend', filter=lambda x: x in dict(App.EXTENDS), help='请选择发布类型'), + Argument('extend', filter=lambda x: x in dict(Deploy.EXTENDS), help='请选择发布类型'), Argument('is_audit', type=bool, default=False) ).parse(request.body) if error is None: + if Deploy.objects.filter(app_id=form.app_id, env_id=form.env_id).exists(): + return json_response(error='应用在该环境下已经存在发布配置') form.host_ids = json.dumps(form.host_ids) if form.extend == '1': extend_form, error = JsonParser( Argument('git_repo', handler=str.strip, help='请输入git仓库地址'), - Argument('git_type', help='参数错误'), Argument('dst_dir', handler=str.strip, help='请输入发布目标路径'), Argument('dst_repo', handler=str.strip, help='请输入目标仓库路径'), Argument('versions', type=int, help='请输入保留历史版本数量'), @@ -40,11 +82,11 @@ class AppView(View): extend_form.filter_rule = json.dumps(extend_form.filter_rule) extend_form.custom_envs = json.dumps(parse_envs(extend_form.custom_envs)) if form.id: - App.objects.filter(pk=form.id).update(**form) - AppExtend1.objects.filter(app_id=form.id).update(**extend_form) + Deploy.objects.filter(pk=form.id).update(**form) + DeployExtend1.objects.filter(deploy_id=form.id).update(**extend_form) else: - app = App.objects.create(created_by=request.user, **form) - AppExtend1.objects.create(app=app, **extend_form) + deploy = Deploy.objects.create(created_by=request.user, **form) + DeployExtend1.objects.create(deploy=deploy, **extend_form) elif form.extend == '2': extend_form, error = JsonParser( Argument('server_actions', type=list, help='请输入执行动作'), @@ -57,19 +99,27 @@ class AppView(View): extend_form.server_actions = json.dumps(extend_form.server_actions) extend_form.host_actions = json.dumps(extend_form.host_actions) if form.id: - App.objects.filter(pk=form.id).update(**form) - AppExtend2.objects.filter(app_id=form.id).update(**extend_form) + Deploy.objects.filter(pk=form.id).update(**form) + DeployExtend2.objects.filter(deploy_id=form.id).update(**extend_form) else: - app = App.objects.create(created_by=request.user, **form) - AppExtend2.objects.create(app=app, **extend_form.actions) + deploy = Deploy.objects.create(created_by=request.user, **form) + DeployExtend2.objects.create(deploy=deploy, **extend_form) + return json_response(error=error) + + def delete(self, request): + form, error = JsonParser( + Argument('id', type=int, help='请指定操作对象') + ).parse(request.GET) + if error is None: + Deploy.objects.filter(pk=form.id).delete() return json_response(error=error) def get_versions(request, a_id): - app = App.objects.filter(pk=a_id).first() - if not app: + deploy = Deploy.objects.filter(pk=a_id).first() + if not deploy: return json_response(error='未找到指定应用') - if app.extend == '2': + if deploy.extend == '2': return json_response(error='该应用不支持此操作') - branches, tags = fetch_versions(app) + branches, tags = fetch_versions(deploy) return json_response({'branches': branches, 'tags': tags}) diff --git a/spug_api/apps/deploy/models.py b/spug_api/apps/deploy/models.py index 9f5dd6b..51e72b6 100644 --- a/spug_api/apps/deploy/models.py +++ b/spug_api/apps/deploy/models.py @@ -1,7 +1,7 @@ from django.db import models from libs import ModelMixin, human_datetime from apps.account.models import User -from apps.app.models import App +from apps.app.models import Deploy class DeployRequest(models.Model, ModelMixin): @@ -17,7 +17,7 @@ class DeployRequest(models.Model, ModelMixin): ('1', '正常发布'), ('2', '回滚') ) - app = models.ForeignKey(App, on_delete=models.CASCADE) + deploy = models.ForeignKey(Deploy, on_delete=models.CASCADE) name = models.CharField(max_length=50) type = models.CharField(max_length=2, choices=TYPES, default='1') extra = models.TextField()