Esempio n. 1
0
class AppSlug():
    def __init__(self, job, *args, **kwargs):
        self.job = job
        self.configs = kwargs.get("config")
        self.region_api = RegionAPI(conf=self.configs['region'])
        self.oss_api = OssAPI(conf=self.configs['oss']['ali_shanghai'])
        self.locker = TaskLocker(conf=self.configs['etcd'])
        self.user_cs_client = UserConsoleAPI(conf=self.configs['userconsole'])
        self.api = ACPAPI(conf=self.configs['region'])
        self.region_client = RegionBackAPI()
        self.slug_configs = self.configs["publish"]["slug"]
        self.is_region_slug = self.slug_configs.get('all_region_ftp')
        self.is_oss_ftp = self.slug_configs.get('oss_ftp')
        # 用户文件存储路径
        self.SRV_SLUG_BASE_DIR = self.slug_configs.get(
            'slug_path') + '{tenantId}/slug/{serviceId}/{deployVersion}.tgz'
        # 数据中心slug存储路径
        self.SLUG_PATH = self.slug_configs.get(
            'curr_region_dir') + '{serviceKey}/{appVersion}.tgz'
        self.CURR_REGION_PATH = self.slug_configs.get(
            'curr_region_path') + self.SLUG_PATH
        # 区域中心slug的ftp配置
        self.ALL_REGION_FTP_HOST = self.slug_configs.get('all_region_ftp_host')
        self.ALL_REGION_FTP_PORT = self.slug_configs.get('all_region_ftp_port')
        self.ALL_REGION_FTP_USERNAME = self.slug_configs.get(
            'all_region_username')
        self.ALL_REGION_FTP_PASSWORD = self.slug_configs.get(
            'all_region_password')
        self.ALL_REGION_FTP_NAMESPACE = self.slug_configs.get(
            'all_region_namespace')
        self.ALL_REGION_FTP_PATH = self.ALL_REGION_FTP_NAMESPACE + '{serviceKey}/{appVersion}.tgz'
        # oss存储路径
        CLOUD_ASSISTANT = self.configs.get('CLOUD_ASSISTANT')
        self.OSS_BUCKET = self.slug_configs.get('oss_bucket', "")
        self.OSS_OBJECT_NAME = CLOUD_ASSISTANT + '/{serviceKey}/{appVersion}.tgz'
        logger.debug("mq_work.app_slug", 'init app slug')

    def do_work(self):
        try:
            logger.debug("mq_work.app_slug",
                         'get task....{}'.format(self.job.body))
            task = json.loads(self.job.body)
            self.task = task
            if "event_id" in self.task:
                self.event_id = task["event_id"]
                self.log = EventLog().bind(
                    event_id=self.event_id, step="image_manual")
            else:
                self.event_id = ""
                self.log = EventLog().bind(event_id="", step="image_manual")
            if task['action'] == 'create_new_version':
                self.log.info("开始分享新版本应用。")
                self.create_new_version()
            elif task['action'] == 'download_and_deploy':
                self.log.info("开始同步应用。")
                self.download_and_deploy()
            elif task['action'] == 'delete_old_version':
                self.log.info("开始删除旧版本应用。")
                self.delete_old_version()
        except Exception as e:
            logger.exception('mq_work.app_slug', e)

    def _upload_ftp(self, service_key, app_version, md5file):
        """ 上传文件到ftp """
        utils = FTPUtils(
            host=self.ALL_REGION_FTP_HOST,
            username=self.ALL_REGION_FTP_USERNAME,
            password=self.ALL_REGION_FTP_PASSWORD,
            namespace=self.ALL_REGION_FTP_NAMESPACE,
            port=self.ALL_REGION_FTP_PORT)
        # 检查service_key对应的文件是否存在,不存在生成
        service_dir = self.ALL_REGION_FTP_NAMESPACE + service_key
        logger.debug("mq_work.app_slug",
                    'slug task is {}'.format(self.task))
        logger.debug("mq_work.app_slug",
                     '*******upload dir is {}'.format(service_dir))
        utils.check_dir(service_dir)
        # 上传文件
        curr_region_slug = self.CURR_REGION_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        logger.debug("mq_work.app_slug",
                     '*******upload file path is {}'.format(curr_region_slug))
        utils.upload(service_dir, curr_region_slug)
        # 上传md5文件
        if md5file:
            utils.upload(service_dir, md5file)
        return True

    def _create_md5(self, md5string, dest_slug_file):
        try:
            md5file = dest_slug_file + ".md5"
            f = open(md5file, "w")
            f.write(md5string)
            f.close()
            return md5file
        except Exception as e:
            logger.error("mq_work.app_slug", "sum file md5 filed!")
            logger.exception("mq_work.app_slug", e)
        return None

    def _check_md5(self, md5string, md5file):
        try:
            f = open(md5file)
            new_md5 = f.readline()
            return md5string == new_md5
        except Exception as e:
            logger.error("mq_work.app_slug", "check md5 filed!")
            logger.exception("mq_work.app_slug", e)
        return False

    def create_new_version(self):
        service_key = self.task['service_key']
        app_version = self.task['app_version']
        service_id = self.task['service_id']
        deploy_version = self.task['deploy_version']
        tenant_id = self.task['tenant_id']
        dest = self.task['dest']
        share_id = self.task.get('share_id', None)

        # 检查数据中心下路径是否存在
        source_slug_file = self.SRV_SLUG_BASE_DIR.format(
            tenantId=tenant_id,
            serviceId=service_id,
            deployVersion=deploy_version)
        self.log.debug("数据中心文件路径{0}".format(source_slug_file))
        # 当前数据中心文件名称
        dest_slug_file = self.CURR_REGION_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        self.log.debug('当前数据中心文件名称'.format(dest_slug_file))
        # 检查目录是否存在
        curr_region_dir = os.path.dirname(dest_slug_file)
        if not os.path.exists(curr_region_dir):
            os.makedirs(curr_region_dir)
        # 复制文件
        self.log.debug(
            "开始复制文件 file {0} to {1}".format(source_slug_file, dest_slug_file))
        shutil.copyfile(source_slug_file, dest_slug_file)
        # 计算md5
        md5string = get_md5(source_slug_file)
        # 生成md5file
        md5file = self._create_md5(md5string, dest_slug_file)
        if md5file is None:
            self.log.error("md5文件没有生成。")
        # 区域中心对象存储,使用ftp
        slug = self.SLUG_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        if dest == "yb":
            data = {
                'service_key': service_key,
                'app_version': app_version,
                'slug': slug,
                'image': "",
                'dest_yb': True,
                'dest_ys': False,
            }
            if share_id is not None:
                data['share_id'] = share_id
            try:
                self.region_client.service_publish_new_region(data)
            except Exception as e:
                self.region_client.service_publish_failure_region(data)
                self.log.error(
                    "云帮应用本地发布失败,保存publish 失败。{0}".format(e.message),
                    step="callback",
                    status="failure")
                pass
            if self.is_region_slug:
                try:
                    self.log.info("开始上传应用到本地云帮")
                    self._upload_ftp(service_key, app_version, md5file)
                    logger.debug("mq_work.app_slug",
                                 "*******ftp upload success!")
                    # self.update_publish_event(event_id=event_id, status='end', desc=u"云帮应用本地发布完毕")
                    self.user_cs_client.service_publish_success(
                        json.dumps(data))
                    try:
                        self.region_client.service_publish_success_region(data)
                    except Exception as e:
                        self.region_client.service_publish_failure_region(data)
                        logger.exception(e)
                        pass

                    self.log.info("云帮应用本地发布完毕", step="last", status="success")
                except Exception as e:
                    logger.error("mq_work.app_slug",
                                 "*******ftp upload failed")
                    logger.exception("mq_work.app_slug", e)
                    self.region_client.service_publish_failure_region(data)
                    self.log.info(
                        "云帮应用本地发布失败。{}".format(e.message),
                        step="callback",
                        status="failure")
            else:

                self.user_cs_client.service_publish_success(json.dumps(data))
                try:
                    self.region_client.service_publish_success_region(data)
                except Exception as e:
                    self.region_client.service_publish_failure_region(data)
                    logger.exception(e)
                    pass

                self.log.info("云帮应用本地发布完毕", step="last", status="success")
        elif dest == "ys":
            data = {
                'service_key': service_key,
                'app_version': app_version,
                'slug': slug,
                'image': "",
                'dest_ys': True,
                'dest_yb': False
            }
            if share_id is not None:
                data['share_id'] = share_id
            try:
                self.region_client.service_publish_new_region(data)
            except Exception as e:
                self.region_client.service_publish_failure_region(data)
                self.log.error(
                    "云帮应用本地发布失败,保存publish 失败。{0}".format(e.message),
                    step="callback",
                    status="failure")
                pass
            if self.is_oss_ftp:
                try:
                    self.log.info("开始上传应用到云市")
                    self._upload_ftp(service_key, app_version, md5file)
                    logger.debug("mq_work.app_slug",
                                 "*******ftp upload success!")
                    self.log.info("云市应用发布完毕", step="last", status="success")

                    self.user_cs_client.service_publish_success(
                        json.dumps(data))
                    try:
                        self.region_client.service_publish_success_region(data)
                    except Exception as e:
                        logger.exception(e)
                        self.region_client.service_publish_failure_region(data)
                        pass

                except Exception as e:
                    logger.error("mq_work.app_slug",
                                 "*******ftp upload failed, {0}".format(e))
                    self.region_client.service_publish_failure_region(data)
                    self.log.error(
                        "云市应用发布失败.", status="failure", step="callback")
            else:
                self.user_cs_client.service_publish_success(json.dumps(data))
                try:
                    self.region_client.service_publish_success_region(data)
                except Exception as e:
                    logger.exception(e)
                    self.region_client.service_publish_failure_region(data)
                    pass

                self.log.info("云市应用发布完毕", step="last", status="success")

    def _download_ftp(self, service_key, app_version, namespace, is_md5=False):
        """ 云帮ftp下载文件 """
        utils = FTPUtils(
            host=self.ALL_REGION_FTP_HOST,
            username=self.ALL_REGION_FTP_USERNAME,
            password=self.ALL_REGION_FTP_PASSWORD,
            namespace=self.ALL_REGION_FTP_NAMESPACE,
            port=self.ALL_REGION_FTP_PORT)
        logger.info("mq_work.app_slug",
                    "*******[download]download file from ftp")
        # 检查service_key对应的文件是否存在,不存在生成
        remote_file = self.ALL_REGION_FTP_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        if is_md5:
            remote_file += ".md5"
        if not namespace:
            logger.info("mq_work.app_slug",
                        "*******[download]namespace is null")
            logger.error("mq_work.app_slug",
                         "*******[download]namespace is null")
        else:
            logger.info("mq_work.app_slug",
                        "*******[download]namespace is {}".format(namespace))
            remote_file = "../" + namespace + "/" + remote_file
        logger.info("mq_work.app_slug",
                    "*******[download]remote file is {}".format(remote_file))
        curr_region_slug = self.CURR_REGION_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        if is_md5:
            curr_region_slug += ".md5"
        logger.info(
            "mq_work.app_slug",
            "*******[download]curr_region_slug is {}".format(curr_region_slug))
        return utils.download(remote_file, curr_region_slug)

    def _download_ftp_market(self,
                             service_key,
                             app_version,
                             namespace,
                             is_md5=False):
        """ 云市ftp下载文件 """
        utils = FTPUtils(
            host=self.ALL_REGION_FTP_HOST,
            username=self.ALL_REGION_FTP_USERNAME,
            password=self.ALL_REGION_FTP_PASSWORD,
            namespace=self.ALL_REGION_FTP_NAMESPACE,
            port=self.ALL_REGION_FTP_PORT)
        logger.info("mq_work.app_slug",
                    "*******[download]download file from ftp")
        # 检查service_key对应的文件是否存在,不存在生成
        remote_file = self.ALL_REGION_FTP_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        if is_md5:
            remote_file += ".md5"
        if not namespace:
            logger.info("mq_work.app_slug",
                        "*******[download]namespace is null")
            logger.error("mq_work.app_slug",
                         "*******[download]namespace is null")
        else:
            logger.info("mq_work.app_slug",
                        "*******[download]namespace is {}".format(namespace))
            remote_file = "../" + namespace + "/" + remote_file
        logger.info("mq_work.app_slug",
                    "*******[download]remote file is {}".format(remote_file))
        curr_region_slug = self.CURR_REGION_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        if is_md5:
            curr_region_slug += ".md5"
        logger.info(
            "mq_work.app_slug",
            "*******[download]curr_region_slug is {}".format(curr_region_slug))
        return utils.download(remote_file, curr_region_slug)

    def download_and_deploy(self):
        """ 下载slug包 """

        def start_service(service_id, deploy_version, operator):
            # body = {
            #     "deploy_version": deploy_version,
            #     "operator": operator,
            #     "event_id": self.event_id
            # }
            body = {
                "deploy_version": deploy_version,
                "event_id": self.event_id
            }
            try:
                # logger.info("mq_work.app_slug", "start service {}:{}".format(service_id, deploy_version))
                self.log.info("开始调用api启动应用。")
                self.api.upgrade_service(self.tenant_name, self.service_alias, json.dumps(body))
                # self.region_api.start_service(service_id, json.dumps(body))
            except self.region_api.CallApiError, e:
                self.log.info(
                    "开始调用api启动应用失败。{}".format(e.message),
                    step="callback",
                    status="failure")
                logger.exception("mq_work.app_slug", e)

        service_key = self.task['app_key']
        namespace = self.task['namespace']
        app_version = self.task['app_version']
        tenant_name = self.task['tenant_name']
        service_alias = self.task['service_alias']
        event_id = self.task['event_id']

        # 检查数据中心的是否存在slug包
        dest_slug_file = self.CURR_REGION_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        logger.info("mq_work.app_slug",
                    "dest_slug_file:{}".format(dest_slug_file))
        ftp_ok = False
        try:
            # 检查当前服务器是否有slug文件
            if os.path.exists(dest_slug_file):
                self.log.debug("当前服务器存在本应用。本机同步开始")
                md5string = get_md5(dest_slug_file)
                # 检查云帮ftp是否打开, 下载md5进行校验
                md5_ok = False
                if self.is_region_slug:
                    self.log.debug("文件MD5校验开始。")
                    try:
                        md5_ok = self._download_ftp(service_key, app_version,
                                                    namespace, True)
                        self.log.info("MD5校验完成。")
                    except Exception as e:
                        logger.info(
                            "mq_work.app_slug",
                            "download md5 file from cloudassistant ftp failed!"
                        )
                        self.log.error(
                            "MD5校验失败。{}".format(e.message),
                            step="callback",
                            status="failure")
                        logger.exception("mq_work.app_slug", e)
                # md5未下载并且云市ftp开启
                if not md5_ok and self.is_oss_ftp:
                    self.log.info("MD5校验不通过。开始从云市同步新版本。")
                    try:
                        md5_ok = self._download_ftp_market(
                            service_key, app_version, namespace, True)
                    except Exception as e:
                        self.log.info(
                            "从云市同步新版本发生异常。{}".format(e.message),
                            step="callback",
                            status="failure")
                        logger.exception("mq_work.app_slug", e)
                if md5_ok:
                    md5file = dest_slug_file + ".md5"
                    same_file = self._check_md5(md5string, md5file)
                    if same_file:
                        logger.debug("mq_work.app_slug", "md5 check same.")
                        ftp_ok = True
                    else:
                        logger.debug(
                            "mq_work.app_slug",
                            "file md5 is changed, now delete old file")
                        os.remove(dest_slug_file)
                else:
                    logger.debug("mq_work.app_slug",
                                 "md5file download failed, now delete slug")
                    os.remove(dest_slug_file)

            # 检查当前服务器是否有slug文件
            if not os.path.exists(dest_slug_file):
                curr_region_dir = os.path.dirname(dest_slug_file)
                if not os.path.exists(curr_region_dir):
                    os.makedirs(curr_region_dir)
                logger.debug("mq_work.app_slug",
                             "now check ftp:".format(self.is_region_slug))
                # 云帮ftp开关是否打开
                if self.is_region_slug:
                    logger.debug('mq_work.app_slug', 'now check file on ftp!')
                    try:
                        ftp_ok = self._download_ftp(service_key, app_version,
                                                    namespace)
                    except Exception as e:
                        logger.info("mq_work.app_slug",
                                    "download object failed")
                        logger.exception("mq_work.app_slug", e)
                    logger.debug(
                        "mq_work.app_slug",
                        "*******[ftp download slug]result:==={}".format(
                            ftp_ok))

                # 判断是否需要从云市上下载,未下载并且云市ftp开启
                if not ftp_ok and self.is_oss_ftp:
                    logger.info(
                        "mq_work.app_slug",
                        "now download from hub ftp:{}".format(dest_slug_file))
                    ftp_ok = self._download_ftp_market(service_key,
                                                       app_version, namespace)
                    logger.debug(
                        "mq_work.app_slug",
                        "*******[ftp download slug]result:==={}".format(
                            ftp_ok))
            else:
                ftp_ok = True
        except Exception as e:
            logger.exception("mq_work.app_slug", e)
        version_status = {
            "final_status":"failure",
        }
        if ftp_ok:
            self.log.info("应用同步完成,开始启动应用。", step="app-image", status="success")
            version_body = {
                "type": 'slug',
                "path": dest_slug_file,
                "event_id": self.event_id
            }
            version_status = {
                "final_status":"success",
            }
            try:
                self.region_client.update_version_region(json.dumps(version_body))
                self.region_client.update_version_event(self.event_id,json.dumps(version_status))
            except Exception as e:
                pass
            try:
                body = {
                    "deploy_version": self.task['deploy_version'],
                    "event_id": self.event_id
                }
                # self.api.start_service(tenant_name, service_alias, event_id)
                self.api.upgrade_service(self.task['tenant_name'], self.task['service_alias'], json.dumps(body))
            except Exception as e:
                logger.exception(e)
                self.log.error(
                    "应用自动启动失败。请手动启动", step="callback", status="failure")
        else:
            self.log.error("应用同步失败。", step="callback", status="failure")
            try:
                self.region_client.update_version_event(self.event_id,json.dumps(version_status))
            except Exception as e:
                self.log.error("更新version信息失败", step="app-slug")
                pass
