def init_region_tenant(self, tenant, region): """ 为团队初始化所在数据中心数据,如果tenant_region存在记录,且未初始化,将记录更新 :param tenant: :param region: :return: 成功返回True,失败返回False """ logger.debug("init region tenant...") success = True tenant_region = self.get_tenant_region_info(tenant, region) if not tenant_region: tenant_region = TenantRegionInfo() tenant_region.tenant_id = tenant.tenant_id tenant_region.region_name = region tenant_region.save() if not tenant_region.is_init: api = RegionInvokeApi() logger.debug( "create tenant {0} with tenant_id {1} on region {2}".format( tenant.tenant_name, tenant.tenant_id, region)) logger.info("start invoking api to init region tenant !") try: res, body = api.create_tenant(region, tenant.tenant_name, tenant.tenant_id, tenant.enterprise_id) logger.debug(res, body) tenant_region.is_active = True tenant_region.is_init = True # todo 将从数据中心获取的租户信息记录到tenant_region, 当前只是用tenant的数据填充 tenant_region.region_tenant_id = tenant.tenant_id tenant_region.region_tenant_name = tenant.tenant_name tenant_region.region_scope = 'public' tenant_region.enterprise_id = tenant.enterprise_id tenant_region.save() except api.CallApiError as e: logger.error("create tenant {0} failed".format( tenant.tenant_name)) logger.exception(e) success = False # 部分初始化但是 else: if (not tenant_region.region_tenant_id) or \ (not tenant_region.region_tenant_name) or \ (not tenant_region.enterprise_id): tenant_region.region_tenant_id = tenant.tenant_id tenant_region.region_tenant_name = tenant.tenant_name tenant_region.region_scope = 'public' tenant_region.enterprise_id = tenant.enterprise_id tenant_region.save() return success
import logging import re from console.constants import AppConstants, ServiceLanguageConstants from console.enum.component_enum import ComponentType, is_state from console.exception.main import ErrVolumePath, ServiceHandleException from console.repositories.app_config import mnt_repo, volume_repo from console.services.app_config.label_service import LabelService from console.services.exception import (ErrVolumeTypeDoNotAllowMultiNode, ErrVolumeTypeNotFound) from console.utils.urlutil import is_path_legal from www.apiclient.regionapi import RegionInvokeApi from www.models.main import TenantServiceVolume from www.utils.crypt import make_uuid region_api = RegionInvokeApi() label_service = LabelService() logger = logging.getLogger("default") volume_bound = "bound" volume_not_bound = "not_bound" volume_ready = "READY" class AppVolumeService(object): SYSDIRS = [ "/", "/bin", "/boot", "/dev", "/etc",
from www.app_http import AppServiceApi from www.decorator import perm_required from www.models.main import ServiceGroup, ServiceGroupRelation, TenantServiceInfo, TenantServiceEnvVar, Users, \ ServiceEvent from www.monitorservice.monitorhook import MonitorHook from www.tenantservice.baseservice import BaseTenantService, TenantUsedResource from www.utils.crypt import make_uuid from www.views import AuthedView from www.views.mixin import LeftSideBarMixin logger = logging.getLogger('default') monitorhook = MonitorHook() baseService = BaseTenantService() tenantUsedResource = TenantUsedResource() region_api = RegionInvokeApi() appClient = AppServiceApi() class AddGroupView(LeftSideBarMixin, AuthedView): """添加组""" @perm_required('manage_service') def post(self, request, *args, **kwargs): group_name = request.POST.get("group_name", "") try: if group_name.strip() == "": return JsonResponse({"ok": False, "info": "组名不能为空"}) if ServiceGroup.objects.filter(tenant_id=self.tenant.tenant_id, region_name=self.response_region, group_name=group_name).exists(): return JsonResponse({"ok": False, "info": "组名已存在"})
def create_and_init_tenant(self, user_id, tenant_name='', region_names=[], enterprise_id='', tenant_alias=''): """ 创建一个团队,并完成团队对指定数据中心的初始化 :param user_id: 用户id :param tenant_name: 团队英文, 兼容历史的tenant租户名称信息 :param tenant_alias: 团队别名, 对团队显示名称 :param region_names: 指定需要开通的数据中心名字列表 :param enterprise_id: 企业ID,(兼容实现,如果未指定则使用团队的tenant_id) :return: """ logger.debug('create_and_init_tenant.....') logger.debug('user_id: {}'.format(user_id)) logger.debug('tenant_name: {}'.format(tenant_name)) logger.debug('region_names: {}'.format(region_names)) logger.debug('enterprise_id: {}:'.format(enterprise_id)) logger.debug('tenant_alias: {}'.format(tenant_alias)) # 判断用户是否存在, 如果有enterprise_id意味着用户与enterprise已经绑定 if enterprise_id: user = Users.objects.get(user_id=user_id, enterprise_id=enterprise_id) enterprise = TenantEnterprise.objects.get( enterprise_id=enterprise_id) else: user = Users.objects.get(user_id=user_id) enterprise = None if user.is_active: logger.info('user is already active, return default tenant') return Tenants.objects.get(creater=user.user_id) tenant_name_regx = re.compile(r'^[a-z0-9-]*$') if tenant_name and not tenant_name_regx.match(tenant_name): logger.error('bad tenant_name!') raise Exception( 'tenant_name must consist of lower case alphanumeric characters or -' ) # 判断团队是否存在 if not tenant_name: tenant_name = self.random_tenant_name() logger.info( 'tenant_name not specify, generator [{}]'.format(tenant_name)) tenants_num = Tenants.objects.filter(tenant_name=tenant_name).count() if tenants_num > 0: raise Exception('team {} already existed!'.format(tenant_name)) # 根据lisence确定是否可以创建新的团队 is_private = sn.instance.is_private() if is_private: tenants_num = Tenants.objects.count() # 私有云用户默认都是企业付费用户,公有云默认用户是免费企业用户 if is_private: pay_type = 'payed' pay_level = 'company' else: pay_type = 'free' pay_level = 'company' expired_day = 7 if hasattr(settings, "TENANT_VALID_TIME"): expired_day = int(settings.TENANT_VALID_TIME) expire_time = dt.datetime.now() + dt.timedelta(days=expired_day) # 计算此团队需要初始化的数据中心 region_configs = {r.get('name'): r for r in regionConfig.regions()} if not region_configs: raise Exception('please config one region at least.') prepare_init_regions = [] if region_names: for region_name in region_names: if region_name in region_configs: prepare_init_regions.append( region_configs.get(region_name)) else: prepare_init_regions.extend(region_configs.values()) if not prepare_init_regions: raise Exception('please init one region at least.') logger.info('prepared init region: {}'.format( [r.get('name') for r in prepare_init_regions])) # 团队管理的默认数据中心 default_region = prepare_init_regions[0] # 使用已存在的企业 if enterprise: logger.info('enterprise existed: {}'.format( enterprise.enterprise_name)) if not tenant_alias: tenant_alias = u'{0}的团队'.format(enterprise.enterprise_alias) # 创建团队 tenant = Tenants.objects.create( tenant_name=tenant_name, pay_type=pay_type, pay_level=pay_level, creater=user_id, region=default_region.get('name'), expired_time=expire_time, tenant_alias=tenant_alias, enterprise_id=enterprise.enterprise_id, limit_memory=4096) logger.info('create tenant:{}'.format(tenant.to_dict())) # 兼容用现有的团队id建立企业信息 else: logger.info( 'enterprise not existed, use tenant for default enterprise.') if not tenant_alias: tenant_alias = u'{0}的团队'.format(tenant_name) # 创建团队 tenant = Tenants.objects.create(tenant_name=tenant_name, pay_type=pay_type, pay_level=pay_level, creater=user_id, region=default_region.get('name'), expired_time=expire_time, tenant_alias=tenant_alias, limit_memory=4096) logger.info('create tenant:{}'.format(tenant.to_dict())) # 依赖团队信息创建企业信息 enterprise = TenantEnterprise.objects.create( enterprise_name=tenant_name, enterprise_alias=tenant_name, enterprise_id=tenant.tenant_id) logger.info('create enterprise with tenant:{}'.format( enterprise.to_dict())) # 将企业id关联到团队之上 tenant.enterprise_id = enterprise.enterprise_id tenant.save() # 将此用户与企业关系绑定 user.enterprise_id = enterprise.enterprise_id monitor_hook.tenantMonitor(tenant, user, "create_tenant", True) # 创建用户团队企业关系及权限,创建团队的用户即为此团队的管理员 logger.debug( 'create tenant_perm! user_pk: {0}, tenant_pk:{1}, enterprise_pk:{2}' .format(user_id, tenant.pk, enterprise.pk)) PermRelTenant.objects.create(user_id=user_id, tenant_id=tenant.pk, identity='admin', enterprise_id=enterprise.pk) # 初始化数据中心并建立团队与数据中心的关系 api = RegionInvokeApi() for region in prepare_init_regions: tenant_region = TenantRegionInfo.objects.create( tenant_id=tenant.tenant_id, region_name=region.get('name'), enterprise_id=enterprise.enterprise_id) try: res, body = api.create_tenant(region.get('name'), tenant.tenant_name, tenant.tenant_id, enterprise.enterprise_id) logger.debug(res) logger.debug(body) tenant_region.is_active = True tenant_region.is_init = True # todo 将从数据中心获取的租户信息记录到tenant_region, 当前只是用tenant的数据填充 tenant_region.region_tenant_id = tenant.tenant_id tenant_region.region_tenant_name = tenant.tenant_name tenant_region.region_scope = 'public' tenant_region.save() logger.info("tenant_region[{0}] = {1}, {2}, {3}".format( tenant_region.region_name, tenant_region.region_tenant_id, tenant_region.region_tenant_name, tenant_region.region_scope)) monitor_hook.tenantMonitor(tenant, user, "init_tenant", True) logger.info("init success!") except Exception as e: logger.error("init failed: {}".format(e.message)) logger.exception(e) tenant_region.is_init = False tenant_region.is_active = False tenant_region.save() monitor_hook.tenantMonitor(tenant, user, "init_tenant", False) user.is_active = True user.save() try: content = '新用户: {0}, 手机号: {1}, 租户: {2}, 邮箱: {3}, 企业: {4}'.format( user.nick_name, user.phone, tenant.tenant_name, user.email, enterprise.enterprise_alias) send_mail("new user active tenant", content, '*****@*****.**', notify_mail_list) except Exception: pass return tenant
class NodeService(object): url = "http://test.goodrain.com:6200" default_headers = { 'Connection': 'keep-alive', 'Content-Type': 'application/json' } http_client = HttpInvokeApi() region_api = RegionInvokeApi() def wapper_node_info(self, node_list, region, cluster): for node in node_list: status = node["status"] node["status_cn"] = STATUS_MAP.get(status, "未知") node['region_alias'] = region.region_alias node['cluster_alias'] = cluster.cluster_alias node['cluster_name'] = cluster.cluster_name node["region_name"] = region.region_name node["region_id"] = region.region_id node["cluster_id"] = cluster.ID return node_list def get_nodes(self, region_id, cluster_id): region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(ID=cluster_id) # 更新请求发送客户端 list = [] try: self.http_client.update_client(region) res, body = self.http_client.get_region_nodes(body=None) if 400 <= res.status <= 600: return body["code"], body["body"] list = body["body"]["list"] except Exception as e: logger.exception(e) node_list = self.wapper_node_info(list, region, cluster) return 200, node_list # def add_node(self, region_id, cluster_id, **kwargs): # # 此方法已废弃 # region = RegionConfig.objects.get(region_id=region_id) # cluster = RegionClusterInfo.objects.get(ID=cluster_id) # self.http_client.update_client(region) # # body = kwargs # labels = json.loads(body["labels"]) # body["labels"] = labels # uuid = make_uuid() # body["uuid"] = uuid # res, body = self.http_client.add_node(json.dumps(body)) # # 为节点记录标签 # if 200 <= body["code"] < 300: # all_labels = Labels.objects.all() # # 标签ID和标签英文名称字符串 # label_map = {l.label_name: l.label_id for l in all_labels} # node_labels = [] # for label_name in labels.keys(): # label_id = label_map.get(label_name, None) # if label_id: # node_label = NodeLabels( # region_id=region_id, # cluster_id=cluster_id, # node_uuid=uuid, # label_id=label_id, # ) # node_labels.append(node_label) # NodeLabels.objects.bulk_create(node_labels) # return body["code"], body["body"] def get_node_brief_info(self, region_id, cluster_id, node_uuid): region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(ID=cluster_id) self.http_client.update_client(region) res, body = self.http_client.get_node_brief_info(node_uuid, None) result = body["body"] result["bean"]["region_id"] = region_id result["bean"]["cluster_id"] = cluster_id result["bean"]["region_name"] = region.region_name result["bean"]["cluster_name"] = cluster.cluster_name result["bean"]["region_alias"] = region.region_alias result["bean"]["cluster_alias"] = cluster.cluster_alias return body["code"], result def format_memory(self, memorystr): if memorystr.endswith("m".upper()) or memorystr.endswith("m"): memory = memorystr[:-1] return int(memory.strip()) else: return int(memorystr.strip()) def get_node_service_details(self, nonterminatedpods): tenant_ids = [] service_alias_list = [] for info in nonterminatedpods: tenant_ids.append(info["namespace"]) service_alias_list.append(info["id"]) tenants = Tenants.objects.filter(tenant_id__in=tenant_ids).values( "tenant_id", "tenant_name") services = TenantServiceInfo.objects.filter( service_alias__in=service_alias_list).values( "service_alias", "service_cname") tenant_id_name_map = { tenant["tenant_id"]: tenant["tenant_name"] for tenant in tenants } service_alias_name_map = { service["service_alias"]: service["service_cname"] for service in services } for info in nonterminatedpods: info["tenant_name"] = tenant_id_name_map.get(info["namespace"], "") info["service_cname"] = service_alias_name_map.get(info["id"], "") pod_list = sorted(nonterminatedpods, key=lambda pod: (self.format_memory(pod["memoryrequests"]), self.format_memory(pod["cpurequest"])), reverse=True) return pod_list def wapper_node_labels(self, labels): all_labels = Labels.objects.all() # 标签中文和标签英文名称字符串 label_map = {l.label_name: l.label_alias for l in all_labels} rt_label = {} if labels: for k in labels.iterkeys(): val = label_map.get(k, None) if val: rt_label[k] = val return rt_label def get_node_info(self, region_id, cluster_id, node_uuid): region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(ID=cluster_id) self.http_client.update_client(region) res, body = self.http_client.get_node_info(node_uuid, None) if 400 <= res.status <= 600: return body["code"], body result = body["body"] nonterminatedpods = result["bean"].get("nonterminatedpods") nonterminatedpods = self.get_node_service_details(nonterminatedpods) labels = result["bean"].get("labels") labels = self.wapper_node_labels(labels) status = result["bean"].get("status") result["bean"]["status_cn"] = STATUS_MAP.get(status, "未知") result["bean"]["nonterminatedpods"] = nonterminatedpods result["bean"]["labels"] = labels result["bean"]["region_id"] = region_id result["bean"]["cluster_id"] = cluster_id result["bean"]["region_name"] = region.region_name result["bean"]["cluster_name"] = cluster.cluster_name result["bean"]["region_alias"] = region.region_alias result["bean"]["cluster_alias"] = cluster.cluster_alias return body["code"], result def update_node_info(self, region_id, cluster_id, node_uuid, **kwargs): # 此方法已废弃 region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(ID=cluster_id) self.http_client.update_client(region) body = kwargs labels = json.loads(body["labels"]) body["labels"] = labels res, body = self.http_client.update_node_info(node_uuid, json.dumps(body)) # 更新节点标签 if 200 <= body["code"] < 300: all_labels = Labels.objects.all() # 标签ID和标签英文名称字符串 label_map = {l.label_name: l.label_id for l in all_labels} # 删除原有标签 NodeLabels.objects.filter(node_uuid=node_uuid).delete() node_labels = [] for label_name in labels.keys(): label_id = label_map.get(label_name, None) if label_id: node_label = NodeLabels( region_id=region_id, cluster_id=cluster_id, node_uuid=node_uuid, label_id=label_id, ) node_labels.append(node_label) NodeLabels.objects.bulk_create(node_labels) return body["code"], body["body"] def delete_node(self, region_id, cluster_id, node_uuid): """删除节点""" region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(ID=cluster_id) self.http_client.update_client(region) res, body = self.http_client.delete_node(node_uuid, None) result = body["body"] return body["code"], result def get_all_region_nodes(self): regions = region_service.get_all_regions(True) # 对每个数据中心下的每个集群查询节点信息 node_list = [] for region in regions: cluster_list = cluster_service.get_cluster_by_region( region.region_id) for cluster in cluster_list: status, nodes = self.get_nodes(region.region_id, cluster.ID) if status == 200: for node in nodes: node["region_id"] = region.region_id node["cluster_id"] = cluster.ID node["region_alias"] = region.region_alias node["cluster_alias"] = cluster.cluster_alias node_list.append(node) sorted_nodes = sorted(node_list, key=lambda node: node["host_name"]) return sorted_nodes def manage_node(self, region_id, cluster_id, node_uuid, action): """节点操作""" if not action: raise ParamsError("未识别操作") region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(ID=cluster_id) self.http_client.update_client(region) if action == "online": res, body = self.http_client.online_node(node_uuid, None) elif action == "offline": res, body = self.http_client.offline_node(node_uuid, None) elif action == "reschedulable": res, body = self.http_client.schedulable_node(node_uuid, None) elif action == "unschedulable": res, body = self.http_client.unschedulable_node(node_uuid, None) else: raise ParamsError("未识别操作") result = body["body"] return body["code"], result def node_check(self, region_id, data): region = RegionConfig.objects.get(region_id=region_id) params = {} cluster = RegionClusterInfo.objects.get(region_id=region_id) host = data.get("host") port = data.get("port", 22) params["hostport"] = host + ":" + str(port) node_type = data.get("node_type") params["hosttype"] = node_type login_type = data.get("login_type") params["pwd"] = None params["type"] = False if login_type == "root": params["type"] = True root_pwd = data.get("root_pwd") params["pwd"] = root_pwd self.http_client.update_client(region) res, body = self.http_client.node_login_check(json.dumps(params)) if 200 <= res.status < 400: bean = body["bean"] return 200, bean else: return res.status, body["msg"] def node_init(self, region_id, data): region = RegionConfig.objects.get(region_id=region_id) params = {} cluster = RegionClusterInfo.objects.get(region_id=region_id) node_ip = data.get("node_ip") params["ip"] = node_ip self.http_client.update_client(region) res, body = self.http_client.node_component_init( node_ip, json.dumps(params)) logger.debug("res {0} ,body {1}".format(res, body)) if 200 <= res.status < 400: return 200, body["bean"] else: return int(res.status), body["msg"] def node_install(self, region_id, node_ip): """节点组件安装""" region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(region_id=region_id) self.http_client.update_client(region) res, body = self.http_client.node_component_install(node_ip, None) if 200 <= res.status < 400: return 200, body["bean"] else: return int(res.status), body["msg"] def is_init(self, region_id, node_ip): """判断节点是否初始化""" nodes = NodeInstallInfo.objects.filter(region_id=region_id, node_ip=node_ip) flag = True if nodes: node = nodes[0] if node.init_status == "uninit": flag = False else: NodeInstallInfo.objects.create(region_id=region_id, node_ip=node_ip, init_status="uninit") flag = False return flag def check_init_status(self, region_id, node_ip): """检测节点初始化状态""" region = RegionConfig.objects.get(region_id=region_id) # if not self.is_init(region_id, node_ip): # code, result = self.node_init(region_id, {"node_ip": node_ip}) # if code != 200: # body = {} # body["msg_show"] = "初始化指令发送失败" # return code, body # else: # # 表示初始化中 # NodeInstallInfo.objects.filter(region_id=region_id, node_ip=node_ip).update(init_status="initing") self.http_client.update_client(region) res, body = self.http_client.node_init_status(node_ip, None) rt_body = {} if 200 <= res.status < 400: result = body["bean"] status = result["status"] if status == "failed": msg = "初始化失败{0}".format(result["msg"]) elif status == "success": msg = "初始化成功" elif status == "uninit": # 未初始化进行初始化 code, result = self.node_init(region_id, {"node_ip": node_ip}) msg = "未初始化" logger.debug("init node status {0}, result is {1}".format( code, result)) elif status == "initing": msg = "初始化中" else: msg = "正在初始化节点..." rt_body["status"] = status rt_body["msg"] = msg else: rt_body["status"] = "failed" rt_body["msg"] = "初始化失败" return rt_body def node_install_status(self, region_id, node_ip): """查询节点安装状态""" region = RegionConfig.objects.get(region_id=region_id) cluster = RegionClusterInfo.objects.get(region_id=region_id) self.http_client.update_client(region) res, body = self.http_client.node_component_status(node_ip, None) if 200 <= res.status < 400: return 200, body["bean"] else: return int(res.status), body["msg"] if body["msg"] else "安装状态查询异常" def update_node_labels(self, region_id, cluster_id, node_uuid, labels_map): """添加节点的标签""" region = RegionConfig.objects.get(region_id=region_id) labels_map = json.loads(labels_map) all_labels = Labels.objects.all() label_id_map = {l.label_name: l.label_id for l in all_labels} node_labels = [] for k, v in labels_map.iteritems(): # 对于用户自定义的标签进行操作 if v == "selfdefine": label_id = label_id_map.get(k, None) if label_id: node_label = NodeLabels(region_id=region_id, cluster_id=cluster_id, node_uuid=node_uuid, label_id=label_id) node_labels.append(node_label) res, body = self.http_client.update_node_labels( region, node_uuid, json.dumps(labels_map)) NodeLabels.objects.filter(region_id=region_id, node_uuid=node_uuid).delete() NodeLabels.objects.bulk_create(node_labels) return res, body def get_ws_url(self, request, default_url, ws_type): if default_url != "auto": return "{0}/{1}".format(default_url, ws_type) logger.debug(request.META) host = request.META.get('REMOTE_ADDR').split(':')[0] return "ws://{0}:6060/{1}".format(host, ws_type)