示例#1
0
 def exec_hook_after_release(self, host):
     try:
         after_hook_path = os.path.join(
             settings.BASE_DIR,
             'storage/hooks/after_hook_' + str(self.projectEnvConfig.id))
         if os.path.exists(after_hook_path):
             self.myLoggingService.info('检测到发布后Hook, 准备执行:')
             with open(after_hook_path) as f:
                 for line in f:
                     self.myLoggingService.info(line.strip())
             # 推送脚本
             filename = 'opendeploy_hook_after_' + str(
                 self.id) + '_' + get_random_string(30)
             remote_path = '/tmp/' + filename
             command = RSYNC_PREFIX + after_hook_path + ' ' + host + ':' + remote_path
             self.myLoggingService.info(command)
             commandService = CommandService(command)
             if commandService.returncode > 0:
                 self.myLoggingService.error('推送脚本异常')
                 return False
             # @TODO
             self.myLoggingService.info('开始执行...')
             release_path = self.get_release_path()
             if release_path:
                 command = SSH_PREFIX + host + ' "chmod 777 ' + remote_path + ' && export OPENDEPLOY_ID=' + str(self.id) + ' && source /etc/profile && cd ' \
                      + release_path + ' && ' + remote_path + ' && ' + 'rm -f ' + remote_path + ' 2>&1"'
             else:
                 command = SSH_PREFIX + host + ' "chmod 777 ' + remote_path + ' && export OPENDEPLOY_ID=' + str(self.id) + ' && source /etc/profile && ' \
                      + remote_path + ' && ' + 'rm -f ' + remote_path + ' 2>&1"'
             self.myLoggingService.info(command)
             commandService = CommandService(command)
             self.myLoggingService.info('exit_code:' +
                                        str(commandService.returncode))
             if commandService.returncode > 0:
                 self.myLoggingService.error('发布后hook执行异常')
                 if len(commandService.stdout) > 0:
                     self.myLoggingService.info('脚本输出:')
                     for line in commandService.stdout_as_list:
                         self.myLoggingService.error(line)
                 if len(commandService.stderr) > 0:
                     self.myLoggingService.error('脚本错误:')
                     for line in commandService.stderr_as_list:
                         self.myLoggingService.error(line)
                 return False
             else:
                 self.myLoggingService.info('发布后hook执行正常')
                 if len(commandService.stdout_as_list) > 0:
                     self.myLoggingService.info('脚本输出:')
                     for line in commandService.stdout_as_list:
                         self.myLoggingService.info(line)
                 return True
     except:
         return False
示例#2
0
def credential_edit(request, id):
    credential = Credentials.objects.get(pk=id)
    auth_type = credential.type
    if request.method == 'POST':
        if auth_type == Credentials.TYPE_USER_PWD:
            f = AddCredentialForPasswordForm(request.POST)
        else:
            f = AddCredentialForPrivateForm(request.POST)
        if f.is_valid():
            cleaned_data = f.cleaned_data
            try:
                credential.type = auth_type
                credential.username = cleaned_data['username']
                credential.comment = cleaned_data['comment']
                if auth_type == Credentials.TYPE_USER_PWD:
                    credential.password = cleaned_data['password']
                else:
                    credential.private_key = cleaned_data['private_key']
                credential.save()
                if auth_type != Credentials.TYPE_USER_PWD:
                    key_path = os.path.join(
                        settings.BASE_DIR,
                        'storage/privary_key/' + str(credential.id))
                    if len(credential.private_key) > 0:
                        with open(key_path, 'w') as f:
                            f.write(credential.private_key.rstrip() + '\n')
                        command = 'dos2unix ' + key_path
                        CommandService(command)
                        os.chmod(key_path, stat.S_IRWXU)
                    else:
                        if os.path.exists(key_path):
                            os.unlink(key_path)
                messages.info(request, '修改成功')
            except:
                messages.error(request, '修改失败')
            finally:
                return redirect('/admin/deploy/credential')
    else:
        if auth_type == Credentials.TYPE_USER_PWD:
            f = AddCredentialForPasswordForm()
        else:
            f = AddCredentialForPrivateForm()
    return render(
        request, 'admin/deploy/edit_credential.html', {
            "form": f,
            "credential": credential,
            "type_choices": Credentials.TYPE_CHOICES,
            "auth_type": auth_type,
            "type_user_pwd": Credentials.TYPE_USER_PWD,
        })
