Beispiel #1
0
    def receive(self, text_data=None, bytes_data=None):
        info = json.loads(text_data)
        self.config = ProjectConfig.objects.select_related('project').get(
            id=info.get('config_id'))

        unique_key = self.config.project.project_name + self.config.project.project_env

        if self.redis_instance.get(unique_key):
            self.send('有相同的任务正在进行!请稍后重试!')
            self.close()
        else:
            self.redis_instance.set(unique_key, 1)
            timeline_header = '<li><i class="fa fa-flag bg-blue"></i><div class="timeline-item"><h3 class="timeline-header"><a href="javascript:void(0)">{}</a></h3><div class="timeline-body"></div></div></li>'
            cmd_detail = '<p style="font-style: italic; color: grey;">{}</p>'
            timeline_body_green = '<p style="color: #008000">{}</p>'
            timeline_body_red = '<p style="color: #FF0000">{}</p>'

            self.branch_tag = info.get('branch_tag')
            rollback = info.get('rollback', False)
            self.d_type = 'rollback' if rollback else 'deploy'
            commit = info.get('commit', None)
            self.release_name = commit if commit else self.branch_tag

            # 初始化ansible
            server_objs = self.config.deploy_server.all()
            host_ids = [server.id for server in server_objs]
            resource = gen_resource.GenResource().gen_host_list(
                host_ids=host_ids)
            self.host_list = [
                server.assets.asset_management_ip for server in server_objs
            ]
            ans = ansible_api_v2.ANSRunner(resource, sock=self)

            if self.config.repo == 'git':
                tool = GitTools(repo_url=self.config.repo_url,
                                path=self.config.src_dir,
                                env=self.config.project.project_env)

                tool.checkout(self.branch_tag)
                if commit:
                    tool.checkout(commit)
                    self.release_desc = tool.get_commit_msg(
                        self.branch_tag, commit)
                else:
                    self.release_desc = self.release_name

                self.deploy(rollback, timeline_header, cmd_detail,
                            timeline_body_green, timeline_body_red, ans, info,
                            tool)
            elif self.config.repo == 'svn':
                tool = SVNTools(repo_url=self.config.repo_url,
                                path=self.config.src_dir,
                                env=self.config.project.project_env,
                                username=self.config.repo_user,
                                password=self.config.repo_password)

                if commit:
                    model_name = '' if self.config.repo_model == 'trunk' else self.branch_tag
                    self.release_desc = tool.get_commit_msg(
                        int(commit),
                        self.config.repo_model,
                        model_name=model_name)
                else:
                    self.release_desc = self.release_name

                c = int(commit) if commit else None
                self.deploy(rollback,
                            timeline_header,
                            cmd_detail,
                            timeline_body_green,
                            timeline_body_red,
                            ans,
                            info,
                            tool,
                            repo='svn',
                            commit=c)

            self.close()
            self.redis_instance.delete(unique_key)
    def deploy(self, ticket_no, info, tool, step_msg, ok_msg, fail_msg,
               warn_msg):

        host_ids = info.get('dserver')  # 这里检测发布(回滚)服务器
        tid = Project_Deploy_Ticket.objects.get(id=info.get('tid'))
        dsList = []
        for hs in host_ids:
            ds = Assets.objects.get(id=hs)
            dt = Project_Deploy_Record.objects.filter(
                deploy_ip=ds.asset_management_ip, d_ticket_id=info.get('tid'))
            if dt.count() == 1:  # 是否有发布记录:有
                if self.d_type == "Rollback":  # 不要移动这个代码段位置,否则会逻辑错误!必需要先判断是否是回滚
                    if dt[0].rollback_times != dt[0].deploy_times:
                        self.send_save(
                            ok_msg.format("{ip} {hs} 第{times}次回滚").format(
                                ip=ds.asset_management_ip,
                                hs=ds.asset_hostname,
                                times=dt[0].rollback_times + 1,
                            ))
                        try:  # 回滚次数+1
                            dsList.append(hs)
                            dt.update(rollback_times=dt[0].rollback_times + 1,
                                      update_date=time.strftime(
                                          "%Y-%m-%d %H:%M:%S",
                                          time.localtime()))
                        except Exception as e:
                            self.send_save(
                                fail_msg.format(
                                    "更新 rollback_times + 1 回滚次数异常!{}").format(
                                        e))
                    else:
                        self.send_save(fail_msg.format("回滚次数不能大于发布次数!"))
                elif dt[0].deploy_status == 9:  # 判断记录是否发布成功:发布成功

                    if self.d_type == "Deploy":
                        self.send_save(
                            warn_msg.format(
                                "{ip} {hs} 发布记录为成功,请勿重复发布,踢出发布列表!").format(
                                    ip=ds.asset_management_ip,
                                    hs=ds.asset_hostname
                                    if ds.asset_hostname else 'null'))
                        if dt[0].deploy_times == 1:
                            self.send_save(
                                warn_msg.format(
                                    "{ip} {hs} 回滚记录为成功,请确认部署状态!").format(
                                        ip=ds.asset_management_ip,
                                        hs=ds.asset_hostname
                                        if ds.asset_hostname else 'null'))

                elif dt[0].deploy_status < 9:  # 判断记录是否发布成功:没有发成功
                    if self.d_type == 'Deploy':
                        self.send_save(
                            ok_msg.format(
                                "{ip} {hs} 第{times}次发布 Start").format(
                                    ip=ds.asset_management_ip,
                                    hs=ds.asset_hostname,
                                    times=dt[0].deploy_times + 1,
                                ))
                        try:  # 发布次数+1
                            dsList.append(hs)
                            dt.update(deploy_times=dt[0].deploy_times + 1,
                                      update_date=time.strftime(
                                          "%Y-%m-%d %H:%M:%S",
                                          time.localtime()))
                        except Exception as e:
                            self.send_save(
                                fail_msg.format(
                                    "更新 deploy_times + 1 发布次数异常!{}").format(e))

            elif dt.count() == 0:  # 是否有发布记录:无

                if self.d_type == 'Deploy':
                    self.send_save(
                        ok_msg.format("{ip} {hs} 第1次发布 Start").format(
                            ip=ds.asset_management_ip,
                            hs=ds.asset_hostname
                            if ds.asset_hostname else 'null'))

                    try:  # 创建发布记录表
                        dtc = Project_Deploy_Record.objects.create(
                            assets=ds,
                            deploy_ip=ds.asset_management_ip,
                            deploy_times=1,
                            d_ticket_id=tid,
                        )
                        dsList.append(hs)
                    except Exception as e:
                        self.send_save(
                            fail_msg.format("创建发布记录表异常! {}").format(e))
                        return

                elif self.d_type == 'Rollback':
                    self.send_save(
                        fail_msg.format("{} 没有发布记录,回滚终止!").format(
                            ds.asset_management_ip))
                else:
                    pass

        if dsList:
            resource = gen_resource.GenResource().gen_host_list(
                host_ids=dsList)
            self.host_list = [server['ip'] for server in resource]
            ans = ansible_api_v2.ANSRunner(resource, sock=self)
        else:
            self.send_save(fail_msg.format("没有发布(回滚)主机,部署终止!"), close=True)
            return

        if self.d_type == 'Deploy':
            # 执行同步代码之前的命令,比如编译等
            if self.config.ticket_config.proj_role.post_deploy:
                try:
                    code = tool.run_cmd(
                        self.config.ticket_config.proj_role.post_deploy)
                    if code == 0:
                        self.send_save(ok_msg.format("执行同步代码之前的命令成功"))
                    else:
                        self.send_save(fail_msg.format("执行同步代码之前的命令失败"))
                        return
                except Exception as e:
                    self.send_save(
                        fail_msg.format("执行同步代码之前的命令异常! {}").format(e))
                    return

            # 检测目标机器是否连通,如果连通,判断是否存在存储代码版本的路径,如果不存在就创建
            ans.run_module(
                self.host_list,
                module_name='file',
                module_args='path={} state=directory'.format(
                    os.path.join(
                        self.config.ticket_config.proj_role.deploy_releases,
                        tool.proj_name)),
                deploy=True,
                d_type=self.d_type,
                task='connet',
                tid=tid.id)

            # 备份代码目录
            try:
                backup_dir = self.gen_dir(
                    tool, ticket_no,
                    backup="backup") + "/" + time.strftime("%Y%m%d%H%M%S")
                backup_dest = os.path.join(
                    self.config.ticket_config.proj_role.deploy_webroot,
                    tool.proj_name)
                ans.run_module(
                    self.host_list,
                    module_name='shell',
                    module_args='mkdir -p {} && /bin/cp -rf {}/* {}'.format(
                        backup_dir, backup_dest, backup_dir),
                    deploy=True,
                    d_type=self.d_type,
                    task="backup",
                    tid=tid.id)
            except Exception as e:
                self.send_save(fail_msg.format("目标服务器备份代码异常: {}").format(e))
                return

            # 将代码同步至目标服务器
            try:
                # /data/version/urlmonitor/123131232121238
                des_dir = self.gen_dir(tool, ticket_no)
                # 通过判断路径中是否存在target目录确定是否是JAVA项目
                # target_path /data/urlmonitor/UAT/target
                target_path = os.path.join(tool.proj_path, 'target')
                java_proj = os.path.exists(target_path)
                if java_proj:
                    self.send_save(ok_msg.format("是JAVA项目"))
                else:
                    self.send_save(ok_msg.format("非JAVA项目"))

                # 代码同步源目录
                src_dir = '{}/{}/'.format(
                    target_path, tool.proj_name) if os.path.exists(
                        target_path) else tool.proj_path + '/'
                self.sync_code(
                    ans,
                    self.host_list,
                    src_dir,
                    des_dir,
                    excludes=self.config.ticket_config.proj_role.exclude,
                    d_type=self.d_type,
                    task="sync_code",
                    tid=tid.id)

                # 如果运行服务的用户不是root,就将代码目录的属主改为指定的user
                if self.config.ticket_config.proj_role.run_user != 'root':
                    ans.run_module(
                        self.host_list,
                        module_name='file',
                        module_args='path={} owner={} recurse=yes'.format(
                            des_dir,
                            self.config.ticket_config.proj_role.run_user),
                        deploy=True,
                        send_msg=False,
                        d_type=self.d_type,
                        task="owner",
                        tid=tid.id)
            except Exception as e:
                self.send_save(fail_msg.format("代码同步至目标服务器异常 {}").format(e))
                return

            # 执行部署前任务
            if self.config.ticket_config.proj_role.prev_release:
                try:
                    self.run_cmds(
                        ans,
                        self.host_list,
                        self.config.ticket_config.proj_role.prev_release,
                        d_type=self.d_type,
                        task="prev_release",
                        tid=tid.id)
                except Exception as e:
                    self.send_save(
                        fail_msg.format("目标服务器部署前任务异常 {}").format(e))

            # 配置软连接,指向指定的版本目录
            try:
                src = self.gen_dir(tool, ticket_no)
                dest = os.path.join(
                    self.config.ticket_config.proj_role.deploy_webroot,
                    tool.proj_name)
                ans.run_module(self.host_list,
                               module_name='shell',
                               module_args='rm -rf {} && ln -sf {} {}'.format(
                                   dest, src + '/', dest),
                               deploy=True,
                               d_type=self.d_type,
                               task="release",
                               tid=tid.id)
            except Exception as e:
                self.send_save(fail_msg.format("目标服务器部署异常 {}").format(e))

            # 执行部署后任务
            if self.config.ticket_config.proj_role.post_release:
                try:
                    self.run_cmds(
                        ans,
                        self.host_list,
                        self.config.ticket_config.proj_role.post_release,
                        d_type=self.d_type,
                        task='post_release',
                        tid=tid.id)
                except Exception as e:
                    self.send_save(
                        fail_msg.format("目标服务器部署后任务异常 {}").format(e))

        elif self.d_type == 'Rollback':

            self.send_save(ok_msg.format("开始回滚!"))
            # 回滚代码
            try:
                backup_dir = self.gen_dir(tool, ticket_no, backup="backup")
                backup_dest = os.path.join(
                    self.config.ticket_config.proj_role.deploy_webroot,
                    tool.proj_name)
                print(backup_dir, backup_dest)
                ans.run_module(
                    self.host_list,
                    module_name='raw',
                    module_args=
                    'cd {bak_dir} && back_dir\=`ls -lt |egrep \^d|egrep -v rollback\$|cut -d " " -f 9|egrep \^[2][0-9]|head -n 1` &&  mv $back_dir $back_dir.rollback  && rm -rf {bak_dest} && ln -sf {bak_dir}/$back_dir.rollback {bak_dest}'
                    .format(
                        bak_dir=backup_dir,
                        bak_dest=backup_dest,
                    ),
                    deploy=True,
                    d_type=self.d_type,
                    task="rollback",
                    tid=tid.id)
            except Exception as e:
                self.send_save(fail_msg.format("目标服务器回滚代码异常: {}").format(e))
                return