zoukankan      html  css  js  c++  java
  • 代码发布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. 发布页面实时展示日志信息

  • 相关阅读:
    pthread_once函数的简单示例
    pthread_join直接决定资源是否能够及时释放
    非分离线程未使用join函数例子:
    一个HTTP打趴80%面试者
    BM和KMP字符串匹配算法学习
    STL 几个容器的底层实现
    指针的引用(*&)与指针的指针(**)
    Maven 环境变量设置
    配置JAVA的环境变量
    Maven报错 解决方案。ERROR: No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id
  • 原文地址:https://www.cnblogs.com/ludingchao/p/12734913.html
Copyright © 2011-2022 走看看