示例#3
0
 def exec_hook_before_release(self, working_dir=None):
     try:
         before_hook_path = os.path.join(
             settings.BASE_DIR,
             'storage/hooks/before_hook_' + str(self.projectEnvConfig.id))
         if os.path.exists(before_hook_path):
             if working_dir is None:
                 working_dir = '/app'
             commandService = CommandService('cd ' + working_dir + ' && ' +
                                             before_hook_path)
             self.myLoggingService.info('检测到发布前Hook, 准备执行:')
             self.myLoggingService.info('command:' + before_hook_path)
             with open(before_hook_path) as f:
                 for line in f:
                     self.myLoggingService.info(line.strip())
             self.myLoggingService.info('exit_code:' +
                                        str(commandService.returncode))
             if commandService.returncode > 0:
                 self.myLoggingService.error('发布前hook执行异常')
                 if len(commandService.stdout) > 0:
                     self.myLoggingService.info('脚本输出:')
                     for line in commandService.stdout_as_list:
                         self.myLoggingService.error(line)
                 if len(commandService.stderr) > 0:
                     self.myLoggingService.error('脚本错误:')
                     for line in commandService.stderr_as_list:
                         self.myLoggingService.error(line)
                 return False
             else:
                 self.myLoggingService.info('发布前hook执行正常')
                 if len(commandService.stdout_as_list) > 0:
                     self.myLoggingService.info('脚本输出:')
                     for line in commandService.stdout_as_list:
                         self.myLoggingService.info(line)
                 return True
     except:
         return False
示例#4
0
def project_add(request):
    if request.method == 'POST':
        f = ProjectForm(request.POST)
        if f.is_valid():
            try:
                cleaned_data = f.cleaned_data
                project = Project()
                project.name = cleaned_data['name']
                project.vcs_type = cleaned_data['vcs_type']
                project.repository_url = cleaned_data['repository_url']
                project.credentials = cleaned_data['credentials']
                project.dest_path = cleaned_data['dest_path']
                project.comment = cleaned_data['comment']
                project.deploy_mode = cleaned_data['deploy_mode']
                project.dingding_robot_webhook = cleaned_data[
                    'dingding_robot_webhook']
                project.status = cleaned_data['status']
                project.exclude_file = cleaned_data['exclude_file']
                project.rsync_enable_delete = cleaned_data[
                    'rsync_enable_delete']
                project.enable_mail_notify = cleaned_data['enable_mail_notify']
                project.save()
                exclude_file_path = os.path.join(
                    settings.BASE_DIR,
                    'storage/exclude_file/' + str(project.id))
                if len(project.exclude_file) > 0:
                    with open(exclude_file_path, 'w') as f:
                        f.write(project.exclude_file)

                # 增加环境关联值
                envs = request.POST.getlist('env')
                if envs:
                    for env in envs:
                        projectEnvConfig = ProjectEnvConfig()
                        projectEnvConfig.project = project
                        try:
                            projectEnvConfig.env = Env.objects.get(pk=env)
                        except:
                            pass
                        projectEnvConfig.branch = request.POST.get('branch_' +
                                                                   env)
                        projectEnvConfig.before_hook = request.POST.get(
                            'before_hook_' + env)
                        projectEnvConfig.after_hook = request.POST.get(
                            'after_hook_' + env)
                        if request.POST.get('host_group_' + env):
                            try:
                                projectEnvConfig.host_group = HostGroup.objects.get(
                                    pk=request.POST.get('host_group_' + env))
                            except:
                                pass
                        projectEnvConfig.save()

                        before_hook_path = os.path.join(
                            settings.BASE_DIR, 'storage/hooks/before_hook_' +
                            str(projectEnvConfig.id))
                        if len(projectEnvConfig.before_hook) > 0:
                            with open(before_hook_path, 'w') as f:
                                f.write(projectEnvConfig.before_hook)

                        after_hook_path = os.path.join(
                            settings.BASE_DIR, 'storage/hooks/after_hook_' +
                            str(projectEnvConfig.id))
                        if len(projectEnvConfig.after_hook) > 0:
                            with open(after_hook_path, 'w') as f:
                                f.write(projectEnvConfig.after_hook)

                        if os.path.exists(before_hook_path):
                            os.chmod(before_hook_path, stat.S_IRWXU)
                            command = 'dos2unix ' + before_hook_path
                            CommandService(command)

                        if os.path.exists(after_hook_path):
                            os.chmod(after_hook_path, stat.S_IRWXU)
                            command = 'dos2unix ' + after_hook_path
                            CommandService(command)
                    messages.info(request, '添加成功')
            except:
                messages.error(request, '添加失败')
            finally:
                return redirect('admin:deploy.project')
        else:
            messages.error(request, '表单校验失败')
    else:
        f = ProjectForm()
    return render(
        request, 'admin/deploy/add_project.html', {
            "form": f,
            "status_choices": Project.STATUS_CHOICES,
            "type_choices": Project.TYPE_CHOICES,
            "credentials": Credentials.objects.all(),
            "deploy_mode_choices": Project.DEPLOY_MODE_CHOICES,
            "envlist": Env.objects.all(),
            "host_group": HostGroup.objects.all(),
        })
