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, ''
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": {}})
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": {}})