# 1 开始节点 开始节点无需任何操作 直接成功即可 start_node = models.Node.objects.filter(text='开始',task_id=task_id).first() # 修改开始节点颜色数据 start_node.status = 'green' start_node.save() # 将修改的数据变动发送给前端 async_to_sync(self.channel_layer.group_send)(task_id,{'type':'my.send', 'message':{'code':'deploy', 'node_id':start_node.pk, 'color':start_node.status } } ) # 2 下载前 if task_obj.before_download_script: # TODO:真正的下载脚本内容并在本地执行 before_download_node = models.Node.objects.filter(text='下载前',task_id=task_id).first() before_download_node.status = 'green' before_download_node.save() # 将修改的数据变动发送给前端 async_to_sync(self.channel_layer.group_send)(task_id, {'type': 'my.send', 'message': {'code': 'deploy', 'node_id': before_download_node.pk, 'color': before_download_node.status } }
- 代码优化
# 将真正操作节点的所有操作封装成一个类的方法
- channel-layers小bug修复
# 我们尝试着先模拟延迟 看看是否能够直接在前端展示出延时的效果 if text == 'deploy': # 调用deploy方法 完成发布操作 # self.deploy(task_id,task_obj) 类似于单线程无法实现节点渐变式效果(会等待数据放入队列全部完成,统一群发) # 自己开设一个线程处理发布任务 thread = threading.Thread(target=self.deploy,args=(task_id,task_obj)) thread.start()
- 等代码能够正常运行了之后再去真正的书写执行代码
- 从远程仓库下载的代码和脚本应该存储在特定的位置
"""这里我们直接采用存储在本地的方式 (你可以存储到远程服务器)""" # 文件结构 -codes --bbs --cmdb --luffycity --luffycity-test-v1-12313 --luffycity --项目代码 --scripts -- 脚本文件 import os from django.conf import settings project_name = task_obj.project.title uid = task_obj.uid script_folder = os.path.join(settings.DEPLOY_CODE_PATH,project_name,uid,'scripts') project_folder = os.path.join(settings.DEPLOY_CODE_PATH,project_name,uid,project_name) # 如果代码判断文件夹是否存在并决定是否动态创建 if not os.path.exists(script_folder): # 如何一次性创建多级目录 makedirs os.makedirs(script_folder) if not os.path.exists(project_folder): os.makedirs(project_folder)
- 一旦某一个环节执行错误 应该立刻停止下面所有的操作,没必要再执行
# 2 下载前 if task_obj.before_download_script: # TODO:真正的下载脚本内容并在本地执行 """ 1 将钩子脚本内容下载到本地 2 在本地执行该脚本 """ script_name = 'before_download_script.py' script_path = os.path.join(script_folder,script_name) # 文件操作存储内容 with open(script_path,'w',encoding='utf-8') as f: f.write(task_obj.before_download_script) # 执行脚本内容 subprocess 该模块可以模拟计算机的终端 import subprocess status = 'green' try: subprocess.check_output('python {0}'.format(script_name), shell = True, cwd = script_folder # 先切换到script_folder路径下再执行命令 ) except Exception as e: # 只要报异常 说明脚本文件内的代码写的不对 status = 'red' before_download_node = models.Node.objects.filter(text='下载前', task_id=task_id).first() before_download_node.status = status before_download_node.save() # 将修改的数据变动发送给前端 async_to_sync(self.channel_layer.group_send)(task_id, {'type': 'my.send', 'message': {'code': 'deploy', 'node_id': before_download_node.pk, 'color': status } } ) # 一旦允许出错 代码就不应该继续往下允许 if status == 'red': return
- 下载和上传代码真正实现
# 参考今日代码 status = 'green' try: # from app01.utils.ab_git import GitRepository # obj = GitRepository(project_folder,task_obj.project.repo,task_obj.tag) # 借助于gitpython模块下载代码 from git.repo import Repo # 下载远程仓库的代码可以怎么搞 clone pull # 先定义代码的存放位置 Repo.clone_from(task_obj.project.repo, to_path=project_folder, branch='master') pass except Exception as e: status = 'red' # 模拟下载延迟 # time.sleep(3) download_node = models.Node.objects.filter(text='下载', task_id=task_id).first() # 修改开始节点颜色数据 download_node.status = status download_node.save() # 将修改的数据变动发送给前端 async_to_sync(self.channel_layer.group_send)(task_id, {'type': 'my.send', 'message': {'code': 'deploy', 'node_id': download_node.pk, 'color': status } } ) if status == 'red': return
- 需要服务器上面的操作 需要用continue
for server_obj in task_obj.project.servers.all(): # 6.1 服务器 # time.sleep(3) status = 'green' try: # 将代码上传到服务器上 习惯将数据打包降低大小提升传输速率 这里我们也一样 对代码数据继续打包再上传 upload_folder_path = os.path.join(settings.DEPLOY_CODE_PATH,project_name,uid) # 对上述文件继续压缩 """针对压缩之后的文件夹存储位置 也是单独存储""" import shutil pack_path = shutil.make_archive( base_name=os.path.join(package_folder,uid+'.zip'), # 压缩包路径, format = 'zip', # zip tar rar root_dir= upload_folder_path # 待压缩的文件 ) # 上传代码 paramiko模块 from app01.utils.ssh import SSHProxy with SSHProxy(server_obj.hostname,22,'root','jason123') as ssh: # 远程服务器也应该有一个存储代码的位置 remote_folder = os.path.join(settings.SERVER_PACKAGE_PATH,project_name) ssh.command('mkdir -p {0}'.format(remote_folder)) upload_path = os.path.join(remote_folder,uid+'.zip') #运行过程中,/变为 upload_path = upload_path.replace('\','/') # 替换当中标识符号 print('upload_path:',upload_path) obj.upload(pack_path,upload_path) except Exception as e: status = 'red' server_node = models.Node.objects.filter(text=server_obj.hostname, task_id=task_id, server=server_obj ).first() # 修改开始节点颜色数据 server_node.status = status server_node.save() # 将修改的数据变动发送给前端 async_to_sync(self.channel_layer.group_send)(task_id, {'type': 'my.send', 'message': {'code': 'deploy', 'node_id': server_node.pk, 'color': status } } ) if status == 'red': # 因为是多台服务器 一台出错了 结束当前服务器循环开始下一个服务器循环 continue
拓展