示例#5
0
def project_edit(request, id):
    project = Project.objects.get(pk=id)
    projectEnvConfig = ProjectEnvConfig.objects.filter(project=project)
    # 该项目环境id列表
    env_list_by_project = []
    for v in projectEnvConfig:
        env_list_by_project.append(v.env.id)

    if request.method == 'POST':
        f = ProjectForm(request.POST, instance=project)
        if f.is_valid():
            cleaned_data = f.cleaned_data
            try:
                f.save()
                exclude_file_path = os.path.join(
                    settings.BASE_DIR, 'storage/exclude_file/' + str(id))
                if len(cleaned_data['exclude_file']) > 0:
                    with open(exclude_file_path, 'w') as f:
                        f.write(cleaned_data['exclude_file'].encode())
                else:
                    if os.path.exists(exclude_file_path):
                        os.unlink(exclude_file_path)
                # 增加环境关联值
                envs = request.POST.getlist('projectEnvConfig')
                if envs:
                    for v in envs:
                        # 存在更新
                        try:
                            config = ProjectEnvConfig.objects.get(pk=v)
                            if request.POST.get('branch_' + v):
                                config.branch = request.POST.get('branch_' + v)
                            else:
                                config.branch = 'master'
                            config.before_hook = request.POST.get(
                                'before_hook_' + v, '')
                            config.after_hook = request.POST.get(
                                'after_hook_' + v, '')
                            if request.POST.get('host_group_' + v):
                                config.host_group = HostGroup.objects.get(
                                    pk=request.POST.get('host_group_' + v))
                            config.save()

                            before_hook_path = os.path.join(
                                settings.BASE_DIR,
                                'storage/hooks/before_hook_' + str(config.id))
                            if len(config.before_hook) > 0:
                                with open(before_hook_path, 'w') as f:
                                    f.write(config.before_hook)
                            else:
                                if os.path.exists(before_hook_path):
                                    os.unlink(before_hook_path)

                            after_hook_path = os.path.join(
                                settings.BASE_DIR,
                                'storage/hooks/after_hook_' + str(config.id))
                            if len(config.after_hook) > 0:
                                with open(after_hook_path, 'w') as f:
                                    f.write(config.after_hook)
                            else:
                                if os.path.exists(after_hook_path):
                                    os.unlink(after_hook_path)

                            if os.path.exists(before_hook_path):
                                os.chmod(before_hook_path, stat.S_IRWXU)
                                command = 'dos2unix ' + before_hook_path
                                CommandService(command)

                            if os.path.exists(after_hook_path):
                                os.chmod(after_hook_path, stat.S_IRWXU)
                                command = 'dos2unix ' + after_hook_path
                                CommandService(command)
                        # 不存在插入
                        except:
                            projectEnvConfig = ProjectEnvConfig()
                            projectEnvConfig.project = project
                            projectEnvConfig.env = Env.objects.get(pk=v)
                            if request.POST.get('branch_' + v):
                                projectEnvConfig.branch = request.POST.get(
                                    'branch_' + v)
                            else:
                                projectEnvConfig.branch = 'master'
                            if request.POST.get('host_group_' + v):
                                projectEnvConfig.host_group = HostGroup.objects.get(
                                    pk=request.POST.get('host_group_' + v))
                            projectEnvConfig.before_hook = request.POST.get(
                                'before_hook_' + v, '')
                            projectEnvConfig.after_hook = request.POST.get(
                                'after_hook_' + v, '')
                            projectEnvConfig.save()

                            before_hook_path = os.path.join(
                                settings.BASE_DIR,
                                'storage/hooks/before_hook_' +
                                str(projectEnvConfig.id))
                            with open(before_hook_path, 'w') as f:
                                f.write(projectEnvConfig.before_hook)

                            after_hook_path = os.path.join(
                                settings.BASE_DIR,
                                'storage/hooks/after_hook_' +
                                str(projectEnvConfig.id))
                            with open(after_hook_path, 'w') as f:
                                f.write(projectEnvConfig.after_hook)

                            if os.path.exists(before_hook_path):
                                os.chmod(before_hook_path, stat.S_IRWXU)
                                command = 'dos2unix ' + before_hook_path
                                CommandService(command)

                            if os.path.exists(after_hook_path):
                                os.chmod(after_hook_path, stat.S_IRWXU)
                                command = 'dos2unix ' + after_hook_path
                                CommandService(command)
                messages.info(request, '修改成功')
            except:
                messages.error(request, '修改失败')
            finally:
                return redirect('admin:deploy.project')
    else:
        f = ProjectForm()
    settingService = SettingService()
    general_info = settingService.get_general_info()
    return render(
        request, 'admin/deploy/edit_project.html', {
            "form": f,
            "project": project,
            "projectEnvConfig": projectEnvConfig,
            "status_choices": Project.STATUS_CHOICES,
            "type_choices": Project.TYPE_CHOICES,
            "deploy_mode_choices": Project.DEPLOY_MODE_CHOICES,
            "envlist": Env.objects.all(),
            "host_group": HostGroup.objects.all(),
            "credentials": Credentials.objects.all(),
            "env_list_by_project": env_list_by_project,
            "general_info": general_info,
        })
