def repo_init(self, id): if id: #获取当前id项的业务ip与端口 Dev_info = DeviceInfo.objects.filter(id=int(id)).first() bus_port = Dev_info.businesses.all()[0].businesses_port host_ip = Dev_info.hostname # 扫描业务端口 localhost = Shell('127.0.0.1') #command = 'cd %s && git rev-parse --is-inside-work-tree' % (repo[0]['alias']) command = 'nmap -sT -Pn ' + str(host_ip) + ' -p ' + str( bus_port) + '|grep tcp|awk -F " " \'{print $2}\'' #command = 'ip a|grep eth0|grep inet' result = localhost.local(command) #result = localhost.run(command) #info_logger.error("执行命令结果result...{}".format(result)) if result.exited != 0: info_logger.error("查询业务端口状态信息失败...") elif result.stdout.strip() == 'open': info_logger.info("process is running...{}".format( result.stdout)) elif result.stdout.strip() != 'open': info_logger.info("process is NOT running...{}".format( result.stdout)) localhost.close() return result
def repo_init(self, id): if id: repo = Project.objects.filter(id=int(id)).values('alias', 'repo_url') path = self._path.rstrip('/') + '/' + str(id) + '_' + str(repo[0]['alias']) if not os.path.exists(path): os.makedirs(path) if not os.path.exists(path + '/logs'): os.makedirs(path + '/logs') localhost = Shell('127.0.0.1') command = 'cd %s && git rev-parse --is-inside-work-tree' % (repo[0]['alias']) with localhost.cd(path): result = localhost.local(command, exception=False) if result.exited != 0: command = 'rm -rf %s' % (path + '/' + str(repo[0]['alias'])) localhost.local(command) with localhost.cd(path): command = 'git clone %s %s' % (repo[0]['repo_url'], repo[0]['alias']) result = localhost.local(command) massage = '正在克隆%s到%s ...' % (repo[0]['repo_url'], path) info_logger.info(massage) localhost.close() return result
class DeployExcu(object): _path = settings.WORKSPACE sequence = 0 release_version = None prev_release_version = None result = None file = None start_time = None def __init__(self, webuser, record_id, id=None): self.localhost = Shell('127.0.0.1') if id: project = Project.objects.filter(id=int(id)).values() self.project_id = project[0]['id'] self.alias = str(project[0]['alias']) self.environment = str(project[0]['environment']) self.repo_url = str(project[0]['repo_url']) self.local_code_path = self._path + str(id) + '_' + str(project[0]['alias']) + '/' + str( project[0]['alias']) self.local_project_path = self._path + str(id) + '_' + str(project[0]['alias']) self.local_log_path = self._path + str(id) + '_' + str(project[0]['alias']) + '/logs' self.is_include = project[0]['is_include'] self.excludes = project[0]['excludes'] self.task_envs = project[0]['task_envs'] self.prev_deploy = project[0]['prev_deploy'] self.post_deploy = project[0]['post_deploy'] self.prev_release = project[0]['prev_release'] self.post_release = project[0]['post_release'] self.target_root = project[0]['target_root'] self.target_releases = project[0]['target_releases'] self.version_num = project[0]['version_num'] self.custom_global_env = { 'WEB_ROOT': str(self.target_root), 'CODE_ROOT': str(self.local_code_path), 'ALIAS': str(self.alias), 'START_TIME': str(self.start_time) } if project[0]['task_envs']: task_envs = [i.strip() for i in project[0]['task_envs'].split('\n') if i.strip() and not i.strip().startswith('#')] for var in task_envs: var_list = var.split('=', 1) if len(var_list) != 2: continue self.custom_global_env[var_list[0]] = var_list[1] self.localhost.init_env(env=self.custom_global_env) self.webuser = webuser self.record_id = record_id def do_prev_deploy(self, log): ''' 代码检出前要做的基础工作 ''' self.sequence = 1 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出前的工作[%s]------\n' % (self.sequence)) commands = self.prev_deploy if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with self.localhost.cd(self.local_code_path): self.result = self.localhost.local(command, write=log) def do_checkout(self, version, log): ''' 检出代码 ''' if self.result.exited == 0: self.sequence = 2 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出[%s]------\n' % (self.sequence)) # 更新到指定 commit with self.localhost.cd(self.local_code_path): self.result = self.localhost.local('git fetch --all', write=log) if self.environment == 'tag': command = 'git rev-parse %s' % (version) else: command = 'git rev-parse refs/remotes/origin/%s' % (version) commit_id = self.localhost.local(command, write=log).stdout.strip() command = 'git checkout -f %s' % (commit_id) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) command = 'git show --stat' if self.result.exited == 0: self.result = self.localhost.local(command, write=log) def do_post_deploy(self, log): ''' 检出代码后的工作:如编译 ''' if self.result.exited == 0: self.sequence = 3 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出后的工作[%s]------\n' % (self.sequence)) commands = self.post_deploy if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with self.localhost.cd(self.local_code_path): if self.result.exited == 0: self.result = self.localhost.local(command, write=log) # 打包编译后的文件:包含或排除 self.release_version = self.record_id with self.localhost.cd(self.local_code_path): if self.is_include: files = includes_format(self.local_code_path, self.excludes) for file in files: dirname = file[0] filename = '.' if file[1] == '*' else file[1] tar_name = self.local_project_path.rstrip('/') + '/' + self.release_version + '.tar' tar_params = 'tar rf' if os.path.exists(tar_name) else 'tar cf' if dirname: command = '%s %s -C %s %s' % (tar_params, tar_name, dirname, filename) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) else: command = '%s %s %s' % (tar_params, tar_name, filename) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) else: files = excludes_format(self.local_code_path, self.excludes) command = 'tar cf ../%s %s' % (self.release_version + '.tar', files) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) def do_prev_release(self, log, connect): ''' 部署代码到目标机器前执行 ''' if self.result.exited == 0: self.sequence = 4 with open(log, 'a') as f: f.write('[INFO]------正在执行部署前的工作[%s]------\n' % (self.sequence)) target_release_version = "%s/%s" % (self.target_releases, self.release_version) # 创建远程target_releases目录 command = '[ -d %s ] || mkdir -p %s' % (target_release_version, target_release_version) if self.result.exited == 0: self.result = connect.run(command, write=log) # 上传压缩包 self.file = '%s/%s' % (self.local_project_path.rstrip('/'), self.release_version + '.tar') if self.result.exited == 0: with open(log, 'a') as f: f.write('[INFO]------正在上传压缩包至远程服务器------\n') self.result = connect.put(self.file, remote=target_release_version, write=log) # 判断是否超过可存档的数量 with connect.cd(self.target_releases): command = 'ls -l |grep "^d"|wc -l' if self.result.remote: self.result = connect.run(command, write=log) releases_num = int(self.result.stdout.strip()) if releases_num >= self.version_num: command = "ls -t |sort -t '_' -k 2 |head -1" if self.result.exited == 0: self.result = connect.run(command, write=log) last_record_id = self.result.stdout.strip() command = 'rm -rf %s/%s' % (self.target_releases, last_record_id) if self.result.exited == 0: self.result = connect.run(command, write=log) DeployRecord.objects.filter(record_id=last_record_id).update(is_rollback=False) # 解压并删除压缩源 with connect.cd(target_release_version): command = 'tar xf %s && rm -f %s' % \ (self.release_version + '.tar',self.release_version + '.tar') if self.result.exited == 0: self.result = connect.run(command, write=log) # 执行自定义命令 commands = self.prev_release if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with connect.cd(target_release_version): if self.result.exited == 0: self.result = connect.run(command, write=log) def do_release(self, log, connect): ''' 执行部署到目标机器:生成软链等 ''' if self.result.exited == 0: self.sequence = 5 with open(log, 'a') as f: f.write('[INFO]------正在执行部署工作[%s]------\n' % (self.sequence)) # 创建远程target_root目录 command = '[ -d %s ] || mkdir -p %s' % (self.target_root, self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 检查上次的版本 with connect.cd(self.target_root): version_file = '%s/%s' % (self.target_root, self.alias + '_version.txt') command = 'touch %s && cat %s' % (version_file, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) self.prev_release_version = self.result.stdout # 如果存在旧版本,则删除软链 if self.prev_release_version: command = 'find %s -type l -delete' % (self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 创建当前版本软链到webroot command = 'ln -sfn %s/%s/* %s && echo %s > %s' % (self.target_releases, self.release_version, self.target_root, self.release_version, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) def do_post_release(self, log, connect): ''' 部署代码到目标机器后执行 ''' if self.result.exited == 0: self.sequence = 6 with open(log, 'a') as f: f.write('[INFO]------正在执行部署后的工作[%s]------\n' % (self.sequence)) commands = self.post_release if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with connect.cd(self.target_root): if self.result.exited == 0: self.result = connect.run(command, write=log) connect.close() def end(self, server_ids, record_id): if self.localhost: # 删除打包的源文件 self.localhost.local('rm -f %s' % (self.file)) # 关闭连接 self.localhost.close() # 关闭死循环读取本地日志 gl.set_value('deploy_' + str(self.webuser), True) sid = ','.join(server_ids) defaults = { 'record_id': record_id, 'alias': self.alias, 'server_ids': sid, 'target_root': self.target_root, 'target_releases': self.target_releases, 'prev_record': self.prev_release_version.strip(), 'is_rollback': True, 'status': 'Succeed' } name = '部署_' + record_id if self.result.exited == 0: DeployRecord.objects.filter(name=name).update(**defaults) Project.objects.filter(id=self.project_id).update(last_task_status='Succeed') else: defaults['status'] = 'Failed' defaults['is_rollback'] = False DeployRecord.objects.filter(name=name).update(**defaults) Project.objects.filter(id=self.project_id).update(last_task_status='Failed') @async def start(self, log, version, serverid, record_id, webuser, start_time): self.start_time = start_time try: self.do_prev_deploy(log) self.do_checkout(version, log) self.do_post_deploy(log) for sid in serverid: if sid: auth_info, auth_key = auth_init(sid) if auth_info and auth_key: connect = Shell(auth_info, connect_timeout=5, connect_kwargs=auth_key) self.do_prev_release(log, connect) self.do_release(log, connect) self.do_post_release(log, connect) else: Tailf.send_message(webuser, '[ERROR]服务器ID%s已被删除,部署继续执行!' % sid) else: Tailf.send_message(webuser, '没有选择远程服务器!!!') self.end(serverid, record_id) except Exception as e: Tailf.send_message(webuser, str(e))
def get_branch(self, path): localhost = Shell('127.0.0.1') with localhost.cd(path): localhost.local('git fetch --all') result = localhost.local('git branch -r') return result
def get_tag(self, path): localhost = Shell('127.0.0.1') with localhost.cd(path): localhost.local('git fetch --all') result = localhost.local('git tag -l') return result
class DeployExcu(Task): _path = settings.WORKSPACE sequence = 0 release_version = None prev_release_version = None result = None file = None def deploy_init(self, webuser, record_id, id=None): self.localhost = Shell('127.0.0.1') if id: project = Project.objects.filter(id=int(id)).values() self.project_id = project[0]['id'] self.alias = str(project[0]['alias']) self.repo_url = str(project[0]['repo_url']) self.local_code_path = self._path + str(id) + '_' + str( project[0]['alias']) + '/' + str(project[0]['alias']) self.local_project_path = self._path + str(id) + '_' + str( project[0]['alias']) self.local_log_path = self._path + str(id) + '_' + str( project[0]['alias']) + '/logs' self.is_include = project[0]['is_include'] self.excludes = project[0]['excludes'] self.task_envs = project[0]['task_envs'] self.prev_deploy = project[0]['prev_deploy'] self.post_deploy = project[0]['post_deploy'] self.prev_release = project[0]['prev_release'] self.post_release = project[0]['post_release'] self.target_root = project[0]['target_root'] self.target_releases = project[0]['target_releases'] self.version_num = project[0]['version_num'] self.custom_global_env = { 'WEB_ROOT': str(self.target_root), 'CODE_ROOT': str(self.local_code_path), 'ALIAS': str(self.alias) } if project[0]['task_envs']: task_envs = [ i.strip() for i in project[0]['task_envs'].split('\n') if i.strip() and not i.strip().startswith('#') ] for var in task_envs: var_list = var.split('=', 1) if len(var_list) != 2: continue self.custom_global_env[var_list[0]] = var_list[1] self.localhost.init_env(env=self.custom_global_env) self.webuser = webuser self.record_id = record_id def do_prev_deploy(self, log): ''' 代码检出前要做的基础工作 ''' self.sequence = 1 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出前的工作------%s\n' % (self.sequence)) commands = self.prev_deploy if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with self.localhost.cd(self.local_code_path): self.result = self.localhost.local(command, write=log) def do_checkout(self, version, log): ''' 检出代码 ''' if self.result.exited == 0: self.sequence = 2 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出------%s\n' % (self.sequence)) # 更新到指定 commit with self.localhost.cd(self.local_code_path): self.result = self.localhost.local('git fetch --all', write=log) command = 'git rev-parse %s' % (version) commit_id = self.localhost.local(command, write=log).stdout.strip() command = 'git checkout -f %s' % (commit_id) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) def do_post_deploy(self, log): ''' 检出代码后的工作:如编译 ''' if self.result.exited == 0: self.sequence = 3 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出后的工作------%s\n' % (self.sequence)) commands = self.post_deploy if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with self.localhost.cd(self.local_code_path): if self.result.exited == 0: self.result = self.localhost.local(command, write=log) # 打包编译后的文件:包含或排除 self.release_version = self.record_id with self.localhost.cd(self.local_code_path): if self.is_include: files = includes_format(self.local_code_path, self.excludes) command = 'tar zcf %s/%s %s' % ( self.local_project_path.rstrip('/'), self.release_version + '.tar.gz', files) else: files = excludes_format(self.local_code_path, self.excludes) command = 'tar zcf ../%s %s' % (self.release_version + '.tar.gz', files) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) def do_prev_release(self, log, connect): ''' 部署代码到目标机器前执行 ''' if self.result.exited == 0: self.sequence = 4 with open(log, 'a') as f: f.write('[INFO]------正在执行部署前的工作------%s\n' % (self.sequence)) # 创建远程target_releases目录 command = '[ -d %s ] || mkdir -p %s' % (self.target_releases, self.target_releases) if self.result.exited == 0: self.result = connect.run(command, write=log) # 上传压缩包 self.file = '%s/%s' % (self.local_project_path.rstrip('/'), self.release_version + '.tar.gz') if self.result.exited == 0: connect.put(self.file, remote=self.target_releases, write=log) # 判断是否超过可存档的数量 with connect.cd(self.target_releases): command = 'ls -l |grep "^d"|wc -l' if self.result.exited == 0: self.result = connect.run(command, write=log) releases_num = int(self.result.stdout.strip()) if releases_num >= self.version_num: last_data = DeployRecord.objects.filter( project_id=self.project_id, name__contains='部署', status='Succeed', is_rollback=True).order_by( '-id')[:self.version_num].values() last_record_id = last_data[self.version_num - 1]['record_id'] command = 'rm -rf %s/%s' % (self.target_releases, last_record_id) if self.result.exited == 0: self.result = connect.run(command, write=log) DeployRecord.objects.filter( id=last_data[self.version_num - 1]['id']).update(is_rollback=False) # 解压并删除压缩源 with connect.cd(self.target_releases): command = 'mkdir %s && tar zxf %s -C %s && rm -f %s' % \ (self.release_version, self.release_version + '.tar.gz', self.release_version, self.release_version + '.tar.gz') if self.result.exited == 0: self.result = connect.run(command, write=log) # 执行自定义命令 commands = self.prev_release if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue target_release_version = "%s/%s" % (self.target_releases, self.release_version) with connect.cd(target_release_version): if self.result.exited == 0: self.result = connect.run(command, write=log) def do_release(self, log, connect): ''' 执行部署到目标机器:生成软链等 ''' if self.result.exited == 0: self.sequence = 5 with open(log, 'a') as f: f.write('[INFO]------正在执行部署工作------%s\n' % (self.sequence)) # 创建远程target_root目录 command = '[ -d %s ] || mkdir -p %s' % (self.target_root, self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 检查上次的版本 with connect.cd(self.target_releases): version_file = '%s/%s' % (self.target_root, self.alias + '_version.txt') command = 'touch %s && cat %s' % (version_file, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) self.prev_release_version = self.result.stdout # 如果存在旧版本,则删除软链 if self.prev_release_version: command = 'find %s -type l -delete' % (self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 创建当前版本软链到webroot command = 'ln -sfn %s/%s/* %s && echo %s > %s' % ( self.target_releases, self.release_version, self.target_root, self.release_version, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) def do_post_release(self, log, connect): ''' 部署代码到目标机器后执行 ''' if self.result.exited == 0: self.sequence = 6 with open(log, 'a') as f: f.write('[INFO]------正在执行部署后的工作------%s\n' % (self.sequence)) commands = self.post_release if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with connect.cd(self.target_root): pty = False if command.find('nohup') >= 0 else True if self.result.exited == 0: self.result = connect.run(command, pty=pty, write=log) connect.close() def end(self, server_ids, record_id): if self.localhost: # 删除打包的源文件 self.localhost.local('rm -f %s' % (self.file)) # 关闭连接 self.localhost.close() # 关闭死循环读取本地日志 gl.set_value('deploy_' + str(self.webuser), True) sid = ','.join(server_ids) defaults = { 'record_id': record_id, 'alias': self.alias, 'server_ids': sid, 'target_root': self.target_root, 'target_releases': self.target_releases, 'prev_record': self.prev_release_version.strip(), 'is_rollback': True, 'status': 'Succeed' } name = '部署_' + record_id if self.result.exited == 0: DeployRecord.objects.filter(name=name).update(**defaults) else: defaults['status'] = 'Failed' defaults['is_rollback'] = False DeployRecord.objects.filter(name=name).update(**defaults) def start(self, log, version, serverid, record_id, webuser): try: self.do_prev_deploy(log) self.do_checkout(version, log) self.do_post_deploy(log) for sid in serverid: try: device_info = DeviceInfo.objects.filter( id=int(sid)).values() host = device_info[0]['hostname'] auth_type = device_info[0]['auth_type'] connect_info = ConnectionInfo.objects.filter( hostname=host, auth_type=auth_type).values() user = connect_info[0]['username'] passwd = connect_info[0]['password'] port = connect_info[0]['port'] auth_info = '{user}@{host}:{port}'.format(user=user, host=host, port=port) auth_key = {auth_type: passwd} connect = Shell(auth_info, connect_timeout=5, connect_kwargs=auth_key) self.do_prev_release(log, connect) self.do_release(log, connect) self.do_post_release(log, connect) except Exception as e: send = Tailf() send.send_message(webuser, str(e)) self.end(serverid, record_id) except Exception as e: send = Tailf() send.send_message(webuser, str(e)) def run(self, id, log, version, serverid, record_id, webuser): self.deploy_init(webuser, record_id, id) self.start(log, version, serverid, record_id, webuser)
class DeployExcu(Task): name = __name__ _path = settings.WORKSPACE sequence = 0 release_version = None prev_release_version = None result = None file = None start_time = None def init(self, webuser, record_id, id=None): self.localhost = Shell('127.0.0.1') if id: project = Project.objects.filter(id=int(id)).values() self.project_id = project[0]['id'] self.alias = str(project[0]['alias']) self.environment = str(project[0]['environment']) self.repo_url = str(project[0]['repo_url']) self.local_code_path = self._path + str(id) + '_' + str( project[0]['alias']) + '/' + str(project[0]['alias']) self.local_project_path = self._path + str(id) + '_' + str( project[0]['alias']) self.local_log_path = self._path + str(id) + '_' + str( project[0]['alias']) + '/logs' self.is_include = project[0]['is_include'] self.excludes = project[0]['excludes'] self.is_link = project[0]['is_link'] self.task_envs = project[0]['task_envs'] self.prev_deploy = project[0]['prev_deploy'] self.post_deploy = project[0]['post_deploy'] self.prev_release = project[0]['prev_release'] self.post_release = project[0]['post_release'] self.target_root = project[0]['target_root'] self.target_releases = project[0]['target_releases'] self.version_num = project[0]['version_num'] self.custom_global_env = { 'WEB_ROOT': str(self.target_root), 'CODE_ROOT': str(self.local_code_path), 'ALIAS': str(self.alias), 'START_TIME': str(self.start_time) } if project[0]['task_envs']: task_envs = [ i.strip() for i in project[0]['task_envs'].split('\n') if i.strip() and not i.strip().startswith('#') ] for var in task_envs: var_list = var.split('=', 1) if len(var_list) != 2: continue self.custom_global_env[var_list[0]] = var_list[1] self.localhost.init_env(env=self.custom_global_env) self.webuser = webuser self.record_id = record_id def do_prev_deploy(self, log): ''' 代码检出前要做的基础工作 ''' self.sequence = 1 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出前的工作[%s]------\n' % (self.sequence)) commands = self.prev_deploy if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with self.localhost.cd(self.local_code_path): self.result = self.localhost.local(command, write=log) def do_checkout(self, version, log): ''' 检出代码 ''' self.sequence = 2 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出[%s]------\n' % (self.sequence)) # 更新到指定 commit with self.localhost.cd(self.local_code_path): self.result = self.localhost.local( 'git checkout master && git pull', write=log) command = 'git rev-parse %s' % (version) commit_id = self.localhost.local(command, write=log).stdout.strip() command = 'git checkout -f %s' % (commit_id) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) command = 'git show --stat' if self.result.exited == 0: self.result = self.localhost.local(command, write=log) def do_post_deploy(self, log): ''' 检出代码后的工作:如编译 ''' if self.result.exited == 0: self.sequence = 3 with open(log, 'a') as f: f.write('[INFO]------正在执行代码检出后的工作[%s]------\n' % (self.sequence)) commands = self.post_deploy if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with self.localhost.cd(self.local_code_path): if self.result.exited == 0: self.result = self.localhost.local(command, write=log) # 打包编译后的文件:包含或排除 if self.result.exited == 0: self.release_version = self.record_id with self.localhost.cd(self.local_code_path): if self.is_include: files = includes_format(self.local_code_path, self.excludes) for file in files: dirname = file[0] filename = '.' if file[1] == '*' else file[1] tar_name = self.local_project_path.rstrip( '/') + '/' + self.release_version + '.tar' tar_params = 'tar rf' if os.path.exists( tar_name) else 'tar cf' if dirname: command = '%s %s -C %s %s' % ( tar_params, tar_name, dirname, filename) if self.result.exited == 0: self.result = self.localhost.local( command, write=log) else: command = '%s %s %s' % (tar_params, tar_name, filename) if self.result.exited == 0: self.result = self.localhost.local( command, write=log) else: files = excludes_format(self.local_code_path, self.excludes) command = 'tar cf ../%s %s' % (self.release_version + '.tar', files) if self.result.exited == 0: self.result = self.localhost.local(command, write=log) def do_prev_release(self, log, connect): ''' 部署代码到目标机器前执行 ''' if self.result.exited == 0: self.sequence = 4 with open(log, 'a') as f: f.write('[INFO]------正在执行部署前的工作[%s]------\n' % (self.sequence)) target_release_version = "%s/%s" % (self.target_releases, self.release_version) # 创建远程target_releases目录 command = '[ -d %s ] || mkdir -p %s' % (target_release_version, target_release_version) if self.result.exited == 0: self.result = connect.run(command, write=log) # 上传压缩包 self.file = '%s/%s' % (self.local_project_path.rstrip('/'), self.release_version + '.tar') if self.result.exited == 0: with open(log, 'a') as f: f.write('[INFO]------正在上传压缩包至远程服务器------\n') self.result = connect.put(self.file, remote=target_release_version, write=log) # 删除打包的源文件 self.localhost.local('rm -f %s' % (self.file)) # 判断是否超过可存档的数量 with connect.cd(self.target_releases): command = 'ls -l |grep "^d"|wc -l' if self.result.remote: self.result = connect.run(command, write=log) releases_num = int(self.result.stdout.strip()) if releases_num >= self.version_num: command = "ls -t |sort -t '_' -k 2 |head -1" if self.result.exited == 0: self.result = connect.run(command, write=log) last_record_id = self.result.stdout.strip() command = 'rm -rf %s/%s' % (self.target_releases, last_record_id) if self.result.exited == 0: self.result = connect.run(command, write=log) DeployRecord.objects.filter( record_id=last_record_id).update(is_rollback=False) # 解压并删除压缩源 with connect.cd(target_release_version): command = 'tar xf %s && rm -f %s' % \ (self.release_version + '.tar', self.release_version + '.tar') if self.result.exited == 0: self.result = connect.run(command, write=log) # 执行自定义命令 commands = self.prev_release if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with connect.cd(target_release_version): if self.result.exited == 0: self.result = connect.run(command, write=log) def do_release(self, log, connect): ''' 执行部署到目标机器:生成软链等 ''' if self.result.exited == 0: self.sequence = 5 with open(log, 'a') as f: f.write('[INFO]------正在执行部署工作[%s]------\n' % (self.sequence)) # 创建远程target_root目录 command = '[ -d %s ] || mkdir -p %s' % (self.target_root, self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 检查上次的版本 with connect.cd(self.target_root): version_file = '%s/%s' % (self.target_root, self.alias + '_version.txt') command = 'touch %s && cat %s' % (version_file, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) self.prev_release_version = self.result.stdout # 如果存在旧版本,则删除软链或删除文件 if self.prev_release_version: if self.is_link: command = 'find %s -type l -delete' % (self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 创建当前版本软链到webroot command = 'ln -sfn %s/%s/* %s && echo %s > %s' % ( self.target_releases, self.release_version, self.target_root, self.release_version, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) else: command = 'rm -rf %s/*' % (self.target_root) if self.result.exited == 0: self.result = connect.run(command, write=log) # 复制文件到webroot command = 'cp -r %s/%s/* %s && echo %s > %s' % ( self.target_releases, self.release_version, self.target_root, self.release_version, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) else: if self.is_link: command = 'ln -sfn %s/%s/* %s && echo %s > %s' % ( self.target_releases, self.release_version, self.target_root, self.release_version, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) else: command = 'cp -r %s/%s/* %s && echo %s > %s' % ( self.target_releases, self.release_version, self.target_root, self.release_version, version_file) if self.result.exited == 0: self.result = connect.run(command, write=log) def do_post_release(self, log, connect): ''' 部署代码到目标机器后执行 ''' if self.result.exited == 0: self.sequence = 6 with open(log, 'a') as f: f.write('[INFO]------正在执行部署后的工作[%s]------\n' % (self.sequence)) target_release_version = "%s/%s" % (self.target_releases, self.release_version) # 执行自定义命令 commands = self.post_release if commands: for command in commands.split('\n'): if command.strip().startswith('#') or not command.strip(): continue with connect.cd(target_release_version): if self.result.exited == 0: self.result = connect.run(command, write=log) connect.close() def end(self, server_ids, record_id): sid = ','.join(server_ids) defaults = { 'record_id': record_id, 'alias': self.alias, 'server_ids': sid, 'target_root': self.target_root, 'target_releases': self.target_releases, 'prev_record': self.prev_release_version.strip(), 'is_rollback': True, 'status': 'Succeed' } name = '部署_' + record_id if self.result.exited == 0: DeployRecord.objects.filter(name=name).update(**defaults) Project.objects.filter(id=self.project_id).update( last_task_status='Succeed') else: defaults['status'] = 'Failed' defaults['is_rollback'] = False DeployRecord.objects.filter(name=name).update(**defaults) Project.objects.filter(id=self.project_id).update( last_task_status='Failed') def run(self, id, log, version, serverid, record_id, webuser, start_time): info_logger.info('[部署任务开始] 开始时间:%s 记录ID:%s 部署版本:%s 用户:%s 项目ID:%s' % (start_time, record_id, version, webuser, id)) redis = RedisObj() redis.set('deploy_' + str(webuser) + '_' + str(id), '0') self.init(webuser, record_id, id) self.start_time = start_time with open(log, 'a') as f: f.write('[INFO]版本: %s 执行用户: %s 开始时间: %s\n[INFO]本次部署日志路径: %s\n' % (version, webuser, start_time, log)) try: self.do_prev_deploy(log) self.do_checkout(version, log) self.do_post_deploy(log) for sid in serverid: try: connect = connect_init(sid) connect.init_env(env=self.custom_global_env) self.do_prev_release(log, connect) self.do_release(log, connect) self.do_post_release(log, connect) except Exception as e: time.sleep(5) Tailf.send_message(webuser, '[ERROR] 服务器为空或ID %s 可能已被删除!' % sid) Tailf.send_message(webuser, '[ERROR] 错误信息:' % e) error_logger.error( '[部署任务错误] 开始时间:%s 记录ID:%s 部署版本:%s 用户:%s 项目ID:%s 信息:%s' % (start_time, record_id, version, webuser, id, e)) self.end(serverid, record_id) info_logger.info('[部署任务已结束] 记录ID:%s 部署版本:%s 用户:%s 项目ID:%s' % (record_id, version, webuser, id)) except Exception as e: Tailf.send_message(webuser, '[ERROR] 错误信息: %s' % e) error_logger.error( '[部署任务错误] 开始时间:%s 记录ID:%s 部署版本:%s 用户:%s 项目ID:%s 信息:%s' % (start_time, record_id, version, webuser, id, e)) finally: if self.localhost: self.localhost.close() # 关闭local_tailf死循环 redis.set('deploy_' + str(webuser) + '_' + str(id), '1')