예제 #1
0
def handle_lb(username, access_token, project_id, lb_info, cc_app_id):
    """
    1. 组装 lb 配置文件
    2. 调用 bcs api 创建 Deployment
    """
    cluster_id = lb_info.get('cluster_id')
    # 查询zk的信息
    zk_res = paas_cc.get_zk_config(access_token, project_id, cluster_id)
    if zk_res.get("code") != ErrorCode.NoError:
        logger.err('获取zk信息出错,%s' % zk_res)
        raise error_codes.APIError(_("获取zk信息出错"))
    try:
        zk_data = zk_res.get("data", [])[0]
    except Exception:
        logger.err('获取zk信息出错,%s' % zk_res)
        raise error_codes.APIError(_("获取zk信息出错"))
    bcs_zookeeper = zk_data.get('bcs_zookeeper')
    zookeeper = zk_data.get('zookeeper')

    # 查询仓库地址
    jfrog_domain = paas_cc.get_jfrog_domain(access_token, project_id,
                                            cluster_id)
    if not jfrog_domain:
        jfrog_domain = DEFAUT_LB_JFROG_DOMAIN

    # 调度约束
    try:
        intersection_item = json.loads(lb_info.get("data"))
    except Exception:
        logger.exception("命名空间中的调度约束信息出错")
        raise error_codes.JsonFormatError(_("命名空间中的调度约束信息出错"))
    new_intersection_item = handle_intersection_item(intersection_item)
    constraint = {"IntersectionItem": new_intersection_item}

    # vip 组装为labels
    try:
        ip_list = json.loads(lb_info.get('ip_list'))
    except Exception:
        logger.exception("命名空间中的IP集信息出错")
        raise error_codes.JsonFormatError(_("命名空间中的IP集信息出错"))
    labels = {}
    for i, ip in enumerate(ip_list):
        _key = "io.tencent.bcs.netsvc.requestip.%s" % i
        labels[_key] = ip

    lb_name = lb_info.get('name')
    # 配置文件中的变量赋值
    now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    # 获取 namespace
    data_dict = lb_info['data_dict']
    if data_dict:
        data_dict = json.loads(data_dict)
    else:
        data_dict = {}
    if data_dict.get('image_url'):
        lb_jfrog_url = f'{jfrog_domain}{data_dict["image_url"]}'
    else:
        lb_jfrog_url = f'{jfrog_domain}/paas/public/mesos/bcs-loadbalance'
    resource_limit = data_dict.get('resources', {}).get('limits', {})
    ns_name = get_namespace_name(access_token, project_id, data_dict)
    # 获取data标准日志输出
    data_info = get_data_id_by_project_id(project_id)
    data_id = str(data_info.get('standard_data_id'))

    context = {
        'SYS_PROJECT_KIND': 2,  # 固定为mesos
        'SYS_STANDARD_DATA_ID': data_id,
        'SYS_CC_APP_ID': cc_app_id,
        'SYS_PROJECT_ID': project_id,
        'SYS_OPERATOR': username,
        'SYS_CLUSTER_ID': cluster_id,
        'SYS_BCSGROUP': lb_name,
        'SYS_CC_ZK': zookeeper,
        'SYS_BCS_ZK': bcs_zookeeper,
        'SYS_CREATOR': username,
        'SYS_UPDATOR': username,
        'SYS_CREATE_TIME': now_time,
        'SYS_UPDATE_TIME': now_time,
        'SYS_JFROG_DOMAIN_URL': lb_jfrog_url,
        'CPU': str(resource_limit.get('cpu', 1)),
        'MEMORY': str(resource_limit.get('memory', 1024)),
        'IMAGE_VERSION': data_dict.get('image_version') or '1.1.0',
        'FORWARD_MODE': data_dict.get('forward_mode') or 'haproxy',
        'SYS_NAMESPACE': ns_name,
        'ETH_VALUE': data_dict.get('eth_value') or 'eth1',
        'LB_ADMIN_PORT': DEFAULT_LB_ADMIN_PORT
    }

    # 组装 lb 配置文件
    lb_config = copy.deepcopy(LB_SYS_CONFIG)
    lb_config['spec']['instance'] = data_dict.get('instance', 1)
    lb_config['constraint'] = constraint
    lb_config['spec']['template']['metadata']['labels'] = labels
    lb_config['spec']['template']['spec']['containers'][0]['ports'][0]['hostPort'] = \
        data_dict.get('host_port') or 31000
    # 处理网络模式
    spec = lb_config.get('spec', {}).get('template', {}).get('spec', {})
    spec['networkMode'] = data_dict.get('networkMode')
    spec['networkType'] = data_dict.get('networkType')
    spec['custom_value'] = data_dict.get('custom_value')
    lb_config = handel_custom_network_mode(lb_config)

    lb_config = json.dumps(lb_config)
    try:
        config_profile = render_mako_context(lb_config, context)
    except Exception:
        logger.exception(u"LoadBalance配置文件变量替换错误\nconfig:%s\ncontext:%s" %
                         (lb_config, context))
        raise ValidationError(_("配置文件中有未替换的变量"))

    config_profile = json.loads(config_profile)
    # 调用bcs api 创建
    client = mesos.MesosClient(access_token, project_id, cluster_id, env=None)
    result = client.create_deployment(ns_name, config_profile)
    if not result.get('result'):
        error_msg = result.get('message', '')
        logger.error(f"命名空间[{ns_name}]下创建LoadBalance[{lb_name}]出错:{error_msg}")
        return False, error_msg
    return True, ''
