def copy_envs(self, service_info, current_service):
        s = current_service
        baseService = BaseTenantService()
        envs = AppServiceEnv.objects.filter(service_key=service_info.service_key, app_version=service_info.version)
        outer_ports = AppServicePort.objects.filter(service_key=service_info.service_key,
                                                    app_version=service_info.version,
                                                    is_outer_service=True,
                                                    protocol='http')
        for env in envs:
            if env.attr_name == 'SITE_URL':
                if self.region_name in RegionInfo.valid_regions():
                    port = RegionInfo.region_port(self.region_name)
                    domain = RegionInfo.region_domain(self.region_name)
                    env.options="direct_copy"
                    if len(outer_ports)>0:
                        env.attr_value = 'http://{}.{}.{}{}:{}'.format(outer_ports[0].container_port, current_service.serviceAlias,self.tenant_name, domain, port)
                    logger.debug("SITE_URL = {} options = {}".format(env.attr_value, env.options))
            elif env.attr_name == "TRUSTED_DOMAIN":
                if self.region_name in RegionInfo.valid_regions():
                    port = RegionInfo.region_port(self.region_name)
                    domain = RegionInfo.region_domain(self.region_name)
                    env.options = 'direct_copy'
                    if len(outer_ports) > 0:
                        env.attr_value = '{}.{}.{}{}:{}'.format(outer_ports[0].container_port, current_service.serviceAlias, self.tenant_name, domain, port)
                    logger.debug("TRUSTED_DOMAIN = {} options = {}".format(env.attr_value, env.options))

            baseService.saveServiceEnvVar(s.tenant_id, s.service_id, env.container_port, env.name,
                                          env.attr_name, env.attr_value, env.is_change, env.scope)
 def set_tenant_default_env(self, envs, outer_ports):
     for env in envs:
         if env.attr_name == 'SITE_URL':
             if self.cookie_region in RegionInfo.valid_regions():
                 port = RegionInfo.region_port(self.cookie_region)
                 domain = RegionInfo.region_domain(self.cookie_region)
                 env.options = 'direct_copy'
                 if len(outer_ports) > 0:
                     env.attr_value = 'http://{}.{}.{}{}:{}'.format(outer_ports[0].container_port, self.serviceAlias, self.tenantName, domain, port)
                 logger.debug("SITE_URL = {} options = {}".format(env.attr_value, env.options))
         elif env.attr_name == 'TRUSTED_DOMAIN':
             if self.cookie_region in RegionInfo.valid_regions():
                 port = RegionInfo.region_port(self.cookie_region)
                 domain = RegionInfo.region_domain(self.cookie_region)
                 env.options = 'direct_copy'
                 if len(outer_ports) > 0:
                     env.attr_value = '{}.{}.{}{}:{}'.format(outer_ports[0].container_port, self.serviceAlias, self.tenantName, domain, port)
                 logger.debug("TRUSTED_DOMAIN = {} options = {}".format(env.attr_value, env.options))
Example #3
0
 def set_direct_copy_options(self, envs, service_id, service_key, version):
     outer_ports = AppServicePort.objects.filter(service_key=service_key,
                                                 app_version=version,
                                                 is_outer_service=True,
                                                 protocol='http')
     service_alias = "gr" + service_id[-6:]
     for env in envs:
         if env.attr_name == 'SITE_URL' or env.attr_name == 'TRUSTED_DOMAIN':
             if self.cookie_region in RegionInfo.valid_regions():
                 env.options = 'direct_copy'
                 if len(outer_ports) > 0:
                     port = RegionInfo.region_port(self.response_region)
                     domain = RegionInfo.region_domain(self.response_region)
                     if env.attr_name == 'SITE_URL':
                         env.attr_value = 'http://{}.{}.{}{}:{}'.format(outer_ports[0].container_port, service_alias,
                                                                        self.tenantName, domain, port)
                     else:
                         env.attr_value = '{}.{}.{}{}:{}'.format(outer_ports[0].container_port, service_alias,
                                                                 self.tenantName, domain, port)
Example #4
0
    def post(self, request, service_name, *args, **kwargs):
        """
        创建云市服务接口
        ---
        parameters:
            - name: service_name
              description: 服务名称
              required: true
              type: string
              paramType: path
            - name: tenant_name
              description: 租户名称
              required: true
              type: string
              paramType: form
            - name: region
              description: 数据中心
              required: true
              type: string
              paramType: form
            - name: service_key
              description: 镜像key
              required: true
              type: string
              paramType: form
            - name: version
              description: 镜像version
              required: true
              type: string
              paramType: form
            - name: user_id
              description: 创建人id
              required: true
              type: int
              paramType: form
            - name: username
              description: 创建人姓名
              required: true
              type: string
              paramType: form
            - name: service_memory
              description: 服务的内存大小
              required: false
              type: int
              paramType: form
            - name: service_node
              description: 节点个数
              required: false
              type: int
              paramType: form
            - name: dep_info
              description: 套餐依赖服务的设置(json)
              required: false
              type: string
              paramType: form
            - name: env_list
              description: 服务的环境参数
              required: false
              type: array
              paramType: form
            - name: limit
              description: 是否检查资源限制
              required: false
              type: bool
              paramType: form
        """
        logger.debug("openapi.cloudservice", request.data)
        tenant_name = request.data.get("tenant_name", None)
        if tenant_name is None:
            return Response(status=405, data={"success": False, "msg": u"租户名称为空"})
        # 数据中心
        region = request.data.get("region", None)
        if region is None:
            return Response(status=406, data={"success": False, "msg": u"数据中心名称为空"})
        # 根据service_key, version创建服务
        service_key = request.data.get("service_key", None)
        if service_key is None:
            return Response(status=408, data={"success": False, "msg": u"镜像key为空!"})
        # 服务描述
        version = request.data.get("version", None)
        if version is None:
            return Response(status=409, data={"success": False, "msg": u"镜像version为空!"})
        # 非必填字段
        user_id = request.data.get("user_id", "1")
        username = request.data.get("username", "system")
        service_memory = request.data.get("service_memory", "")
        service_node = request.data.get("service_node", 1)
        dep_info = request.data.get("dep_info", "[]")
        dep_info_json = json.loads(dep_info)
        dep_service_info = {"{0}-{1}".format(x.get("service_key"), x.get("app_version")): x for x in dep_info_json}

        logger.debug("openapi.cloudservice", "now create service: service_name:{0}, tenant_name:{1}, region:{2}, key:{3}, version:{4}".format(service_name, tenant_name, region, service_key, version))
        r = re.compile("^[a-z][a-z0-9-]*[a-z0-9]$")
        if not r.match(service_name):
            return Response(status=412, data={"success": False, "msg": u"服务名称不合法!"})
        # 根据租户名称获取租户信息
        try:
            tenant = Tenants.objects.get(tenant_name=tenant_name)
        except Tenants.DoesNotExist:
            logger.error("openapi.cloudservice", "Tenant {0} is not exists".format(tenant_name))
            return Response(status=413, data={"success": False, "msg": u"查询不到租户"})

        # 检查租户是否欠费
        # if tenantAccountService.isOwnedMoney(tenant, region):

        # 检查服务名称是否存在
        num = TenantServiceInfo.objects.filter(tenant_id=tenant.tenant_id,
                                               service_alias=service_name).count()
        if num > 0:
            logger.error("openapi.cloudservice", "Tenant {0} region {1} service:{2} is exists=!".format(tenant_name, region, service_name))
            return Response(status=414, data={"success": False, "msg": u"服务名称已经存在"})

        # 检查对应region上的tenant是否创建
        init_region_tenant = manager.init_region_tenant(region, tenant_name, tenant.tenant_id, username)
        if not init_region_tenant:
            logger.error("openapi.cloudservice", "Tenant {0} region {1} init failed!".format(tenant_name, region))
            return Response(status=470, data={"success": False, "msg": u"init region tenant failed!"})

        # 没有模版从app下载模版\根据模版查询服务依赖信息
        status, success, dep_map, msg = manager.download_service(service_key, version)
        if status == 500:
            logger.error("openapi.cloudservice", msg)
            return Response(status=status, data={"success": success, "msg": msg})
        # relation_list 从后向前安装服务
        dep_required_memory = 0
        dep_service_list = None
        if len(dep_map) > 0:
            dep_query = Q()
            for tmp_key, tmp_version in dep_map.items():
                dep_query = dep_query | (Q(service_key=tmp_key) & Q(version=tmp_version))
            dep_service_list = ServiceInfo.objects.filter(dep_query)
            if len(dep_service_list) > 0:
                # 计算依赖服务需要的资源
                for dep_service_tmp in list(dep_service_list):
                    tmp_key = "{0}-{1}".format(dep_service_tmp.service_key, dep_service_tmp.version)
                    dep_info = dep_service_info.get(tmp_key)
                    if dep_info is not None:
                        dep_required_memory += int(dep_info["memory"]) * int(dep_info["node"])
                    else:
                        dep_required_memory += int(dep_service_tmp.min_memory)
                # dep_required_memory = reduce(lambda x, y: x + y, [s.min_memory for s in dep_service_list])

        # 生成随机service_id
        service_id = crypt.make_uuid(tenant.tenant_id)
        # 查询服务模版
        service = ServiceInfo.objects.get(service_key=service_key, version=version)
        service.desc = ''
        if service_memory != "":
            cm = int(service_memory)
            if cm >= 128:
                ccpu = int(cm / 128) * 20
                service.min_cpu = ccpu
                service.min_memory = cm
        # 计算服务资源
        tenant_service_info = TenantServiceInfo()
        tenant_service_info.min_memory = service.min_memory
        tenant_service_info.service_region = region
        tenant_service_info.min_node = service.min_node
        if int(service_node) > 1:
            tenant_service_info.min_node = int(service_node)
        diffMemory = dep_required_memory + service.min_node * service.min_memory
        # 是否检查资源限制
        limit = request.data.get("limit", True)
        if limit:
            rt_type, flag = manager.predict_next_memory(tenant, tenant_service_info, diffMemory, False)
            if not flag:
                if rt_type == "memory":
                    logger.error("openapi.cloudservice", "Tenant {0} region {1} service:{2} memory!".format(tenant_name, region, service_name))
                    return Response(status=416, data={"success": False, "msg": u"内存已经到最大值"})
                else:
                    logger.error("openapi.cloudservice", "Tenant {0} region {1} service:{2} memory!".format(tenant_name, region, service_name))
                    return Response(status=417, data={"success": False, "msg": u"资源已经到最大值"})
        logger.debug("openapi.cloudservice", "now install dep service and service,memory:{0}".format(diffMemory))

        # 创建依赖的服务
        dep_sids = []
        tenant_service_list = []
        if dep_service_list is not None:
            # 服务从后向前安装
            dep_service_list.reverse()
            for dep_service in dep_service_list:
                dep_service_id = crypt.make_uuid(dep_service.service_key)
                logger.debug("openapi.cloudservice", "install dep service:{0}".format(dep_service_id))
                try:
                    depTenantService = manager.create_service(dep_service_id,
                                                              tenant.tenant_id,
                                                              dep_service.service_name.lower() + "_" + service_name,
                                                              dep_service,
                                                              user_id,
                                                              region=region,
                                                              service_origin='cloud')
                    # 更新服务节点、内存
                    tmp_key = "{0}-{1}".format(dep_service_tmp.service_key, dep_service_tmp.version)
                    dep_info = dep_service_info.get(tmp_key)
                    if dep_info is not None:
                        depTenantService.min_node = int(dep_info["node"])
                        depTenantService.min_memory = int(dep_info["memory"])
                        depTenantService.save()
                    manager.add_service_extend(depTenantService, dep_service)
                    monitorhook.serviceMonitor(username, depTenantService, 'create_service', True)
                    tenant_service_list.append(depTenantService)
                    dep_sids.append(dep_service_id)
                except Exception as e:
                    logger.exception("openapi.cloudservice", e)
                    TenantServiceInfo.objects.filter(service_id=service_id).delete()
                    TenantServiceAuth.objects.filter(service_id=service_id).delete()
                    TenantServiceEnvVar.objects.filter(service_id=service_id).delete()
                    TenantServiceRelation.objects.filter(service_id=service_id).delete()
                    TenantServiceVolume.objects.filter(service_id=service_id).delete()
                    return Response(status=418, data={"success": False, "msg": u"创建控制台依赖服务失败!"})
                logger.debug("openapi.cloudservice", "install dep service:{0} over".format(dep_service_id))
                logger.debug("openapi.cloudservice", "install dep region service,region:{0}".format(region))
                try:
                    manager.create_region_service(depTenantService,
                                                  tenant_name,
                                                  region,
                                                  username)
                    monitorhook.serviceMonitor(username, depTenantService, 'init_region_service', True)
                except Exception as e:
                    logger.error("openapi.cloudservice", "create region service failed!", e)
                    return Response(status=419, data={"success": False, "msg": u"创建region服务失败!"})
                logger.debug("openapi.cloudservice", "install dep region service,region:{0} over".format(region))
                logger.debug("openapi.cloudservice", "install dep relation")
                # 依赖关系 todo 无法处理多层依赖关系,
                manager.create_service_dependency(tenant.tenant_id,
                                                  service_id,
                                                  dep_service_id,
                                                  region)
                logger.debug("openapi.cloudservice", "install dep relation over")
                # 添加goodrain_web_api反馈
                monitorhook.serviceMonitor(username, depTenantService, 'create_service', True,
                                           origin='goodrain_web_api')

        # create console service
        logger.debug("openapi.cloudservice", "install current service now")
        try:
            newTenantService = manager.create_service(service_id,
                                                      tenant.tenant_id,
                                                      service_name,
                                                      service,
                                                      user_id,
                                                      region=region,
                                                      service_origin='cloud')
            need_update = False
            if service_memory != "" and int(service_memory) > 128:
                newTenantService.min_memory = int(service_memory)
                need_update = True
            if int(service_node) > 1:
                newTenantService.min_node = int(service_node)
                need_update = True
            if need_update:
                newTenantService.save()
            if len(dep_service_list) > 0:
                self.saveAdapterEnv(newTenantService)
            manager.add_service_extend(newTenantService, service)
            monitorhook.serviceMonitor(username, newTenantService, 'create_service', True)
        except Exception as e:
            logger.error("openapi.cloudservice", "create console service failed!", e)
            TenantServiceInfo.objects.filter(service_id=service_id).delete()
            TenantServiceAuth.objects.filter(service_id=service_id).delete()
            TenantServiceEnvVar.objects.filter(service_id=service_id).delete()
            TenantServiceRelation.objects.filter(service_id=service_id).delete()
            TenantServiceVolume.objects.filter(service_id=service_id).delete()
            return Response(status=418, data={"success": False, "msg": u"创建控制台服务失败!"})
        logger.debug("openapi.cloudservice", "install current service now success!")
        env_list = request.data.get("env_list", None)
        # query service port
        service_port_list = TenantServicesPort.objects.filter(service_id=newTenantService.service_id,
                                                              is_outer_service=True,
                                                              protocol='http')
        if env_list is not None:
            env_var_list = TenantServiceEnvVar.objects.filter(service_id=service_id, tenant_id=tenant.tenant_id, is_change=True)
            env_var_map = {x.attr_name: x for x in list(env_var_list)}
            for env_var in env_list:
                attr_name = env_var.get("attr_name")
                attr_value = env_var.get("attr_value")
                env = env_var_map.get(attr_name, None)
                if attr_name == "SITE_URL":
                    port = RegionInfo.region_port(region)
                    domain = RegionInfo.region_domain(region)
                    if len(service_port_list) > 0:
                        port_value = service_port_list[0].container_port
                        attr_value = 'http://{}.{}.{}{}:{}'.format(port_value, service_name, tenant.tenant_name, domain, port)
                    logger.debug("openapi.cloudservice", "SITE_URL = {}".format(env.attr_value))
                elif attr_name == "TRUSTED_DOMAIN":
                    port = RegionInfo.region_port(region)
                    domain = RegionInfo.region_domain(region)
                    if len(service_port_list) > 0:
                        port_value = service_port_list[0].container_port
                        attr_value = '{}.{}.{}{}:{}'.format(port_value, service_name, tenant.tenant_name, domain, port)
                    logger.debug("openapi.cloudservice", "TRUSTED_DOMAIN = {}".format(env.attr_value))

                if env is not None:
                    env.attr_value = attr_value
                else:
                    env = TenantServiceEnvVar(
                        tenant_id=tenant.tenant_id,
                        service_id=service_id,
                        container_port=env_var.get("container_port"),
                        name=env_var.get("name"),
                        attr_name=attr_name,
                        attr_value=attr_value,
                        is_change=env_var.get("is_change"),
                        scope=env_var.get("scope"),
                    )
                env.save()
        logger.debug("openapi.cloudservice", "install service env success!")
        # create region service
        logger.debug("openapi.cloudservice", "install region service {0}!".format(region))
        try:
            manager.create_region_service(newTenantService,
                                          tenant_name,
                                          region,
                                          username, dep_sids=json.dumps(dep_sids))
            monitorhook.serviceMonitor(username, newTenantService, 'init_region_service', True)
        except Exception as e:
            logger.error("openapi.cloudservice", "create region service failed!", e)
            return Response(status=419, data={"success": False, "msg": u"创建region服务失败!"})
        logger.debug("openapi.cloudservice", "install region service {0} success!".format(region))

        # 发送goodrain_web_api反馈
        # 1、依赖信息
        tmp_info = []
        for dep_service in tenant_service_list:
            tmp_array = {"dep_id": dep_service.service_id,
                         "dep_name": dep_service.service_alias}
            tmp_info.append(tmp_array)
        tmp_data = {
            "service_region": region,
            "deps": tmp_info
        }
        monitorhook.serviceMonitor(username, newTenantService, 'create_service', True,
                                   origin='goodrain_web_api',
                                   info=json.dumps(tmp_data))

        wild_domain = ""
        if region in settings.WILD_DOMAINS.keys():
            wild_domain = settings.WILD_DOMAINS[newTenantService.service_region]
        http_port_str = ""
        if region in settings.WILD_PORTS.keys():
            http_port_str = settings.WILD_PORTS[region]
        http_port_str = ":" + http_port_str
        # 只有http服务返回url
        access_url = ""

        if len(service_port_list) > 0:
            port_value = service_port_list[0].container_port
            access_url = "http://{0}.{1}.{2}{3}{4}".format(port_value,
                                                           newTenantService.service_alias,
                                                           tenant_name,
                                                           wild_domain,
                                                           http_port_str)
        logger.debug("openapi.cloudservice", "service access url {0}".format(access_url))
        json_data = {}
        json_data["cloud_assistant"] = sn.instance.cloud_assistant
        json_data["url"] = access_url
        json_data["service"] = newTenantService.to_dict()
        json_data["dep_service"] = map(lambda x: x.to_dict(), tenant_service_list)
        # 服务env+依赖服务env
        dep_service_ids = [x.service_id for x in tenant_service_list]
        if service_id not in dep_service_ids:
            dep_service_ids.append(service_id)
        env_var_list = TenantServiceEnvVar.objects.filter(service_id__in=dep_service_ids).exclude(attr_name="GD_ADAPTER")
        env_list = []
        # 过滤掉不显示字段
        for env_var in list(env_var_list):
            if env_var.name in ["GD_ADAPTER", "GR_PROXY"]:
                continue
            env_list.append(env_var)
        json_data["env_list"] = map(lambda x: x.to_dict(), env_list)
        # 服务port+依赖服务port
        # port_list = TenantServicesPort.objects.filter(service_id__in=dep_service_ids)
        # json_data["port_list"] = port_list
        # 服务volume+依赖服务
        # TenantServiceVolume.objects.filter(service_id__in=dep_service_ids)
        # 依赖的环境变量

        return Response(status=200, data={"success": True, "service": json_data})