def post(self, request, project_id, version_id): version_entity = validate_version_id(project_id, version_id, is_version_entity_retrun=True) template_id = version_entity.template_id project_kind = request.project.kind self.slz = InstanceNamespaceSLZ(data=request.data, context={'project_kind': project_kind}) self.slz.is_valid(raise_exception=True) slz_data = self.slz.data if 'instance_entity' not in slz_data: raise ValidationError(_("请选择要实例化的模板")) instance_entity = slz_data['instance_entity'] # 根据template_id 查询已经被实例化过的 ns exist_instance_id = VersionInstance.objects.filter( template_id=template_id, is_deleted=False).values_list('id', flat=True) filter_ns = InstanceConfig.objects.filter( instance_id__in=exist_instance_id, is_deleted=False, is_bcs_success=True).exclude(ins_state=InsState.NO_INS.value) exist_ns = [] # 查询每类资源已经实例化的ns,求合集,这些已经实例化过的ns不能再被实例化 for cate in instance_entity: cate_data = instance_entity[cate] cate_name_list = [ i.get('name') for i in cate_data if i.get('name') ] cate_ns = filter_ns.filter(category=cate, name__in=cate_name_list) exist_ns.extend(list(cate_ns)) ns_resources = {} for inst_config in exist_ns: ns_id = int(inst_config.namespace) # HPA只通过模板集管理,可以重试实例化(apply操作) if inst_config.category == K8sResourceName.K8sHPA.value: continue if ns_id not in ns_resources: ns_resources[ns_id] = [ inst_config.category, ] else: ns_resources[ns_id].append(inst_config.category) for ns_id, resources in ns_resources.items(): ns_resources[ns_id] = list(set(resources)) return Response({ "code": 0, "message": "OK", "data": { "ns_resources": ns_resources } })
def preview_config(self, request, project_id): project_kind = request.project.kind serializer = PreviewInstanceSLZ(data=request.data, context={'project_kind': project_kind}) serializer.is_valid(raise_exception=True) slz_data = serializer.data # 验证 version_id 是否属于该项目 version_id = slz_data['version_id'] show_version_id = slz_data['show_version_id'] template, version_entity = validate_version_id( project_id, version_id, is_return_all=True, show_version_id=show_version_id ) # 验证用户是否有使用权限 perm = bcs_perm.Templates(request, project_id, template.id, template.name) perm.can_use(raise_exception=True) template_id = version_entity.template_id version = version_entity.version tem_instance_entity = version_entity.get_version_instance_resource_ids # 验证前端传过了的预览资源是否在该版本的资源 req_instance_entity = slz_data.get('instance_entity') or {} instance_entity = validate_instance_entity(req_instance_entity, tem_instance_entity) access_token = self.request.user.token.access_token username = self.request.user.username namespace = slz_data['namespace'] lb_info = slz_data.get('lb_info', {}) # 验证关联lb情况下,lb 是否都已经选中 service_id_list = instance_entity.get('service') or [] v_res, err_list, err_msg = validate_lb_info_by_version_id( access_token, project_id, version_entity, [namespace], lb_info, service_id_list ) if not v_res: return Response({"code": 400, "message": err_msg, "data": err_list}) # 查询当前命名空间的变量信息 variable_dict = slz_data.get('variable_info', {}).get(namespace) or {} params = { "instance_id": "instanceID", "version_id": version_id, "show_version_id": show_version_id, "template_id": template_id, "version": version, "project_id": project_id, "access_token": access_token, "username": username, "lb_info": lb_info, "variable_dict": variable_dict, "is_preview": True, } data = preview_config_json(namespace, instance_entity, **params) return Response({"code": 0, "message": "OK", "data": data})
def post(self, request, project_id): """实例化模板""" self.project_id = project_id version_id = request.data.get('version_id') show_version_id = request.data.get('show_version_id') template, version_entity = validate_version_id( project_id, version_id, is_return_all=True, show_version_id=show_version_id) # 验证用户是否有模板集实例化权限 perm_ctx = TemplatesetPermCtx(username=request.user.username, project_id=project_id, template_id=template.id) TemplatesetPermission().can_instantiate(perm_ctx) self.template_id = version_entity.template_id tem_instance_entity = version_entity.get_version_instance_resource_ids project_kind = request.project.kind self.slz = VersionInstanceCreateOrUpdateSLZ( data=request.data, context={'project_kind': project_kind}) self.slz.is_valid(raise_exception=True) slz_data = self.slz.data # 验证前端传过了的预览资源是否在该版本的资源 req_instance_entity = slz_data.get('instance_entity') or {} self.instance_entity = validate_instance_entity( req_instance_entity, tem_instance_entity) namespaces = slz_data['namespaces'] ns_list = namespaces.split(',') if namespaces else [] access_token = self.request.user.token.access_token username = self.request.user.username # 判断 template 下 前台传过来的 namespace 是否已经实例化过 res, ns_name_list, namespace_dict = validate_ns_by_tempalte_id( self.template_id, ns_list, access_token, project_id, req_instance_entity) if not res: return Response({ "code": 400, "message": _("以下命名空间已经实例化过,不能再实例化\n{}").format("\n".join(ns_name_list)), "data": ns_name_list, }) slz_data['ns_list'] = ns_list slz_data['instance_entity'] = self.instance_entity slz_data['template_id'] = self.template_id slz_data['project_id'] = project_id slz_data['version_id'] = version_id slz_data['show_version_id'] = show_version_id result = handle_all_config(slz_data, access_token, username, project_kind=request.project.kind) instance_entity = slz_data.get("instance_entity") all_tmpl_name_dict = self.get_tmpl_name(instance_entity) # 添加操作记录 temp_name = version_entity.get_template_name() for i in result['success']: TemplatesetAuditor(audit_ctx=AuditContext( project_id=project_id, user=username, resource=temp_name, resource_id=self.template_id, extra=self.instance_entity, description=_("实例化模板集[{}]命名空间[{}]").format( temp_name, i['ns_name']), activity_type=ActivityType.Add, activity_status=ActivityStatus.Succeed, )).log_raw() failed_ns_name_list = [] failed_msg = [] is_show_failed_msg = False # 针对createError的触发后台任务轮训 if result.get('failed'): check_instance_status.delay( request.user.token.access_token, project_id, request.project.get("kind"), all_tmpl_name_dict, result['failed'], ) for i in result['failed']: if i['res_type']: description = _("实例化模板集[{}]命名空间[{}],在实例化{}时失败,错误消息:{}").format( temp_name, i['ns_name'], i['res_type'], i['err_msg']) failed_ns_name_list.append( _("{}(实例化{}时)").format(i['ns_name'], i['res_type'])) else: description = _("实例化模板集[{}]命名空间[{}]失败,错误消息:{}").format( temp_name, i['ns_name'], i['err_msg']) failed_ns_name_list.append(i['ns_name']) if i.get('show_err_msg'): failed_msg.append(i['err_msg']) is_show_failed_msg = True TemplatesetAuditor(audit_ctx=AuditContext( project_id=project_id, user=username, resource=temp_name, resource_id=self.template_id, extra=self.instance_entity, description=description, activity_type=ActivityType.Add, activity_status=ActivityStatus.Failed, )).log_raw() if is_show_failed_msg: msg = '\n'.join(failed_msg) else: msg = _("以下命名空间实例化失败,\n{},请联系集群管理员解决").format( "\n".join(failed_ns_name_list)) if failed_ns_name_list: return Response({ "code": 400, "message": msg, "data": failed_ns_name_list }) return Response({ "code": 0, "message": "OK", "data": { "version_id": version_id, "template_id": self.template_id, }, })
def preview_config(self, request, project_id): project_kind = request.project.kind serializer = PreviewInstanceSLZ(data=request.data, context={'project_kind': project_kind}) serializer.is_valid(raise_exception=True) slz_data = serializer.data # 验证 version_id 是否属于该项目 version_id = slz_data['version_id'] show_version_id = slz_data['show_version_id'] template, version_entity = validate_version_id( project_id, version_id, is_return_all=True, show_version_id=show_version_id) # 验证用户是否有模板集的实例化权限 perm_ctx = TemplatesetPermCtx(username=request.user.username, project_id=project_id, template_id=template.id) TemplatesetPermission().can_instantiate(perm_ctx) template_id = version_entity.template_id version = version_entity.version tem_instance_entity = version_entity.get_version_instance_resource_ids # 验证前端传过了的预览资源是否在该版本的资源 req_instance_entity = slz_data.get('instance_entity') or {} instance_entity = validate_instance_entity(req_instance_entity, tem_instance_entity) access_token = self.request.user.token.access_token username = self.request.user.username namespace_id = slz_data['namespace'] lb_info = slz_data.get('lb_info', {}) resp = paas_cc.get_namespace(access_token, project_id, namespace_id) if resp.get('code') != 0: return Response({ 'code': 400, 'message': f"查询命名空间(namespace_id:{project_id}-{namespace_id})出错:{resp.get('message')}", }) namespace_info = resp['data'] perm_ctx = NamespaceScopedPermCtx( username=username, project_id=project_id, cluster_id=namespace_info['cluster_id'], name=namespace_info['name'], ) NamespaceScopedPermission().can_use(perm_ctx) # 查询当前命名空间的变量信息 variable_dict = slz_data.get('variable_info', {}).get(namespace_id) or {} params = { "instance_id": "instanceID", "version_id": version_id, "show_version_id": show_version_id, "template_id": template_id, "version": version, "project_id": project_id, "access_token": access_token, "username": username, "lb_info": lb_info, "variable_dict": variable_dict, "is_preview": True, } data = preview_config_json(namespace_id, instance_entity, **params) return Response({"code": 0, "message": "OK", "data": data})
def post(self, request, project_id): """实例化模板""" # 参数验证 self.project_id = project_id version_id = request.data.get('version_id') show_version_id = request.data.get('show_version_id') template, version_entity = validate_version_id( project_id, version_id, is_return_all=True, show_version_id=show_version_id ) # 验证用户是否有使用权限 perm = bcs_perm.Templates(request, project_id, template.id, template.name) perm.can_use(raise_exception=True) self.template_id = version_entity.template_id tem_instance_entity = version_entity.get_version_instance_resource_ids project_kind = request.project.kind self.slz = VersionInstanceCreateOrUpdateSLZ(data=request.data, context={'project_kind': project_kind}) self.slz.is_valid(raise_exception=True) slz_data = self.slz.data # 验证前端传过了的预览资源是否在该版本的资源 req_instance_entity = slz_data.get('instance_entity') or {} self.instance_entity = validate_instance_entity(req_instance_entity, tem_instance_entity) namespaces = slz_data['namespaces'] ns_list = namespaces.split(',') if namespaces else [] access_token = self.request.user.token.access_token username = self.request.user.username # 验证关联lb情况下,lb 是否都已经选中 service_id_list = self.instance_entity.get('service') or [] v_res, err_list, err_msg = validate_lb_info_by_version_id( access_token, project_id, version_entity, ns_list, slz_data.get('lb_info', {}), service_id_list ) if not v_res: return Response({"code": 400, "message": err_msg, "data": err_list}) # 判断 template 下 前台传过来的 namespace 是否已经实例化过 res, ns_name_list, namespace_dict = validate_ns_by_tempalte_id( self.template_id, ns_list, access_token, project_id, req_instance_entity ) if not res: return Response( { "code": 400, "message": _("以下命名空间已经实例化过,不能再实例化\n{}").format("\n".join(ns_name_list)), "data": ns_name_list, } ) slz_data['ns_list'] = ns_list slz_data['instance_entity'] = self.instance_entity slz_data['template_id'] = self.template_id slz_data['project_id'] = project_id slz_data['version_id'] = version_id slz_data['show_version_id'] = show_version_id result = handle_all_config(slz_data, access_token, username, project_kind=request.project.kind) instance_entity = slz_data.get("instance_entity") all_tmpl_name_dict = self.get_tmpl_name(instance_entity) # 添加操作记录 temp_name = version_entity.get_template_name() for i in result['success']: client.ContextActivityLogClient( project_id=project_id, user=username, resource_type="template", resource=temp_name, resource_id=self.template_id, extra=json.dumps(self.instance_entity), description=_("实例化模板集[{}]命名空间[{}]").format(temp_name, i['ns_name']), ).log_add(activity_status="succeed") failed_ns_name_list = [] failed_msg = [] is_show_failed_msg = False # 针对createError的触发后台任务轮训 if result.get('failed'): check_instance_status.delay( request.user.token.access_token, project_id, request.project.get("kind"), all_tmpl_name_dict, result['failed'], ) for i in result['failed']: if i['res_type']: description = _("实例化模板集[{}]命名空间[{}],在实例化{}时失败,错误消息:{}").format( temp_name, i['ns_name'], i['res_type'], i['err_msg'] ) failed_ns_name_list.append(_("{}(实例化{}时)").format(i['ns_name'], i['res_type'])) else: description = _("实例化模板集[{}]命名空间[{}]失败,错误消息:{}").format(temp_name, i['ns_name'], i['err_msg']) failed_ns_name_list.append(i['ns_name']) if i.get('show_err_msg'): failed_msg.append(i['err_msg']) is_show_failed_msg = True client.ContextActivityLogClient( project_id=project_id, user=username, resource_type="template", resource=temp_name, resource_id=self.template_id, extra=json.dumps(self.instance_entity), description=description, ).log_add(activity_status="failed") if is_show_failed_msg: msg = '\n'.join(failed_msg) else: msg = _("以下命名空间实例化失败,\n{},请联系集群管理员解决").format("\n".join(failed_ns_name_list)) if failed_ns_name_list: return Response({"code": 400, "message": msg, "data": failed_ns_name_list}) return Response( { "code": 0, "message": "OK", "data": { "version_id": version_id, "template_id": self.template_id, }, } )
def post(self, request, project_id, version_id): version_entity = validate_version_id(project_id, version_id, is_version_entity_retrun=True) project_kind = request.project.kind self.slz = VariableNamespaceSLZ(data=request.data, context={'project_kind': project_kind}) self.slz.is_valid(raise_exception=True) slz_data = self.slz.data if 'instance_entity' not in slz_data: raise ValidationError(_("请选择要实例化的模板")) instance_entity = slz_data['instance_entity'] lb_services = [] key_list = [] for cate in instance_entity: cate_data = instance_entity[cate] cate_id_list = [i.get('id') for i in cate_data if i.get('id')] # 查询这些配置文件的变量名 for _id in cate_id_list: if cate in ['metric']: config = self.get_metric_confg(_id) else: try: resource = MODULE_DICT.get(cate).objects.get(id=_id) except Exception: continue config = resource.config search_list = check_var_by_config(config) key_list.extend(search_list) # mesos Deployment 需要再查询 Application 的配置文件 if cate in ['deployment']: deployment_app = VersionedEntity.get_application_by_deployment_id(version_id, _id) deployment_app_config = deployment_app.config _search_list = check_var_by_config(deployment_app_config) key_list.extend(_search_list) # mesos service 查询需要lb的列表 if project_kind == 2 and cate == 'service': lb_services = version_entity.get_lb_services_by_ids(cate_id_list) key_list = list(set(key_list)) variable_dict = {} if key_list: # 验证变量名是否符合规范,不符合抛出异常,否则后续用 django 模板渲染变量也会抛出异常 var_objects = Variable.objects.filter(Q(project_id=project_id) | Q(project_id=0)) access_token = request.user.token.access_token namespace_res = paas_cc.get_namespace_list(access_token, project_id, limit=ALL_LIMIT) namespace_data = namespace_res.get('data', {}).get('results') or [] namespace_dict = {str(i['id']): i['cluster_id'] for i in namespace_data} ns_list = slz_data['namespaces'].split(',') if slz_data['namespaces'] else [] for ns_id in ns_list: _v_list = [] for _key in key_list: key_obj = var_objects.filter(key=_key) if key_obj.exists(): _obj = key_obj.first() # 只显示自定义变量 if _obj.category == 'custom': cluster_id = namespace_dict.get(ns_id, 0) _v_list.append( {"key": _obj.key, "name": _obj.name, "value": _obj.get_show_value(cluster_id, ns_id)} ) else: _v_list.append({"key": _key, "name": _key, "value": ""}) variable_dict[ns_id] = _v_list return Response( {"code": 0, "message": "OK", "data": {"lb_services": lb_services, "variable_dict": variable_dict}} )