def post(self, request, project_id, clb_id): # 获取配置 record = CloudLoadBlancer.objects.retrieve_record(clb_id) # 校验使用集群权限 clb_utils.can_use_cluster(request, project_id, record['cluster_id']) # 获取 repo 地址 repo_domain = paas_cc.get_jfrog_domain(request.user.token.access_token, project_id, record['cluster_id']) if not repo_domain: repo_domain = settings.DEFAUT_MESOS_LB_JFROG_DOMAIN record['repo_domain'] = repo_domain mesos_json = json.loads(render_to_string('mesos.json', record)) with client.ContextActivityLogClient( project_id=project_id, user=request.user.username, resource_type='lb', resource=record['resource_name'], description=_("集群:{}, 创建clb关联deployment:{}").format( record['cluster_id'], record['resource_name']), ).log_add(): clb_utils.create_mesos_deployment(request.user.token.access_token, project_id, record['cluster_id'], record['namespace'], mesos_json) # 更改状态 self.update_clb_status(clb_id, clb_constants.CLB_CREATED_STATUS) return response.Response()
def retrieve(self, request, project_id, *args, **kwargs): cluster_id = request.query_params.get("cluster_id") check_cluster_perm(user=request.user, project_id=project_id, cluster_id=cluster_id, request=request) # 获取镜像地址 jfrog_domain = paas_cc.get_jfrog_domain(access_token=self.access_token, project_id=self.project_id, cluster_id=cluster_id) cluster_info = paas_cc.get_cluster(request.user.token.access_token, project_id, cluster_id)["data"] context = dict(cluster_id=cluster_id, cluster_name=cluster_info["name"], jfrog_domain=jfrog_domain, expr="{{ .Values.__BCS__.SYS_JFROG_DOMAIN }}", link=settings.HELM_DOC_TRICKS) note = _('''集群: {cluster}({cluster_id})的容器仓库域名为:{dept_domain}, 可在Chart直接引用 {expr} 更加方便, [详细说明]({link})''').format( cluster=context['cluster_name'], cluster_id=context['cluster_id'], dept_domain=context['jfrog_domain'], expr=context['expr'], link=context['link']) context["note"] = note return Response(data=context)
def retrieve(self, request, project_id, *args, **kwargs): cluster_id = request.query_params.get("cluster_id") check_cluster_perm(user=request.user, project_id=project_id, cluster_id=cluster_id, request=request) # 获取镜像地址 jfrog_domain = paas_cc.get_jfrog_domain(access_token=self.access_token, project_id=self.project_id, cluster_id=cluster_id) cluster_info = paas_cc.get_cluster(request.user.token.access_token, project_id, cluster_id)["data"] context = dict(cluster_id=cluster_id, cluster_name=cluster_info["name"], jfrog_domain=jfrog_domain, expr="{{ .Values.__BCS__.SYS_JFROG_DOMAIN }}", link=settings.HELM_DOC_TRICKS) note = '{pre_msg}: {cluster}({cluster_id}){dept_key}:{dept_domain},{chart} {expr} {suf_msg} {link}'.format( pre_msg=_("集群"), cluster=context['cluster_name'], cluster_id=context['cluster_id'], dept_key=_("的容器仓库域名为"), dept_domain=context['jfrog_domain'], chart=_("可在Chart直接引用"), expr=repr(context['expr']), suf_msg=_("更加方便, [详细说明]"), link=context['link']) context["note"] = note return Response(data=context)
def create_imagepullsecret(access_token, project_id, project_code, cluster_id, namespace): # get dept domain dept_domain = paas_cc.get_jfrog_domain(access_token, project_id, cluster_id) # 判断是否为研发仓库,正式环境分为:研发仓库、生产仓库,这2个仓库的账号要分开申请 is_bk_dept = True if dept_domain.startswith(settings.BK_JFROG_ACCOUNT_DOMAIN) else False dept_account = get_jfrog_account(access_token, project_code, project_id, is_bk_dept) # get user or pwd by dept account user = dept_account.get('user', '') pwd = dept_account.get('password', '') # compose config secret_config = { "kind": "secret", "metadata": { "name": MESOS_IMAGE_SECRET, "namespace": namespace }, "datas": { "user": { "content": base64.b64encode(user.encode(encoding="utf-8")).decode() }, "pwd": { "content": base64.b64encode(pwd.encode(encoding="utf-8")).decode() } }, "apiVersion": "v4" } client = MesosClient(access_token, project_id, cluster_id, env=None) resp = client.create_secret(namespace, secret_config) if (resp.get('code') != ErrorCode.NoError) and ('already exists' not in resp.get('message', '')): raise error_codes.APIError(f'create secret error, result.get("message")')
def render_helm_values(access_token, project_id, cluster_id, protocol_type, replica_count, namespace): """渲染helm values配置文件""" # check protocol exist http_enabled = "false" https_enabled = "false" http_port = DEFAULT_HTTP_PORT https_port = DEFAULT_HTTPS_PORT protocol_type_list = re.findall(r"[^,; ]+", protocol_type) for info in protocol_type_list: protocol_port = info.split(":") if "http" in protocol_port: http_enabled = "true" http_port = protocol_port[-1] if len(protocol_port) == 2 and protocol_port[-1] else DEFAULT_HTTP_PORT if "https" in protocol_port: https_enabled = "true" https_port = protocol_port[-1] if len(protocol_port) == 2 and protocol_port[-1] else DEFAULT_HTTPS_PORT jfrog_domain = paas_cc.get_jfrog_domain(access_token=access_token, project_id=project_id, cluster_id=cluster_id) # render template = K8S_NGINX_INGRESS_CONTROLLER_CHART_VALUES template = template.replace("__REPO_ADDR__", jfrog_domain) template = template.replace("__CONTROLLER_IMAGE_PATH__", CONTROLLER_IMAGE_PATH) # TODO: 先调整为固定版本,后续允许用户在前端选择相应的版本 template = template.replace("__TAG__", "0.35.0") template = template.replace("__CONTROLLER_REPLICA_COUNT__", str(replica_count)) template = template.replace("__BACKEND_IMAGE_PATH__", BACKEND_IMAGE_PATH) template = template.replace("__HTTP_ENABLED__", http_enabled) template = template.replace("__HTTP_PORT__", http_port) template = template.replace("__HTTPS_ENABLED__", https_enabled) template = template.replace("__HTTPS_PORT__", https_port) template = template.replace("__NAMESPACE__", namespace) return template
def init_mesos_ns_by_bcs(self, access_token, project_id, project_code, cluster_id, ns_name): """新建包含仓库账号信息的sercret配置文件并下发""" # 获取镜像仓库地址 jfrog_domain = paas_cc.get_jfrog_domain(access_token, project_id, cluster_id) # 按项目申请仓库的账号信息 # 判断是否为研发仓库,正式环境分为:研发仓库、生产仓库,这2个仓库的账号要分开申请 if jfrog_domain.startswith(settings.BK_JFROG_ACCOUNT_DOMAIN): is_bk_jfrog = True else: is_bk_jfrog = False jfrog_account = get_jfrog_account(access_token, project_code, project_id, is_bk_jfrog) _user = jfrog_account.get('user', '') _pwd = jfrog_account.get('password', '') jfrog_config = { "kind": "secret", "metadata": {"name": MESOS_IMAGE_SECRET, "namespace": ns_name}, "datas": { "user": {"content": base64.b64encode(_user.encode(encoding="utf-8")).decode()}, "pwd": {"content": base64.b64encode(_pwd.encode(encoding="utf-8")).decode()}, }, "apiVersion": "v4", } # 下发secret配置文件 client = MesosClient(access_token, project_id, cluster_id, env=None) result = client.create_secret(ns_name, jfrog_config) if result.get('code') != 0: client.delete_secret(ns_name, MESOS_IMAGE_SECRET) raise error_codes.ComponentError.f(_("创建registry secret失败,{}").format(result.get('message')))
def get_image_url(image_url, use_custom_image_url, access_token, project_id, cluster_id): if use_custom_image_url: return image_url # 查询仓库地址 repo_domain = paas_cc.get_jfrog_domain(access_token, project_id, cluster_id) if not repo_domain: repo_domain = inst_constants.DEFAULT_LB_REPO_DOMAIN if image_url: return f"{repo_domain}{image_url}" return f"{repo_domain}{inst_constants.DEFAULT_MESOS_LB_IMAGE_PATH}"
def get_ns_variable(access_token, project_id, namespace_id): """获取命名空间相关的变量信息""" context = {} # 获取命名空间的信息 resp = paas_cc.get_namespace(access_token, project_id, namespace_id) if resp.get('code') != 0: raise ValidationError('{}(namespace_id:{}):{}'.format(_("查询命名空间的信息出错"), namespace_id, resp.get('message'))) data = resp.get('data') cluster_id = data.get('cluster_id') context['SYS_CLUSTER_ID'] = cluster_id context['SYS_NAMESPACE'] = data.get('name') has_image_secret = data.get('has_image_secret') # 获取镜像地址 context['SYS_JFROG_DOMAIN'] = paas_cc.get_jfrog_domain(access_token, project_id, context['SYS_CLUSTER_ID']) context['SYS_IMAGE_REGISTRY_LIST'] = paas_cc.get_image_registry_list(access_token, cluster_id) bcs_context = get_bcs_context(access_token, project_id) context.update(bcs_context) # k8s 集群获取集群版本信息 cluster_version = get_cluster_version(access_token, project_id, cluster_id) return has_image_secret, cluster_version, context
def collect_system_variable(access_token, project_id, namespace_id): sys_variables = {} # 获取标准日志采集的dataid data_info = get_data_id_by_project_id(project_id) sys_variables['SYS_STANDARD_DATA_ID'] = data_info.get('standard_data_id') sys_variables['SYS_NON_STANDARD_DATA_ID'] = data_info.get('non_standard_data_id') resp = paas_cc.get_project(access_token, project_id) if resp.get('code') != 0: logger.error( "查询project的信息出错(project_id:{project_id}):{message}".format( project_id=project_id, message=resp.get('message') ) ) project_info = resp["data"] sys_variables["SYS_CC_APP_ID"] = project_info["cc_app_id"] sys_variables['SYS_PROJECT_KIND'] = project_info["kind"] sys_variables['SYS_PROJECT_CODE'] = project_info["english_name"] resp = paas_cc.get_namespace(access_token, project_id, namespace_id) if resp.get('code') != 0: logger.error( "查询命名空间的信息出错(namespace_id:{project_id}-{namespace_id}):{message}".format( namespace_id=namespace_id, project_id=project_id, message=resp.get('message') ) ) namespace_info = resp["data"] sys_variables["SYS_NAMESPACE"] = namespace_info["name"] sys_variables["SYS_CLUSTER_ID"] = namespace_info["cluster_id"] sys_variables["SYS_PROJECT_ID"] = namespace_info["project_id"] # SYS_JFROG_DOMAIN # SYS_NON_STANDARD_DATA_ID # 获取镜像地址 jfrog_domain = paas_cc.get_jfrog_domain(access_token, project_id, sys_variables['SYS_CLUSTER_ID']) sys_variables['SYS_JFROG_DOMAIN'] = jfrog_domain return sys_variables
def get_ns_variable(self): """获取命名空间相关的变量信息""" # 获取命名空间的信息 resp = paas_cc.get_namespace(self.access_token, self.project_id, self.namespace_id) if resp.get("code") != 0: raise ValidationError("{}(namespace_id:{}):{}".format( _("查询命名空间的信息出错"), self.namespace_id, resp.get("message"))) data = resp.get("data") self.context["SYS_CLUSTER_ID"] = data.get("cluster_id") self.context["SYS_NAMESPACE"] = data.get("name") self.has_image_secret = data.get("has_image_secret") # 获取镜像地址 self.context["SYS_JFROG_DOMAIN"] = paas_cc.get_jfrog_domain( self.access_token, self.project_id, self.context["SYS_CLUSTER_ID"]) self.context[ "SYS_IMAGE_REGISTRY_LIST"] = paas_cc.get_image_registry_list( self.access_token, self.context["SYS_CLUSTER_ID"]) bcs_context = get_bcs_context(self.access_token, self.project_id) self.context.update(bcs_context)
def get_ns_variable(access_token, project_id, namespace_id): """获取命名空间相关的变量信息 """ context = {} # 获取命名空间的信息 resp = paas_cc.get_namespace(access_token, project_id, namespace_id) if resp.get('code') != 0: raise ValidationError(u"查询命名空间的信息出错(namespace_id:%s):%s" % (namespace_id, resp.get('message'))) data = resp.get('data') cluster_id = data.get('cluster_id') context['SYS_CLUSTER_ID'] = cluster_id context['SYS_NAMESPACE'] = data.get('name') has_image_secret = data.get('has_image_secret') # 获取镜像地址 jfrog_domain = paas_cc.get_jfrog_domain(access_token, project_id, context['SYS_CLUSTER_ID']) context['SYS_JFROG_DOMAIN'] = jfrog_domain bcs_context = get_bcs_context(access_token, project_id) context.update(bcs_context) # k8s 集群获取集群版本信息 cluster_version = get_cluster_version(access_token, project_id, cluster_id) return has_image_secret, cluster_version, context
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 get_cc_repo_domain(access_token, project_id, cluster_id): return paas_cc.get_jfrog_domain(access_token, project_id, cluster_id)