代码发布6 点击发布按钮(执行节点对应的操作), 写入的执行代码处理,shutil模块压缩处理

点击发布按钮真正的执行节点背后对应的操作

  • 先假设所有的节点操作都是正常执行
# 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

拓展

1. 补全发布前和发布后的钩子脚本运行

2. 发布页面实时展示日志信息

原文地址:https://www.cnblogs.com/ludingchao/p/12734913.html