标签:route col xxx lin save sync deploy url 节点
* 任务单展示页
不是直接书写增删改查,由于任务肯定是给项目使用的,所以做成了项目的一个展示字段,点击先查看当前项目所有的任务单记录,之后渲染添加按钮完成添加功能
这么做的目的在于添加任务的时候无需选择项目,
* 任务单添加页
一开始我们也是公用项目与服务器表的添加页面
并且添加页涉及到前端标签渲染,数据校验,信息展示所以借助于modelform完成
并不是模型表中所有的字段都需要展示到前端,exclude剔除(uid,project,status)
后台重写save方法,将uid和project手动传值
对任务单的添加页单独开设html文件书写
该页面有三块区域
* 当前任务对应的项目基本信息展示
* 基本配置
* 脚本钩子
注意脚本钩子的个数是不固定的,根据不同的业务逻辑设计不同个数的钩子
前端样式代码拷贝书写
? 针对钩子界面需要额外的渲染select选择框、checkbox、文本框
?
? 钩子模版的保存脚本功能
* 发布任务界面简单搭建
websocket、gojs、paramiko、gitpython
知识简单的实现了,gojs数据取决于后端
* 数据的群发功能
我们之前也实现过群聊的功能,但是我们那种是非主流的,不推荐使用
如果你想要完美的实现群发功能,channels也给你提供了相关的模块
配置文件中配置
# settings中配置
# channel-layers配置
CHANNEL_LAYERS = {
‘default‘: {
‘BACKEND‘:‘channels.layers.InMemoryChannelLayer‘
}
}
用户再连接的时候就应该分配到不同的群号
group_add()
# 将当前的用户加入到群聊中 (括号内子一个参数是群号,第二个是用户的唯一表示)
async_to_sync(self.channel_layer.group_add(task_id,self.channel_layer))
group_send()
# 给特定群号里面的用户发送数据
async_to_sync(self.channel_layer.group_send)(‘123‘,{‘type‘:‘my.send‘,‘message‘:{‘code‘:‘init‘,‘data‘:node_list}})
‘‘‘
type参数指定的是发送数据的方法
my.send > > > 自定义一个my_send 方法
xxx.ooo > > > 自定义一个xxx_ooo方法
message参数后指定的是发送的数据
将message后面的数据交给type指定的方法发送给用户
‘‘‘
def mysend(self,event):
‘‘‘发送数据功能
async_to_sync 会循环调用该方法,给群聊这里面的每一个用户发送数据
for obj in [obj1,obj2,obj3]:
obj.send()
‘‘‘
# 获取message后面的数据
message = event.get(‘message‘)
# 直接发送
self.send(json.dumps(message))
self.scope
# self.scope 看成一个大字典,字典中有前端的所有信息
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
# task_id = self.scope[‘url_route‘][‘args‘].get(‘task_id‘) 无名分组
group_disacad
def websocket_disconnect(self, message):
# 当前用户断开连接之后,应该提出群聊
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
# 去群里将用户剔除
async_to_sync(self.channel_layer.group_disacad)(task_id,self.channel_name)
raise StopConsumer
每一个任务都有自己的对应节点,并且发布之后的任务,在查看的时候应该默认展示之前已经发布了的节点状态
所以根据节点数据应该单独开设一张表来存储
class Node(models.Model):
# 一个任务单有多个节点
task = models.ForeignKey(verbose_name=‘发布任务单‘,to=‘DeployTask‘)
text = models.CharField(verbose_name=‘节点文字‘,max_length=32)
# 节点颜色 初始化颜色 成功之后的颜色 失败之后的颜色
status_choices = [
(‘lightgray‘,‘待发布‘),
(‘green‘,‘成功‘),
(‘red‘,‘失败‘),
]
status = models.CharField(verbose_name=‘状态‘,max_length=32,choices=status_choices,default=‘lightgray‘)
# 自关联 根节点 子节点
parent = models.ForeignKey(verbose_name=‘父节点‘,to=‘self‘,null=True,blank=True)
# 节点与服务器 一对多
servers = models.ForeignKey(to=‘Server‘,verbose_name=‘服务器‘,null=True,blank=True)
根据数据库的信息进行数据的展示
开始,下载,打包上传,服务器
优化
先做基本的节点,不靠考虑钩子节点
开始,下载,打包上传,服务器
代码
def websocket_receive(self, message):
text = message.get(‘text‘)
if text == ‘init‘:
# node_list = [
# {"key": "start", "text": ‘开始‘, "figure": ‘Ellipse‘, "color": "lightgreen"},
# {"key": "download", "parent": ‘start‘, "text": ‘下载代码‘, "color": "lightgreen", "link_text": ‘执行中...‘},
# {"key": "compile", "parent": ‘download‘, "text": ‘本地编译‘, "color": "lightgreen"},
# {"key": "compile", "parent": ‘download‘, "text": ‘本地编译‘, "color": "lightgreen"},
# {"key": "compile", "parent": ‘download‘, "text": ‘本地编译‘, "color": "lightgreen"},
# ]
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
# 动态创建节点信息
‘‘‘
先做基本的节点,不靠考虑钩子节点
开始,下载,打包上传,服务器
‘‘‘
# 添加节点对象到列表中
node_object_list = []
# 判断当前任务是否已经创建过图表数据
node_query = models.Node.objects.filter(task_id=task_id)
if not node_query: # 进行创建
# 1.先创建节点
start_node = models.Node.objects.create(text=‘开始‘,task_id=task_id)
node_object_list.append(start_node)
# 下载节点
down_load_node = models.Node.objects.create(text=‘下载‘,task_id=task_id,parent=start_node)
node_object_list.append(down_load_node)
# 上传节点
upload_node = models.Node.objects.create(text=‘上传‘,task_id=task_id,parent=down_load_node)
node_object_list.append(upload_node)
# 服务器节点需要考虑服务器的个数
task_obj = models.DeployTask.objects.filter(pk=task_id).first()
# 跨表查询获得所有的服务器对象
for server_obj in task_obj.project.servers.all():
server_node = models.Node.objects.create(text=server_obj.hostname,
task_id=task_id,
parent=upload_node,
servers=server_obj
)
node_object_list.append(server_node)
else: # 有数据直接使用数据库的
node_object_list = node_query
# 2.构造gojs需要的节点数据
node_list = []
for node_object in node_object_list:
temp = {
‘key‘: str(node_object.pk),
‘text‘: node_object.text,
‘color‘: node_object.status
}
# 判断当前节点对象是否有父节点,如果有则需要再添加一对键值对 parent
if node_object.parent:
temp[‘parent‘] = str(node_object.parent_id)
# 添加到列表中
node_list.append(temp) # [{}, {}, {}]
# 单独给当前连接对象发送数据
# self.send(text_data=json.dumps({"code":‘init‘,‘data‘:node_list}))
# 给特定群号里面的用户发送数据
async_to_sync(self.channel_layer.group_send)(‘123‘,{‘type‘:‘my.send‘,‘message‘:{‘code‘:‘init‘,‘data‘:node_list}})
‘‘‘
type参数指定的是发送数据的方法
my.send > > > 自定义一个my_send 方法
xxx.ooo > > > 自定义一个xxx_ooo方法
message参数后指定的是发送的数据
将message后面的数据交给type指定的方法发送给用户
‘‘‘
判断当前任务是否已经初始化节点数据,直接返回
def websocket_connect(self, message):
self.accept()
# 获取url中携带的无名或有名分组参数
# self.scope 看成一个大字典,字典中有前端的所有信息
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
# task_id = self.scope[‘url_route‘][‘args‘].get(‘task_id‘) 无名分组
# 将当前的用户加入到群聊中 (括号内子一个参数是群号,第二个是用户的唯一表示)
async_to_sync(self.channel_layer.group_add(task_id,self.channel_layer))
#优化: 查询当前任务是否已经初始化节点数据,如果有就直接返回给前端展示
node_queryset = models.Node.objects.filter(task_id=task_id)
if node_queryset:
node_list = []
for node_object in node_queryset:
temp = {
‘key‘: str(node_object.pk),
‘text‘: node_object.text,
‘color‘: node_object.status
}
# 判断当前节点对象是否有父节点,如果有则需要再添加一对键值对 parent
if node_object.parent:
temp[‘parent‘] = str(node_object.parent_id)
# 添加到列表中
node_list.append(temp) # [{}, {}, {}]
# 发送数据给前端 (单发,谁刷新页面给谁发送)
self.send(text_data=json.dumps({"code":‘init‘,‘data‘:node_list}))
就是判断当前任务对象是否有钩子脚本内容数据
if not node_query: # 进行创建
# 1.先创建节点
start_node = models.Node.objects.create(text=‘开始‘,task_id=task_id)
node_object_list.append(start_node)
# 判断用户是否填写了下载前钩子
if task_obj.before_download_script:
# 有 则需要创建节点,并利用变量名指向,将start_node由开始节点指向下载前钩子节点
start_node = models.Node.objects.create(text=‘下载前‘,task_id=task_id,parent=start_node)
node_object_list.append(start_node)
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
import json
from asgiref.sync import async_to_sync
from app01 import models
def create_node(task_obj,task_id):
# 判断当前任务是否已经创建过图表数据
node_object_list = models.Node.objects.filter(task_id=task_id)
if node_object_list:
return node_object_list
if not node_object_list: # 进行创建
node_object_list = []
# 1.先创建节点
start_node = models.Node.objects.create(text=‘开始‘, task_id=task_id)
node_object_list.append(start_node)
# 判断用户是否填写了下载前钩子
if task_obj.before_download_script:
# 有 则需要创建节点,并利用变量名指向,将start_node由开始节点指向下载前钩子节点
start_node = models.Node.objects.create(text=‘下载前‘, task_id=task_id, parent=start_node)
node_object_list.append(start_node)
# 下载节点
down_load_node = models.Node.objects.create(text=‘下载‘, task_id=task_id, parent=start_node)
node_object_list.append(down_load_node)
# 同理 下载后节点的创建也是如此
# 判断用户是否填写了下载前钩子
if task_obj.after_download_script:
# 有 则需要创建节点,并利用变量名指向,将start_node由开始节点指向下载前钩子节点
down_load_node = models.Node.objects.create(text=‘下载后‘, task_id=task_id, parent=down_load_node)
node_object_list.append(down_load_node)
# 上传节点
upload_node = models.Node.objects.create(text=‘上传‘, task_id=task_id, parent=down_load_node)
node_object_list.append(upload_node)
# 服务器节点需要考虑服务器的个数
task_obj = models.DeployTask.objects.filter(pk=task_id).first()
# 跨表查询获得所有的服务器对象
for server_obj in task_obj.project.servers.all():
server_node = models.Node.objects.create(text=server_obj.hostname,
task_id=task_id,
parent=upload_node,
servers=server_obj
)
node_object_list.append(server_node)
# 判断发布前钩子
if task_obj.before_deploy_script:
server_node = models.Node.objects.create(text=‘发布前‘,
task_id=task_id,
parent=server_node,
servers=server_obj
)
node_object_list.append(server_node)
# 额外的再添加一个节点 : 发布节点
deploy_node = models.Node.objects.create(text=‘发布‘,
task_id=task_id,
parent=server_node,
servers=server_obj
)
node_object_list.append(deploy_node)
# 同理 发布后的钩子
if task_obj.after_deploy_script:
after_deploy_ndoe = models.Node.objects.create(text=‘发布前‘,
task_id=task_id,
parent=deploy_node,
servers=server_obj
)
node_object_list.append(after_deploy_ndoe)
return node_object_list
def convert_object_to_js(node_object_list):
# 2.构造gojs需要的节点数据
node_list = []
for node_object in node_object_list:
temp = {
‘key‘: str(node_object.pk),
‘text‘: node_object.text,
‘color‘: node_object.status
}
# 判断当前节点对象是否有父节点,如果有则需要再添加一对键值对 parent
if node_object.parent:
temp[‘parent‘] = str(node_object.parent_id)
# 添加到列表中
node_list.append(temp) # [{}, {}, {}]
return node_list
class PublishConsumer(WebsocketConsumer):
def websocket_connect(self, message):
self.accept()
# 获取url中携带的无名或有名分组参数
# self.scope 看成一个大字典,字典中有前端的所有信息
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
# task_id = self.scope[‘url_route‘][‘args‘].get(‘task_id‘) 无名分组
# 将当前的用户加入到群聊中 (括号内子一个参数是群号,第二个是用户的唯一表示)
async_to_sync(self.channel_layer.group_add(task_id,self.channel_layer))
#优化: 查询当前任务是否已经初始化节点数据,如果有就直接返回给前端展示
node_queryset = models.Node.objects.filter(task_id=task_id)
if node_queryset:
node_list = convert_object_to_js(node_queryset)
# 发送数据给前端 (单发,谁刷新页面给谁发送)
self.send(text_data=json.dumps({"code":‘init‘,‘data‘:node_list}))
def websocket_receive(self, message):
text = message.get(‘text‘)
if text == ‘init‘:
# node_list = [
# {"key": "start", "text": ‘开始‘, "figure": ‘Ellipse‘, "color": "lightgreen"},
# {"key": "download", "parent": ‘start‘, "text": ‘下载代码‘, "color": "lightgreen", "link_text": ‘执行中...‘},
# {"key": "compile", "parent": ‘download‘, "text": ‘本地编译‘, "color": "lightgreen"},
# {"key": "compile", "parent": ‘download‘, "text": ‘本地编译‘, "color": "lightgreen"},
# {"key": "compile", "parent": ‘download‘, "text": ‘本地编译‘, "color": "lightgreen"},
# ]
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
task_obj = models.DeployTask.objects.filter(pk=task_id).first()
# 动态创建节点信息
‘‘‘
先做基本的节点,不靠考虑钩子节点
开始,下载,打包上传,服务器
‘‘‘
# 1.调用create_node()创建节点
node_object_list= create_node(task_obj, task_id)
# 2. 调用convert_object_to_js() 获取gojs所需数据
node_list = convert_object_to_js(node_object_list)
# 单独给当前连接对象发送数据
# self.send(text_data=json.dumps({"code":‘init‘,‘data‘:node_list}))
# 给特定群号里面的用户发送数据
async_to_sync(self.channel_layer.group_send)(‘123‘,{‘type‘:‘my.send‘,‘message‘:{‘code‘:‘init‘,‘data‘:node_list}})
‘‘‘
type参数指定的是发送数据的方法
my.send > > > 自定义一个my_send 方法
xxx.ooo > > > 自定义一个xxx_ooo方法
message参数后指定的是发送的数据
将message后面的数据交给type指定的方法发送给用户
‘‘‘
def mysend(self,event):
‘‘‘发送数据功能
async_to_sync 会循环调用该方法,给群聊这里面的每一个用户发送数据
for obj in [obj1,obj2,obj3]:
obj.send()
‘‘‘
# 获取message后面的数据
message = event.get(‘message‘)
# 直接发送
self.send(json.dumps(message))
def websocket_disconnect(self, message):
# 当前用户断开连接之后,应该提出群聊
task_id = self.scope[‘url_route‘][‘kwargs‘].get(‘task_id‘)
# 去群里将用户剔除
async_to_sync(self.channel_layer.group_disacad)(task_id,self.channel_name)
raise StopConsumer
点击发布任务按钮,执行操作并实时展示状态
远程仓库的代码保存到本地进行执行
标签:route col xxx lin save sync deploy url 节点
原文地址:https://www.cnblogs.com/fwzzz/p/12734004.html