Esempio n. 2
0
    def create_new_version(self):
        service_key = self.task['service_key']
        app_version = self.task['app_version']
        service_id = self.task['service_id']
        deploy_version = self.task['deploy_version']
        tenant_id = self.task['tenant_id']
        dest = self.task['dest']
        share_id = self.task.get('share_id', None)

        # 检查数据中心下路径是否存在
        source_slug_file = self.SRV_SLUG_BASE_DIR.format(
            tenantId=tenant_id,
            serviceId=service_id,
            deployVersion=deploy_version)
        self.log.debug("数据中心文件路径{0}".format(source_slug_file))
        # 当前数据中心文件名称
        dest_slug_file = self.CURR_REGION_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        self.log.debug('当前数据中心文件名称'.format(dest_slug_file))
        # 检查目录是否存在
        curr_region_dir = os.path.dirname(dest_slug_file)
        if not os.path.exists(curr_region_dir):
            os.makedirs(curr_region_dir)
        # 复制文件
        self.log.debug(
            "开始复制文件 file {0} to {1}".format(source_slug_file, dest_slug_file))
        shutil.copyfile(source_slug_file, dest_slug_file)
        # 计算md5
        md5string = get_md5(source_slug_file)
        # 生成md5file
        md5file = self._create_md5(md5string, dest_slug_file)
        if md5file is None:
            self.log.error("md5文件没有生成。")
        # 区域中心对象存储,使用ftp
        slug = self.SLUG_PATH.format(
            serviceKey=service_key, appVersion=app_version)
        if dest == "yb":
            data = {
                'service_key': service_key,
                'app_version': app_version,
                'slug': slug,
                'image': "",
                'dest_yb': True,
                'dest_ys': False,
            }
            if share_id is not None:
                data['share_id'] = share_id
            try:
                self.region_client.service_publish_new_region(data)
            except Exception as e:
                self.region_client.service_publish_failure_region(data)
                self.log.error(
                    "云帮应用本地发布失败,保存publish 失败。{0}".format(e.message),
                    step="callback",
                    status="failure")
                pass
            if self.is_region_slug:
                try:
                    self.log.info("开始上传应用到本地云帮")
                    self._upload_ftp(service_key, app_version, md5file)
                    logger.debug("mq_work.app_slug",
                                 "*******ftp upload success!")
                    # self.update_publish_event(event_id=event_id, status='end', desc=u"云帮应用本地发布完毕")
                    self.user_cs_client.service_publish_success(
                        json.dumps(data))
                    try:
                        self.region_client.service_publish_success_region(data)
                    except Exception as e:
                        self.region_client.service_publish_failure_region(data)
                        logger.exception(e)
                        pass

                    self.log.info("云帮应用本地发布完毕", step="last", status="success")
                except Exception as e:
                    logger.error("mq_work.app_slug",
                                 "*******ftp upload failed")
                    logger.exception("mq_work.app_slug", e)
                    self.region_client.service_publish_failure_region(data)
                    self.log.info(
                        "云帮应用本地发布失败。{}".format(e.message),
                        step="callback",
                        status="failure")
            else:

                self.user_cs_client.service_publish_success(json.dumps(data))
                try:
                    self.region_client.service_publish_success_region(data)
                except Exception as e:
                    self.region_client.service_publish_failure_region(data)
                    logger.exception(e)
                    pass

                self.log.info("云帮应用本地发布完毕", step="last", status="success")
        elif dest == "ys":
            data = {
                'service_key': service_key,
                'app_version': app_version,
                'slug': slug,
                'image': "",
                'dest_ys': True,
                'dest_yb': False
            }
            if share_id is not None:
                data['share_id'] = share_id
            try:
                self.region_client.service_publish_new_region(data)
            except Exception as e:
                self.region_client.service_publish_failure_region(data)
                self.log.error(
                    "云帮应用本地发布失败,保存publish 失败。{0}".format(e.message),
                    step="callback",
                    status="failure")
                pass
            if self.is_oss_ftp:
                try:
                    self.log.info("开始上传应用到云市")
                    self._upload_ftp(service_key, app_version, md5file)
                    logger.debug("mq_work.app_slug",
                                 "*******ftp upload success!")
                    self.log.info("云市应用发布完毕", step="last", status="success")

                    self.user_cs_client.service_publish_success(
                        json.dumps(data))
                    try:
                        self.region_client.service_publish_success_region(data)
                    except Exception as e:
                        logger.exception(e)
                        self.region_client.service_publish_failure_region(data)
                        pass

                except Exception as e:
                    logger.error("mq_work.app_slug",
                                 "*******ftp upload failed, {0}".format(e))
                    self.region_client.service_publish_failure_region(data)
                    self.log.error(
                        "云市应用发布失败.", status="failure", step="callback")
            else:
                self.user_cs_client.service_publish_success(json.dumps(data))
                try:
                    self.region_client.service_publish_success_region(data)
                except Exception as e:
                    logger.exception(e)
                    self.region_client.service_publish_failure_region(data)
                    pass

                self.log.info("云市应用发布完毕", step="last", status="success")