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