예제 #2
0
    def update_services(self, request, project_id, cluster_id, namespace,
                        name):
        """更新 service"""
        access_token = request.user.token.access_token
        flag, project_kind = self.get_project_kind(request, project_id)
        if not flag:
            return project_kind

        if project_kind == MESOS_VALUE:
            # mesos 相关数据
            slz_class = ServiceCreateOrUpdateSLZ
            s_sys_con = SEVICE_SYS_CONFIG
            s_cate = 'service'
        else:
            if namespace in K8S_SYS_NAMESPACE:
                return Response({
                    "code":
                    400,
                    "message":
                    _("不允许操作系统命名空间[{}]").format(','.join(K8S_SYS_NAMESPACE)),
                    "data": {}
                })
            # k8s 相关数据
            slz_class = K8sServiceCreateOrUpdateSLZ
            s_sys_con = K8S_SEVICE_SYS_CONFIG
            s_cate = 'K8sService'

        request_data = request.data or {}
        request_data['version_id'] = request_data['version']
        request_data['item_id'] = 0
        request_data['project_id'] = project_id
        show_version_name = request_data.get('show_version_name', '')
        # 验证请求参数
        slz = slz_class(data=request.data)
        slz.is_valid(raise_exception=True)
        data = slz.data
        namespace_id = data['namespace_id']

        # 检查是否有命名空间的使用权限
        perm = bcs_perm.Namespace(request, project_id, namespace_id)
        perm.can_use(raise_exception=True)

        config = json.loads(data['config'])
        #  获取关联的应用列表
        version_id = data['version_id']
        version_entity = VersionedEntity.objects.get(id=version_id)
        entity = version_entity.get_entity()

        # 实例化时后台需要做的处理
        if project_kind == MESOS_VALUE:
            app_weight = json.loads(data['app_id'])
            apps = entity.get('application') if entity else None
            application_id_list = apps.split(',') if apps else []

            app_id_list = app_weight.keys()
            service_app_list = Application.objects.filter(
                id__in=application_id_list, app_id__in=app_id_list)

            lb_name = data.get('lb_name', '')
            handel_service_db_config(config, service_app_list, app_weight,
                                     lb_name, version_id)
        else:
            logger.exception(
                f"deploy_tag_list {type(data['deploy_tag_list'])}")
            handel_k8s_service_db_config(config,
                                         data['deploy_tag_list'],
                                         version_id,
                                         is_upadte=True)
            resource_version = data['resource_version']
            config['metadata']['resourceVersion'] = resource_version
            cluster_version = get_cluster_version(access_token, project_id,
                                                  cluster_id)
            config = handle_k8s_api_version(config, cluster_id,
                                            cluster_version, 'Service')
        # 前端的缓存数据储存到备注中
        config = handle_webcache_config(config)

        # 获取上下文信息
        username = request.user.username
        now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        context = {
            'SYS_CLUSTER_ID': cluster_id,
            'SYS_NAMESPACE': namespace,
            'SYS_VERSION_ID': version_id,
            'SYS_PROJECT_ID': project_id,
            'SYS_OPERATOR': username,
            'SYS_TEMPLATE_ID': version_entity.template_id,
            'SYS_VERSION': show_version_name,
            'LABLE_VERSION': show_version_name,
            'SYS_INSTANCE_ID': data['instance_id'],
            'SYS_CREATOR': data.get('creator', ''),
            'SYS_CREATE_TIME': data.get('create_time', ''),
            'SYS_UPDATOR': username,
            'SYS_UPDATE_TIME': now_time,
        }
        bcs_context = get_bcs_context(access_token, project_id)
        context.update(bcs_context)

        # 生成配置文件
        sys_config = copy.deepcopy(s_sys_con)
        resource_config = update_nested_dict(config, sys_config)
        resource_config = json.dumps(resource_config)
        try:
            config_profile = render_mako_context(resource_config, context)
        except Exception:
            logger.exception(u"配置文件变量替换出错\nconfig:%s\ncontext:%s" %
                             (resource_config, context))
            raise ValidationError(_("配置文件中有未替换的变量"))

        service_name = config.get('metadata', {}).get('name')
        _config_content = {
            'name': service_name,
            'config': json.loads(config_profile),
            'context': context
        }

        # 更新 service
        config_objs = InstanceConfig.objects.filter(
            namespace=namespace_id,
            category=s_cate,
            name=service_name,
        )
        if config_objs.exists():
            config_objs.update(
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
            _instance_config = config_objs.first()
        else:
            _instance_config = InstanceConfig.objects.create(
                namespace=namespace_id,
                category=s_cate,
                name=service_name,
                config=config_profile,
                instance_id=data.get('instance_id', 0),
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
        _config_content['instance_config_id'] = _instance_config.id
        configuration = {namespace_id: {s_cate: [_config_content]}}

        driver = get_scheduler_driver(access_token, project_id, configuration,
                                      request.project.kind)
        result = driver.instantiation(is_update=True)

        failed = []
        if isinstance(result, dict):
            failed = result.get('failed') or []
        # 添加操作审计
        activity_client.ContextActivityLogClient(
            project_id=project_id,
            user=username,
            resource_type="instance",
            resource=service_name,
            resource_id=_instance_config.id,
            extra=json.dumps(configuration),
            description=_("更新Service[{}]命名空间[{}]").format(
                service_name, namespace),
        ).log_modify(activity_status="failed" if failed else "succeed")

        if failed:
            return Response({
                "code":
                400,
                "message":
                _("Service[{}]在命名空间[{}]更新失败,请联系集群管理员解决").format(
                    service_name, namespace),
                "data": {},
            })
        return Response({"code": 0, "message": "OK", "data": {}})
예제 #3
0
파일: views.py 프로젝트: douit/bk-bcs-saas
    def update_resource(self, request, project_id, cluster_id, namespace,
                        name):
        """更新
        """
        access_token = request.user.token.access_token
        project_kind = request.project.kind

        if project_kind == MESOS_VALUE:
            # mesos 相关数据
            slz_class = self.mesos_slz
            s_sys_con = self.mesos_sys_config
            s_cate = self.mesos_cate
        else:
            if namespace in constants.K8S_SYS_NAMESPACE:
                return Response({
                    "code":
                    400,
                    "message":
                    _("不允许操作系统命名空间[{}]").format(','.join(
                        constants.K8S_SYS_NAMESPACE)),
                    "data": {}
                })
            # k8s 相关数据
            slz_class = self.k8s_slz
            s_sys_con = self.k8s_sys_config
            s_cate = self.k8s_cate

        request_data = request.data or {}
        request_data['project_id'] = project_id
        # 验证请求参数
        slz = slz_class(data=request.data)
        slz.is_valid(raise_exception=True)
        data = slz.data

        config = json.loads(data['config'])
        namespace_id = data['namespace_id']
        username = request.user.username

        # 检查是否有命名空间的使用权限
        perm = bcs_perm.Namespace(request, project_id, namespace_id)
        perm.can_use(raise_exception=True)

        # 对配置文件做处理
        gparams = {
            "access_token": access_token,
            "project_id": project_id,
            "username": username
        }
        generator = GENERATOR_DICT.get(s_cate)(0, namespace_id, **gparams)
        config = generator.handle_db_config(db_config=config)
        # 获取上下文信息
        context = generator.context
        now_time = context.get('SYS_UPDATE_TIME')
        instance_id = data.get('instance_id', 0)
        context.update({
            'SYS_CREATOR': data.get('creator', ''),
            'SYS_CREATE_TIME': data.get('create_time', ''),
            'SYS_INSTANCE_ID': instance_id
        })

        # 生成配置文件
        sys_config = copy.deepcopy(s_sys_con)
        resource_config = update_nested_dict(config, sys_config)
        resource_config = json.dumps(resource_config)
        try:
            config_profile = render_mako_context(resource_config, context)
        except Exception:
            logger.exception(u"配置文件变量替换出错\nconfig:%s\ncontext:%s" %
                             (resource_config, context))
            raise ValidationError(_("配置文件中有未替换的变量"))

        config_profile = generator.format_config_profile(config_profile)

        service_name = config.get('metadata', {}).get('name')
        _config_content = {
            'name': service_name,
            'config': json.loads(config_profile),
            'context': context
        }

        # 更新db中的数据
        config_objs = InstanceConfig.objects.filter(
            namespace=namespace_id,
            category=s_cate,
            name=service_name,
        )
        if config_objs.exists():
            config_objs.update(
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False,
            )
            _instance_config = config_objs.first()
        else:
            _instance_config = InstanceConfig.objects.create(
                namespace=namespace_id,
                category=s_cate,
                name=service_name,
                config=config_profile,
                instance_id=instance_id,
                creator=username,
                updator=username,
                oper_type='update',
                updated=now_time,
                is_deleted=False)
        _config_content['instance_config_id'] = _instance_config.id
        configuration = {namespace_id: {s_cate: [_config_content]}}

        driver = get_scheduler_driver(access_token, project_id, configuration,
                                      request.project.kind)
        result = driver.instantiation(is_update=True)

        failed = []
        if isinstance(result, dict):
            failed = result.get('failed') or []
        # 添加操作审计
        activity_client.ContextActivityLogClient(
            project_id=project_id,
            user=username,
            resource_type="instance",
            resource=service_name,
            resource_id=_instance_config.id,
            extra=json.dumps(configuration),
            description=_("更新{}[{}]命名空间[{}]").format(
                self.category, service_name, namespace)).log_modify(
                    activity_status="failed" if failed else "succeed")

        if failed:
            return Response({
                "code":
                400,
                "message":
                _("{}[{}]在命名空间[{}]更新失败,请联系集群管理员解决").format(
                    self.category, service_name, namespace),
                "data": {}
            })
        return Response({"code": 0, "message": "OK", "data": {}})