示例#6
0
 def rollback(self):
     errno = 0
     single_errno = 0
     for host in self.all_host:
         self.myLoggingService.info('开始回滚主机, host:' + host)
         if self.task.scope == Task.SCOPE_BY_FILE:
             self.myLoggingService.info('准备从发布系统回滚指定文件')
             for item in self.task.files_list.splitlines():
                 self.myLoggingService.info('回滚文件:' + item)
                 rollback_file_path = settings.ROLLBACK_PATH[0] + '/' + str(
                     self.task.id) + '/' + item
                 command = self.rsync_prefix + RSYNC_EXCLUDE_PARMS + rollback_file_path + ' ' + \
                         host + ':' + self.taskService.get_release_path() + '/' + item
                 commandService = CommandService(command)
                 if commandService.returncode > 0:
                     self.myLoggingService.error('文件回滚失败。 路径:' + item)
                     self.myLoggingService.error(command)
                     if len(commandService.stdout_as_list) > 0:
                         for line in commandService.stdout_as_list:
                             self.myLoggingService.error(line)
                     if len(commandService.stderr) > 0:
                         for line in commandService.stderr_as_list:
                             self.myLoggingService.error(line)
                     errno += 1
                     single_errno += 1
                 else:
                     self.myLoggingService.info('文件回滚成功。 路径:' + item)
         else:
             if self.deploy_mode == Project.DEPLOY_MODE_ALL:
                 command = SSH_PREFIX + host + ' " rm -f ' + self.project.dest_path + ' && ln -s -f ' + self.taskService.get_rollback_path() \
                             + ' ' + self.project.dest_path + '"'
             elif self.deploy_mode == Project.DEPLOY_MODE_INCREMENT:
                 command = SSH_PREFIX + host + " '" + self.rsync_prefix + RSYNC_EXCLUDE_PARMS + self.taskService.get_rollback_path() + \
                         '/ ' + self.taskService.get_release_path() + "/'"
             self.myLoggingService.info('command:' + command)
             commandService = CommandService(command)
             if commandService.returncode > 0:
                 self.myLoggingService.error('回滚异常, host:' + host)
                 if len(commandService.stdout_as_list) > 0:
                     self.myLoggingService.error('脚本输出:')
                     for line in commandService.stdout_as_list:
                         self.myLoggingService.error(line)
                 if len(commandService.stderr_as_list) > 0:
                     self.myLoggingService.error('脚本错误:')
                     for line in commandService.stderr_as_list:
                         self.myLoggingService.error(line)
                 errno += 1
                 single_errno += 1
                 try:
                     taskHostRela = TaskHostRela.objects.get(host=host,
                                                             task=self.task)
                 except:
                     taskHostRela = TaskHostRela(task=self.task)
                     taskHostRela.task = self.task
                     taskHostRela.host = host
                 taskHostRela.status_rollback = TaskHostRela.STATUS_ROLLBACK_ERROR
                 taskHostRela.save()
                 continue
             else:
                 status_rollback = TaskHostRela.STATUS_ROLLBACK_SUCCESS
                 self.myLoggingService.info('回滚正常, host:' + host)
                 if len(commandService.stdout_as_list) > 0:
                     self.myLoggingService.info('脚本输出:')
                     for line in commandService.stdout_as_list:
                         self.myLoggingService.info(line)
         # after hook
         res_hook_after = self.taskService.exec_hook_after_release(host)
         if res_hook_after:
             status_rollback = TaskHostRela.STATUS_ROLLBACK_SUCCESS
             self.myLoggingService.info('回滚后调用钩子成功')
         elif res_hook_after == False:
             status_rollback = TaskHostRela.STATUS_ROLLBACK_ERROR
             self.myLoggingService.error('回滚后调用钩子失败')
             errno += 1
             single_errno += 1
         else:
             status_rollback = TaskHostRela.STATUS_ROLLBACK_SUCCESS
             self.myLoggingService.info('未检测到回滚后调用钩子')
         #标记主机状态
         try:
             taskHostRela = TaskHostRela.objects.get(host=host,
                                                     task=self.task)
             taskHostRela.status_rollback = status_rollback
             taskHostRela.save()
         except:
             pass
         if single_errno > 0:
             self.myLoggingService.error('主机回滚失败,' + host)
         else:
             self.myLoggingService.info('主机回滚成功,' + host)
     if errno > 0:
         self.task.status_rollback = Task.STATUS_ROLLBACK_FINISH_ERR
         self.myLoggingService.info('回滚结束,有异常情况')
     else:
         self.task.status_rollback = Task.STATUS_ROLLBACK_FINISH
         self.myLoggingService.info('回滚成功')
     self.task.save()
     send_notify(self.task.id, rollback=True)
