mirror of https://github.com/openspug/spug
A api update
parent
0390a9003a
commit
dc4b1cd5bf
|
@ -0,0 +1,82 @@
|
|||
from django.db import models
|
||||
from libs import ModelMixin, human_time
|
||||
from apps.account.models import User
|
||||
from apps.config.models import Environment
|
||||
import json
|
||||
|
||||
|
||||
class App(models.Model, ModelMixin):
|
||||
EXTENDS = (
|
||||
('1', '常规发布'),
|
||||
('2', '自定义发布'),
|
||||
)
|
||||
name = models.CharField(max_length=50)
|
||||
env = models.ForeignKey(Environment, on_delete=models.PROTECT)
|
||||
host_ids = models.TextField()
|
||||
extend = models.CharField(max_length=2, choices=EXTENDS)
|
||||
is_audit = models.BooleanField()
|
||||
|
||||
created_at = models.CharField(max_length=20, default=human_time)
|
||||
created_by = models.ForeignKey(User, models.PROTECT, related_name='+')
|
||||
updated_at = models.CharField(max_length=20, null=True)
|
||||
updated_by = models.ForeignKey(User, models.PROTECT, related_name='+', null=True)
|
||||
|
||||
@property
|
||||
def extend_obj(self):
|
||||
cls = AppExtend1 if self.extend == '1' else AppExtend2
|
||||
return cls.objects.filter(app=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
|
||||
|
||||
def __repr__(self):
|
||||
return '<App %r>' % self.name
|
||||
|
||||
class Meta:
|
||||
db_table = 'apps'
|
||||
ordering = ('-id',)
|
||||
|
||||
|
||||
class AppExtend1(models.Model, ModelMixin):
|
||||
GIT_TYPES = (
|
||||
('tag', 'tag'),
|
||||
('branch', 'branch')
|
||||
)
|
||||
app = models.OneToOneField(App, 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()
|
||||
filter_rule = models.TextField()
|
||||
custom_envs = models.TextField()
|
||||
hook_pre_server = models.TextField(null=True)
|
||||
hook_post_server = models.TextField(null=True)
|
||||
hook_pre_host = models.TextField(null=True)
|
||||
hook_post_host = models.TextField(null=True)
|
||||
|
||||
def to_dict(self, *args, **kwargs):
|
||||
tmp = super().to_dict(*args, **kwargs)
|
||||
tmp['filter_rule'] = json.loads(self.filter_rule)
|
||||
tmp['custom_envs'] = '\n'.join(f'{k}={v}' for k, v in json.loads(self.custom_envs).items())
|
||||
return tmp
|
||||
|
||||
def __repr__(self):
|
||||
return '<AppExtend1 app_id=%r>' % self.app_id
|
||||
|
||||
class Meta:
|
||||
db_table = 'app_extend1'
|
||||
|
||||
|
||||
class AppExtend2(models.Model, ModelMixin):
|
||||
app = models.OneToOneField(App, primary_key=True, on_delete=models.CASCADE)
|
||||
actions = models.TextField()
|
||||
|
||||
def __repr__(self):
|
||||
return '<AppExtend2 app_id=%r>' % self.app_id
|
||||
|
||||
class Meta:
|
||||
db_table = 'app_extend2'
|
|
@ -0,0 +1,7 @@
|
|||
from django.urls import path
|
||||
|
||||
from .views import *
|
||||
|
||||
urlpatterns = [
|
||||
path('', AppView.as_view()),
|
||||
]
|
|
@ -0,0 +1,66 @@
|
|||
from django.views.generic import View
|
||||
from libs import JsonParser, Argument, json_response
|
||||
from apps.app.models import App, AppExtend1, AppExtend2
|
||||
import json
|
||||
|
||||
|
||||
class AppView(View):
|
||||
def get(self, request):
|
||||
apps = App.objects.all()
|
||||
return json_response(apps)
|
||||
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
Argument('name', 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('is_audit', type=bool, default=False)
|
||||
).parse(request.body)
|
||||
if error is None:
|
||||
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='请输入保留历史版本数量'),
|
||||
Argument('filter_rule', type=dict, help='参数错误'),
|
||||
Argument('custom_envs', handler=str.strip, required=False),
|
||||
Argument('hook_pre_server', handler=str.strip, default=''),
|
||||
Argument('hook_post_server', handler=str.strip, default=''),
|
||||
Argument('hook_pre_host', handler=str.strip, default=''),
|
||||
Argument('hook_post_host', handler=str.strip, default='')
|
||||
).parse(request.body)
|
||||
if error:
|
||||
return json_response(error=error)
|
||||
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)
|
||||
else:
|
||||
app = App.objects.create(created_by=request.user, **form)
|
||||
AppExtend1.objects.create(app=app, **extend_form)
|
||||
elif form.extend == '2':
|
||||
extend_form, error = JsonParser(
|
||||
Argument('actions', type=list, filter=lambda x: len(x), help='请输入执行动作')
|
||||
).parse(request.body)
|
||||
if error:
|
||||
return json_response(error=error)
|
||||
app = App.objects.create(created_by=request.user, **form)
|
||||
AppExtend2.objects.create(app=app, actions=json.dumps(extend_form.actions))
|
||||
return json_response(error=error)
|
||||
|
||||
|
||||
def parse_envs(data):
|
||||
tmp = {}
|
||||
if data:
|
||||
for line in data.split('\n'):
|
||||
fields = line.split('=', 1)
|
||||
if len(fields) != 2 or fields[0].strip() == '':
|
||||
raise Exception(f'解析自定义全局变量{line!r}失败,确认其遵循 key = value 格式')
|
||||
tmp[fields[0].strip()] = fields[1].strip()
|
||||
return tmp
|
|
@ -206,11 +206,11 @@ def parse_text(request):
|
|||
Argument('o_id', type=int, help='缺少必要参数'),
|
||||
Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'),
|
||||
Argument('env_id', type=int, help='缺少必要参数'),
|
||||
Argument('data', help='缺少必要参数')
|
||||
Argument('data', handler=str.strip, help='缺少必要参数')
|
||||
).parse(request.body)
|
||||
if error is None:
|
||||
data = {}
|
||||
for line in form.pop('data').strip().split('\n'):
|
||||
for line in form.pop('data').split('\n'):
|
||||
fields = line.split('=', 1)
|
||||
if len(fields) != 2 or fields[0].strip() == '':
|
||||
return json_response(error=f'解析配置{line!r}失败,确认其遵循 key = value 格式')
|
||||
|
|
|
@ -17,7 +17,8 @@ class Argument(object):
|
|||
:param bool required: is required
|
||||
"""
|
||||
|
||||
def __init__(self, name, default=None, required=True, type=str, filter=None, help=None, nullable=False):
|
||||
def __init__(self, name, default=None, handler=None, required=True, type=str, filter=None, help=None,
|
||||
nullable=False):
|
||||
self.name = name
|
||||
self.default = default
|
||||
self.type = type
|
||||
|
@ -25,6 +26,7 @@ class Argument(object):
|
|||
self.nullable = nullable
|
||||
self.filter = filter
|
||||
self.help = help
|
||||
self.handler = handler
|
||||
if not isinstance(self.name, str):
|
||||
raise TypeError('Argument name must be string')
|
||||
if filter and not callable(self.filter):
|
||||
|
@ -63,6 +65,8 @@ class Argument(object):
|
|||
if not self.filter(value):
|
||||
raise ParseError(
|
||||
self.help or 'Value Error: %s filter check failed' % self.name)
|
||||
if self.handler:
|
||||
value = self.handler(value)
|
||||
return value
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ INSTALLED_APPS = [
|
|||
'apps.monitor',
|
||||
'apps.alarm',
|
||||
'apps.config',
|
||||
'apps.app',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -24,4 +24,5 @@ urlpatterns = [
|
|||
path('alarm/', include('apps.alarm.urls')),
|
||||
path('setting/', include('apps.setting.urls')),
|
||||
path('config/', include('apps.config.urls')),
|
||||
path('app/', include('apps.app.urls')),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue