def _get_namespace_map(self, project_id): """获取命名空间dict """ resp = paas_cc.get_namespace_list(self.request.user.token.access_token, project_id, limit=ALL_LIMIT) namespace_list = resp.get("data", {}).get("results") or [] namespace_map = {(i["cluster_id"], i["name"]): i["id"] for i in namespace_list} return namespace_map
def get_ns_list_by_user_perm(self, request, project_id): """获取用户所有有使用权限的命名空间""" access_token = request.user.token.access_token # 获取全部namespace,前台分页 result = paas_cc.get_namespace_list(access_token, project_id, with_lb=0, limit=LIMIT_FOR_ALL_DATA) if result.get('code') != 0: raise error_codes.APIError.f(result.get('message', '')) ns_list = result['data']['results'] or [] if not ns_list: return [] # 补充cluster_name字段 cluster_ids = [i['cluster_id'] for i in ns_list] cluster_list = paas_cc.get_cluster_list(access_token, project_id, cluster_ids).get('data') or [] cluster_dict = {i['cluster_id']: i for i in cluster_list} # 命名空间列表补充集群信息,过来权限时需要 for i in ns_list: i['namespace_id'] = i['id'] if i['cluster_id'] in cluster_dict: i['cluster_name'] = cluster_dict[i['cluster_id']]['name'] i['environment'] = cluster_dict[i['cluster_id']]['environment'] else: i['cluster_name'] = i['cluster_id'] i['environment'] = None perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES) # 只过滤有编辑权限 filter_parms = {'is_filter': True, 'filter_type': 'edit'} ns_list = perm.hook_base_perms(ns_list, **filter_parms) return ns_list
def get_namespaces(self, request, project_id): resp = paas_cc.get_namespace_list(request.user.token.access_token, project_id, desire_all_data=True) if resp.get("code") != ErrorCode.NoError: raise error_codes.APIError.f(resp.get("message")) return resp.get("data", {}).get("results") or []
def get_project_namespaces(access_token, project_id): """get all namespace from project""" ns_resp = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=True) if ns_resp.get('code') != ErrorCode.NoError: raise error_codes.APIError(ns_resp.get('message')) data = ns_resp.get('data') or {} return data.get('results') or []
def list(self, request, project_id): """获取所有HPA数据 """ access_token = request.user.token.access_token cluster_dicts = self.get_project_cluster_info(request, project_id) cluster_data = cluster_dicts.get('results', {}) or {} k8s_hpa_list = [] 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 = {i['name']: i['id'] for i in namespace_data} for cluster_info in cluster_data: cluster_id = cluster_info['cluster_id'] cluster_env = cluster_info.get('environment') cluster_name = cluster_info['name'] hpa_list = utils.get_cluster_hpa_list(request, project_id, cluster_id, cluster_env, cluster_name) k8s_hpa_list.extend(hpa_list) for p in k8s_hpa_list: p['namespace_id'] = namespace_dict.get(p['namespace']) perm = bcs_perm.Namespace(request, project_id, bcs_perm.NO_RES) k8s_hpa_list = perm.hook_perms(k8s_hpa_list, ns_id_flag='namespace_id') return Response(k8s_hpa_list)
def check_ns_with_project(self, request, project_id, ns_id, cluster_type, cluster_env_map): """判断命名空间属于项目 """ resp = paas_cc.get_namespace_list(request.user.token.access_token, project_id, desire_all_data=True) if resp.get("code") != ErrorCode.NoError: raise error_codes.APIError.f(resp.get("message")) data = resp.get("data") or {} if not data.get("results"): raise error_codes.APIError.f("查询命名空间为空") ns_list = data["results"] cluster_id = None ns_name = None for info in ns_list: if str(info["id"]) != str(ns_id): continue else: cluster_id = info["cluster_id"] ns_name = info["name"] if str( cluster_env_map.get( info["cluster_id"], {}).get("cluster_env")) != str(cluster_type): raise error_codes.CheckFailed.f("命名空间不属于当前项目或集群") return cluster_id, ns_name
def filter_namespaces(self, filter_use_perm): result = paas_cc.get_namespace_list(self.access_token, self.project_id, desire_all_data=True) results = result["data"]["results"] if not results: return [] # 补充cluster_name字段 cluster_ids = [i['cluster_id'] for i in results] cluster_list = paas_cc.get_cluster_list( self.access_token, self.project_id, cluster_ids).get('data') or [] # cluster_list = bcs_perm.Cluster.hook_perms(request, project_id, cluster_list) cluster_dict = {i['cluster_id']: i for i in cluster_list} filter_ns_list = [] for i in results: # 过滤掉k8s系统和bcs平台使用的命名空间 if i["name"] in K8S_PLAT_NAMESPACE: continue # ns_vars = NameSpaceVariable.get_ns_vars(i['id'], project_id) i['ns_vars'] = [] if i['cluster_id'] in cluster_dict: i['cluster_name'] = cluster_dict[i['cluster_id']]['name'] i['environment'] = cluster_dict[i['cluster_id']]['environment'] else: i['cluster_name'] = i['cluster_id'] i['environment'] = None filter_ns_list.append(i) return filter_ns_list
def get_namespace_id_name(self, access_token, project_id): """获取命名空间ID和名称对应关系 """ namespace = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=True) namespace = namespace.get('data', {}).get('results') or [] namespace = {i['id']: i['name'] for i in namespace} return namespace
def get_detail(self, request, project_id, lb_id): access_token = request.user.token.access_token data = self.get_project_lb(project_id, lb_id=lb_id) namespace = paas_cc.get_namespace_list( access_token, project_id, limit=constants.ALL_LIMIT) namespace = namespace.get('data', {}).get('results') or [] namespace = {i['id']: i['name'] for i in namespace} merge_data = self.merge_data(data, namespace) # 获取集群名称 cluster_id = merge_data[0].get('cluster_id') cls_res = paas_cc.get_cluster(access_token, project_id, cluster_id) cluster_data = cls_res.get('data', {}) cluster_name = cluster_data.get('name') or cluster_id cluster_dict = {cluster_id: cluster_name} cluster_envs = {cluster_id: cluster_data.get('environment', '')} # 按前端需要二次处理数据 data = self.handle_lb_dtail_data( request, access_token, project_id, merge_data, cluster_dict, namespace, cluster_envs) return Response({ "code": 0, "results": data[0] })
def check_namespace_use_perm(self, request, project_id, namespace_list): """检查是否有命名空间的使用权限""" access_token = request.user.token.access_token # 根据 namespace 查询 ns_id namespace_res = paas_cc.get_namespace_list(access_token, project_id, limit=LIMIT_FOR_ALL_DATA) namespace_data = namespace_res.get('data', {}).get('results') or [] namespace_dict = {i['name']: i['id'] for i in namespace_data} namespace_cluster_dict = { i['name']: i['cluster_id'] for i in namespace_data } for namespace in namespace_list: # 检查是否有命名空间的使用权限 perm_ctx = NamespaceScopedPermCtx( username=request.user.username, project_id=project_id, cluster_id=namespace_cluster_dict.get(namespace), name=namespace, ) self.iam_perm.can_use(perm_ctx) return namespace_dict
def get_queryset(self): result = paas_cc.get_namespace_list(self.access_token, self.project_id, desire_all_data=True) results = result["data"]["results"] if not results: return [] # 补充cluster_name字段 cluster_ids = [i['cluster_id'] for i in results] cluster_list = paas_cc.get_cluster_list( self.access_token, self.project_id, cluster_ids).get('data') or [] # cluster_list = bcs_perm.Cluster.hook_perms(request, project_id, cluster_list) cluster_dict = {i['cluster_id']: i for i in cluster_list} for i in results: # ns_vars = NameSpaceVariable.get_ns_vars(i['id'], project_id) i['ns_vars'] = [] if i['cluster_id'] in cluster_dict: i['cluster_name'] = cluster_dict[i['cluster_id']]['name'] i['environment'] = cluster_dict[i['cluster_id']]['environment'] else: i['cluster_name'] = i['cluster_id'] i['environment'] = None perm = bcs_perm.Namespace(self.request, self.project_id, bcs_perm.NO_RES) results = perm.hook_perms(results, True) return results
def get_ns_info(self, request, project_id, ns_id_list): """获取ns信息""" resp = paas_cc.get_namespace_list(request.user.token.access_token, project_id, limit=LIMIT_FOR_ALL_DATA) if resp.get("code") != ErrorCode.NoError: raise error_codes.APIError.f(resp.get("message")) results = (resp.get("data") or {}).get("results") or [] return results
def check_instance_status(access_token, project_id, project_kind, tmpl_name_dict, ns_info): # 通过命名空间获取集群信息 all_ns = get_namespace_list(access_token, project_id, desire_all_data=True) all_ns_list = all_ns.get("data", {}).get("results") or [] # 进行匹配命名空间和集群及模板 ns_id_info_map = {info["ns_id"]: info for info in ns_info} ns_cluster = {} ns_name_id = {} for info in all_ns_list: if str(info["id"]) in ns_id_info_map: ns_name_id[info["name"]] = info["id"] if info["cluster_id"] not in ns_cluster: ns_cluster[info["cluster_id"]] = [info["name"]] else: ns_cluster[info["cluster_id"]].append(info["name"]) end_time = datetime.now() + POLLING_TIMEOUT # 查询状态 while datetime.now() < end_time: time.sleep(POLLING_INTERVAL_SECONDS) for cluster_id, ns in ns_cluster.items(): ns_name_str = ",".join(set(ns)) for category, tmpl in tmpl_name_dict.items(): tmpl_name_str = ",".join(set(tmpl)) results = get_app_status( access_token, project_id, project_kind, cluster_id, tmpl_name_str, ns_name_str, category ) # 更新db for key, val in results.items(): if val: ns_id = ns_name_id.get(key[1]) update_data_record(key[0], ns_id, key[2])
def validate_lb_info_by_version_id(access_token, project_id, version_entity, ns_list, lb_info, service_id_list): """检查预览/实例化 service 时,关联lb情况下,lb 是否都已经选中 """ # 1. 判断是否需要关联lb lb_services = version_entity.get_lb_services_by_ids(service_id_list) if not lb_services: return True, [], '' service_name_list = [i['name'] for i in lb_services] err_list = [] # 2. 依次判断每个 ns 下每个 关联的 service 下是否都有 可用的lb for ns_id in ns_list: # 2.1 先判断该命名空间是否有lb信息 if ns_id not in lb_info.keys(): for _s in service_name_list: err_list.append({'ns_id': ns_id, 'service': _s}) continue # 判断每一个 service 是否都有值 lb_data = lb_info[ns_id] lb_data_skey = lb_data.keys() for _s in service_name_list: if _s not in lb_data_skey: err_list.append({'ns_id': ns_id, 'service': _s}) if not err_list: return True, [], '' namespace = paas_cc.get_namespace_list( access_token, project_id, limit=ALL_LIMIT) namespace = namespace.get('data', {}).get('results') or [] namespace_dict = {str(i['id']): i['name'] for i in namespace} err_list = ["namespace[%s]:%s" % (namespace_dict.get(_e['ns_id']), _e['service']) for _e in err_list] err_msg = _('请选择 service 关联的 LoadBalance: {}').format(' '.join(err_list)) return False, err_list, err_msg
def get_cc_namespaces(access_token, project_id): resp = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=True) if resp.get("code") != ErrorCode.NoError: raise error_codes.APIError( f"get namespace error, {resp.get('message')}") return getitems(resp, 'data.results') or []
def get_project_namespaces(access_token, project_id): resp = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=1) if resp.get('code') != ErrorCode.NoError: raise error_codes.APIError( _("获取项目下命名空间信息异常,{}").format(resp.get('message'))) return resp['data'].get('results') or []
def get_namespaces(access_token, project_id): resp = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=True) if resp.get('code') != ErrorCode.NoError: raise error_codes.APIError( f"get namespace error, {resp.get('message')}") return resp.get('data', {}).get('results', [])
def get_namespace_name_id(self, request, project_id): resp = paas_cc.get_namespace_list(request.user.token.access_token, project_id, limit=10000, offset=0) if resp.get('code') != ErrorCode.NoError: raise error_codes.CheckFailed.f(resp.get('message')) data = resp.get('data', {}).get('results', []) return {info.get('name'): info.get('id') for info in data if info}
def validate_ns_by_tempalte_id(template_id, ns_list, access_token, project_id, instance_entity={}): """实例化,参数 ns_list 不能与 db 中已经实例化过的 ns 重复 """ namespace = paas_cc.get_namespace_list(access_token, project_id, limit=ALL_LIMIT) namespace = namespace.get('data', {}).get('results') or [] namespace_dict = {str(i['id']): i['name'] for i in namespace} # 查看模板下已经实例化过的 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).values_list('namespace', flat=True) exist_ns = [] # 查询每类资源已经实例化的ns,求合集,这些已经实例化过的ns不能再被实例化 for cate in instance_entity: # HPA 编辑以模板集为准, 可以重复实例化 if cate in [K8sResourceName.K8sHPA.value, MesosResourceName.hpa.value]: continue 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).values_list('namespace', flat=True) exist_ns.extend(list(cate_ns)) new_ns_list = [str(_i) for _i in ns_list] # 列表的交集 intersection_list = list(set(exist_ns).intersection(set(new_ns_list))) # hpa白名单控制 cluster_id_list = list( set([ i['cluster_id'] for i in namespace if str(i['id']) in new_ns_list ])) if K8sResourceName.K8sHPA.value in instance_entity or MesosResourceName.hpa.value in instance_entity: if not enabled_hpa_feature(cluster_id_list): raise error_codes.APIError( _("当前实例化包含HPA资源,{}").format(settings.GRAYSCALE_FEATURE_MSG)) if not intersection_list: return True, [], namespace_dict ns_name_list = [] for _n_id in intersection_list: _ns_name = namespace_dict.get(_n_id, _n_id) ns_name_list.append(_ns_name) return False, ns_name_list, namespace_dict
def get_all_namespace(self, access_token, project_id): resp = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=True) if resp.get("code") != 0: raise error_codes.APIError.f(resp.get("message")) return { item["id"]: item for item in resp.get("data", {}).get("results") or [] }
def get_instance(self, request, project_id, metric_id): """查询Metric实例化的详细信息 """ ref = MetricModel.objects.filter(project_id=project_id, pk=metric_id).first() if not ref: raise error_codes.ResNotFoundError(_('metric不存在')) metric_name = ref.name # 查询项目下的所有集群id列表 access_token = request.user.token.access_token cluster_data = paas_cc.get_all_clusters(access_token, project_id).get('data') or {} cluster_list = cluster_data.get('results') or [] cluster_dict = {} for _n in cluster_list: _env = _n['environment'] if _env in cluster_dict: cluster_dict[_env].append(_n['cluster_id']) else: cluster_dict[_env] = [_n['cluster_id']] # 查询项目下的命名空间列表 access_token = request.user.token.access_token result = paas_cc.get_namespace_list(access_token, project_id, with_lb=0, limit=ALL_LIMIT) ns_list = result.get('data', {}).get('results') or [] ns_dict = {} for _n in ns_list: ns_dict[_n['name']] = _n['id'] if request.project.kind == ProjectKind.MESOS.value: # mesos category_list = ['application', 'deployment'] else: category_list = POD_RES_LIST instance_info = InstanceConfig.objects.filter( is_deleted=False, category__in=category_list).exclude( ins_state=InsState.NO_INS.value) data = [] # 根据集群的环境不同调用不同环境的storageAPI for env, cluster_id_list in cluster_dict.items(): metric_instance_list = get_metric_instances( access_token, project_id, metric_name, env, cluster_id_list, ns_dict, instance_info) data.extend(metric_instance_list) return Response(data)
def handle(self, *args, **options): """用到了 paas_cc 的两个API,必须要带用户登录态的accesstoken才可以 """ print(options) if options.get('access_token'): access_token = options['access_token'] else: return False # 获取所有的项目信息 pro_res = paas_cc.get_projects(access_token) pro_data = pro_res.get('data') or [] init_ns = 0 has_init = 0 error_list = [] for _d in pro_data: # 只需要处理 mesos 项目 _kind = _d.get('kind') if _kind != 2: continue project_id = _d.get('project_id') project_code = _d.get('english_name') self.stdout.write(self.style.SUCCESS("init project:%s" % project_code)) # 查询项目下的所有命名空间 ns_result = paas_cc.get_namespace_list(access_token, project_id, limit=constants.ALL_LIMIT) ns_res = ns_result.get('data') or {} ns_data = ns_res.get('results') or [] for _ns in ns_data: has_image_secret = _ns.get('has_image_secret') # 已经初始化过的则不再初始化 if has_image_secret: has_init = has_init + 1 continue cluster_id = _ns.get('cluster_id') ns_name = _ns.get('name') namespace_id = _ns.get('id') ns_base = NamespaceBase() try: ns_base.init_mesos_ns_by_bcs(access_token, project_id, project_code, cluster_id, ns_name) except Exception: error_list.append('%s[%s]' % (ns_name, namespace_id)) self.stdout.write(self.style.WARNING("error init image secret in ns: %s[%s]" % ( ns_name, namespace_id))) else: # 更新 paas_cc.update_namespace(access_token, project_id, namespace_id, has_image_secret=True) self.stdout.write(self.style.SUCCESS("init image secret in ns: %s[%s]" % (ns_name, namespace_id))) init_ns = init_ns + 1 self.stdout.write(self.style.WARNING("error_list:%s" % ','.join(error_list))) self.stdout.write(self.style.SUCCESS("init end, init_ns:%s, has_init:%s, error:%s" % (init_ns, has_init, len(error_list))))
def _get_namespace_map(self, project_id: str) -> Dict: """ 获取命名空间配置信息 :param project_id: 项目 ID :return: {(cluster_id, name): id} """ resp = paas_cc.get_namespace_list(self.request.user.token.access_token, project_id, limit=ALL_LIMIT) namespaces = getitems(resp, 'data.results', []) return {(i['cluster_id'], i['name']): i['id'] for i in namespaces}
def get_namespaces(self, request, project_id): """获取namespace """ resp = paas_cc.get_namespace_list( request.user.token.access_token, project_id, limit=10000, offset=0 ) if resp.get("code") != ErrorCode.NoError: return False, APIResponse({ "code": resp.get("code", DEFAULT_ERROR_CODE), "message": resp.get("message") }) return True, resp["data"]
def get_namespace_data(self, access_token, project_id, mult_return=False): all_info = get_namespace_list(access_token, project_id, desire_all_data=True) if all_info.get("code") != ErrorCode.NoError: raise error_codes.APIError.f(all_info.get("message"), replace=True) # 处理命名空间名称和ID data = all_info.get("data") or {} results = data.get("results") or [] if not results: raise error_codes.APIError.f("获取命名空间信息为空", replace=True) if mult_return: return results, all_info return results
def check_namespace_use_perm(self, request, project_id, namespace_list): """检查是否有命名空间的使用权限 """ access_token = request.user.token.access_token # 根据 namespace 查询 ns_id namespace_res = paas_cc.get_namespace_list( access_token, project_id, limit=constants.ALL_LIMIT) namespace_data = namespace_res.get('data', {}).get('results') or [] namespace_dict = {i['name']: i['id'] for i in namespace_data} for namespace in namespace_list: namespace_id = namespace_dict.get(namespace) # 检查是否有命名空间的使用权限 perm = bcs_perm.Namespace(request, project_id, namespace_id) perm.can_use(raise_exception=True) return namespace_dict
def validate_ns_by_tempalte_id(template_id, ns_list, access_token, project_id, instance_entity={}): """实例化,参数 ns_list 不能与 db 中已经实例化过的 ns 重复 """ namespace = paas_cc.get_namespace_list(access_token, project_id, limit=ALL_LIMIT) namespace = namespace.get('data', {}).get('results') or [] namespace_dict = {str(i['id']): i['name'] for i in namespace} # 查看模板下已经实例化过的 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).values_list('namespace', flat=True) 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).values_list('namespace', flat=True) exist_ns.extend(list(cate_ns)) new_ns_list = [str(_i) for _i in ns_list] # 列表的交集 intersection_list = list(set(exist_ns).intersection(set(new_ns_list))) if not intersection_list: return True, [], namespace_dict ns_name_list = [] for _n_id in intersection_list: _ns_name = namespace_dict.get(_n_id, _n_id) ns_name_list.append(_ns_name) return False, ns_name_list, namespace_dict
def validate_update_ns_by_tempalte_id(template_id, ns_list, access_token, project_id): """更新,参数 ns_list 必须全部为 db 中已经实例化过的 ns""" namespace = paas_cc.get_namespace_list(access_token, project_id, limit=ALL_LIMIT) namespace = namespace.get('data', {}).get('results') or [] namespace_dict = {str(i['id']): i['name'] for i in namespace} # 查看模板下已经实例化过的 ns exist_ns = VersionInstance.objects.filter(template_id=template_id).values_list('ns_id', flat=True) new_ns_list = [int(_i) for _i in ns_list] wrong_list = [_n for _n in new_ns_list if _n not in exist_ns] if not wrong_list: return True, [], namespace_dict ns_name_list = [] for _n_id in wrong_list: _ns_name = namespace_dict.get(_n_id, _n_id) ns_name_list.append(_ns_name) return False, ns_name_list, namespace_dict
def validate_name(self, name): """名字不能重复 - mesos 名称全局唯一 - k8s 同一集群下,名称唯一 """ # k8s 不能创建系统的命名空间 project_kind = self.context['request'].project.kind if project_kind == K8S_PROJECT_KIND: if name in K8S_SYS_NAMESPACE: raise ValidationError(u"不允许创建系统命名空间[%s]" % ','.join(K8S_SYS_NAMESPACE)) access_token = self.context['request'].user.token.access_token project_id = self.context['project_id'] ns_id = self.context.get('ns_id') result = paas_cc.get_namespace_list(access_token, project_id, limit=constants.ALL_LIMIT) if result.get('code') != 0: raise ValidationError("校验名称失败, %s" % result) if project_kind == K8S_PROJECT_KIND: results = { str(i['id']): (i['cluster_id'], i['name']) for i in result['data']['results'] or [] } cluster_id = self.initial_data['cluster_id'] ns_name = results.get(ns_id) if (cluster_id, name) in results.values() and (cluster_id, name) != ns_name: raise ValidationError("同一集群,命名空间名称不能重复") elif project_kind == MESOS_PROJECT_KIND: results = { str(i['id']): i['name'] for i in result['data']['results'] or [] } ns_name = results.get(ns_id) if name in results.values() and ns_name != name: raise ValidationError("命名空间名称不能重复") else: raise ValidationError("项目编排类型不正确") return name
def get_cluster_namespace_map(access_token, project_id): """获取项目下命名空间 因为项目确定了容器编排类型,并且为减少多次请求的耗时, 直接查询项目下的命名空间信息 """ # return data format: {'cluster_id': {'ns_name': 'ns_id'}} resp = paas_cc.get_namespace_list(access_token, project_id, desire_all_data=1) if resp.get('code') != ErrorCode.NoError: raise error_codes.APIError( f'get project namespace error, {resp.get("message")}') cluster_namespace_map = {} data = resp.get('data') or {} results = data.get('results') or [] for info in results: cluster_id = info['cluster_id'] if cluster_id in cluster_namespace_map: cluster_namespace_map[cluster_id][info['name']] = info['id'] else: cluster_namespace_map[cluster_id] = {info['name']: info['id']} return cluster_namespace_map