示例#7
0
    def release(self):
        errno = 0
        #检查所有文件是否在工作区存在
        if self.task.scope == Task.SCOPE_BY_FILE:
            if self.check_file_exists() == False:
                self.task.status = Task.STATUS_RELEASE_FINISH_ERR
                self.myLoggingService.error('检查文件列表路径失败,发布退出')
                self.task.save()
                send_notify(self.task.id)
                return None
        # 从远程主机备份文件
        if self.task.scope == Task.SCOPE_BY_FILE:
            self.myLoggingService.info('准备从远程主机备份指定文件')
            rollback_host = self.all_host[0]
            self.myLoggingService.info('备份主机地址:' + rollback_host)
            rollback_path = settings.ROLLBACK_PATH[0] + '/' + str(self.task.id)
            if os.path.exists(rollback_path) == False:
                os.mkdir(rollback_path)
            for item in self.task.files_list.splitlines():
                file_path = rollback_path + '/' + item
                command = self.rsync_prefix + RSYNC_EXCLUDE_PARMS + ' ' + \
                        rollback_host + ':' + self.taskService.get_release_path() + '/' + item + \
                        ' ' + file_path
                commandService = CommandService(command)
                if commandService.returncode > 0:
                    self.myLoggingService.error('文件备份失败, 新文件可忽略。 路径:' + item)
                    self.myLoggingService.error(command)
                    if len(commandService.stdout_as_list) > 0:
                        for line in commandService.stdout_as_list:
                            self.myLoggingService.error(line)
                    if len(commandService.stderr) > 0:
                        for line in commandService.stderr_as_list:
                            self.myLoggingService.error(line)
                else:
                    self.myLoggingService.info('文件备份成功。 路径:' + item)
        for host in self.all_host:
            single_errno = 0
            self.myLoggingService.info('开始发布主机, host:' + host)
            if self.task.scope == Task.SCOPE_BY_FILE:
                for item in self.task.files_list.splitlines():
                    file_path = self.working_dir + '/' + item
                    command = self.rsync_prefix + RSYNC_EXCLUDE_PARMS + file_path + ' ' + \
                            host + ':' + self.taskService.get_release_path()
                    commandService = CommandService(command)
                    if commandService.returncode > 0:
                        self.myLoggingService.error('文件发布失败。 路径:' + item)
                        self.myLoggingService.error(command)
                        if len(commandService.stdout_as_list) > 0:
                            for line in commandService.stdout_as_list:
                                self.myLoggingService.error(line)
                        if len(commandService.stderr) > 0:
                            for line in commandService.stderr_as_list:
                                self.myLoggingService.error(line)
                        errno += 1
                        single_errno += 1
                    else:
                        self.myLoggingService.info('文件发布成功。 路径:' + item)
            else:
                if self.deploy_mode == Project.DEPLOY_MODE_ALL:
                    command = self.rsync_prefix + RSYNC_EXCLUDE_PARMS + self.working_dir + '/ ' + \
                            host + ':' + self.taskService.get_release_path()
                elif self.deploy_mode == Project.DEPLOY_MODE_INCREMENT:
                    command = self.rsync_prefix + RSYNC_EXCLUDE_PARMS + self.working_dir + '/ ' + \
                            host + ':' + self.taskService.get_release_path() + ' --backup --backup-dir=' + self.taskService.get_rollback_path()

                self.myLoggingService.info('command:' + command)
                commandService = CommandService(command)
                self.myLoggingService.info('exit_code:' +
                                           str(commandService.returncode))
                if commandService.returncode > 0:
                    self.myLoggingService.error('同步异常, host:' + host)
                    if len(commandService.stdout_as_list) > 0:
                        self.myLoggingService.error('脚本输出:')
                        for line in commandService.stdout_as_list:
                            self.myLoggingService.error(line)
                    if len(commandService.stderr) > 0:
                        self.myLoggingService.error('脚本错误:')
                        for line in commandService.stderr_as_list:
                            self.myLoggingService.error(line)
                    errno += 1
                    single_errno += 1
                    #标记主机状态
                    taskHostRela = TaskHostRela()
                    taskHostRela.host = host
                    taskHostRela.task = self.task
                    taskHostRela.status_release = TaskHostRela.STATUS_RELEASE_ERROR
                    taskHostRela.save()
                    continue
                else:
                    status_release = TaskHostRela.STATUS_RELEASE_SUCCESS
                    self.myLoggingService.info('同步正常, host:' + host)
                    if len(commandService.stdout_as_list) > 0:
                        self.myLoggingService.info('脚本输出:')
                        for line in commandService.stdout_as_list:
                            self.myLoggingService.info(line)

                    # add link
                    if self.deploy_mode == Project.DEPLOY_MODE_ALL:
                        self.myLoggingService.info('准备切换软链接...')
                        command = SSH_PREFIX + host + ' " rm -f ' + self.project.dest_path + ' && ln -s -f ' + self.taskService.get_release_path() \
                                + ' ' + self.project.dest_path + '"'
                        self.myLoggingService.info(command)
                        commandService = CommandService(command)
                        if len(commandService.stdout_as_list) > 0:
                            self.myLoggingService.info('切换软链接出错')
                            for line in commandService.stdout_as_list:
                                self.myLoggingService.info(line)
                            errno += 1
                            single_errno += 1
                            taskHostRela = TaskHostRela()
                            taskHostRela.host = host
                            taskHostRela.task = self.task
                            taskHostRela.status_release = TaskHostRela.STATUS_RELEASE_ERROR
                            taskHostRela.save()
                            continue
                        self.myLoggingService.info('切换软链接完成')

            # after hook
            res_hook_after = self.taskService.exec_hook_after_release(host)
            if res_hook_after:
                status_release = TaskHostRela.STATUS_RELEASE_SUCCESS
                self.myLoggingService.info('发布后调用钩子成功')
            elif res_hook_after == False:
                status_release = TaskHostRela.STATUS_RELEASE_ERROR
                self.myLoggingService.error('发布后调用钩子失败')
                errno += 1
                single_errno += 1
            else:
                status_release = TaskHostRela.STATUS_RELEASE_SUCCESS
                self.myLoggingService.info('未检测到发布后钩子')

            #标记主机状态
            taskHostRela = TaskHostRela()
            taskHostRela.task = self.task
            taskHostRela.host = host
            taskHostRela.status_release = status_release
            taskHostRela.save()
            if single_errno > 0:
                self.myLoggingService.error('主机发布失败,' + host)
            else:
                self.myLoggingService.info('主机发布成功,' + host)
        if errno > 0:
            self.task.status = Task.STATUS_RELEASE_FINISH_ERR
            self.myLoggingService.info('发布失败,有异常情况')
        else:
            self.task.status = Task.STATUS_RELEASE_FINISH
            self.myLoggingService.info('发布成功')
        self.task.save()
        send_notify(self.task.id)