Apollo源码解析——创建NameSpace


一、概述

Patrol创建Namespace的流程

在这里插入图片描述

二、创建流程

1.页面流程

在这里插入图片描述

在这里插入图片描述

2.代码流程

  1. patrol模块下的NamespaceController#createAppNamespace
  1. 保存AppNamespace到数据库
  2. 发布AppNamespaceCreationEvent 创建事件
  @PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)")
  @PostMapping("/apps/{appId}/appnamespaces")
  public AppNamespace createAppNamespace(@PathVariable String appId,
      @RequestParam(defaultValue = "true") boolean appendNamespacePrefix,
      @Valid @RequestBody AppNamespace appNamespace) {
    //校验参数
    if (!InputValidator.isValidAppNamespace(appNamespace.getName())) {
      throw new BadRequestException(String.format("Invalid Namespace format: %s",
          InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE));
    }

    //保存AppNamespace 对象到数据库
    AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace, appendNamespacePrefix);
 // 赋予权限,若满足如下任一条件:
        // 1. 公开类型的 AppNamespace 。
       // 2. 私有类型的 AppNamespace ,并且允许 App 管理员创建私有类型的 AppNamespace 。
    if (portalConfig.canAppAdminCreatePrivateNamespace() || createdAppNamespace.isPublic()) {
      namespaceService.assignNamespaceRoleToOperator(appId, appNamespace.getName(),
          userInfoHolder.getUser().getUserId());
    }

    // 发布 AppNamespaceCreationEvent 创建事件
    publisher.publishEvent(new AppNamespaceCreationEvent(createdAppNamespace));

    //返回创建的 AppNamespace 对象
    return createdAppNamespace;
  }
  1. AppNamespaceService#createAppNamespaceInLocal

这里其实就是做了一些逻辑上的校验,没问题,然后保存,初始化权限

  @Transactional
  public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace, boolean appendNamespacePrefix) {
    String appId = appNamespace.getAppId();

    //add app org id as prefix
    //校验对应的 app 是否存在,若不存在,抛出 BadRequestException 异常
    App app = appService.load(appId);
    if (app == null) {
      throw new BadRequestException("App not exist. AppId = " + appId);
    }

    //拼接 AppNamespace 的 `name` 属性
    StringBuilder appNamespaceName = new StringBuilder();
    //add prefix postfix
    appNamespaceName
        .append(appNamespace.isPublic() && appendNamespacePrefix ? app.getOrgId() + "." : "")
        .append(appNamespace.getName())
        .append(appNamespace.formatAsEnum() == ConfigFileFormat.Properties ? "" : "." + appNamespace.getFormat());
    appNamespace.setName(appNamespaceName.toString());

    //设置 AppNamespace 的 `comment` 属性为空串 ,若为 null
    if (appNamespace.getComment() == null) {
      appNamespace.setComment("");
    }

    //校验 AppNamespace 的  `format`是否合法
    if (!ConfigFileFormat.isValidFormat(appNamespace.getFormat())) {
     throw new BadRequestException("Invalid namespace format. format must be properties、json、yaml、yml、xml");
    }

    //设置 AppNamespace 的创建和修改人
    String operator = appNamespace.getDataChangeCreatedBy();
    if (StringUtils.isEmpty(operator)) {
      operator = userInfoHolder.getUser().getUserId();//当前登陆的管理员
      appNamespace.setDataChangeCreatedBy(operator);
    }

    appNamespace.setDataChangeLastModifiedBy(operator);

    // globally uniqueness check for public app namespace
    if (appNamespace.isPublic()) {
      checkAppNamespaceGlobalUniqueness(appNamespace);
    } else {
      // check private app namespace
      // 校验 `name` 全局唯一
      if (appNamespaceRepository.findByAppIdAndName(appNamespace.getAppId(), appNamespace.getName()) != null) {
        throw new BadRequestException("Private AppNamespace " + appNamespace.getName() + " already exists!");
      }
      // should not have the same with public app namespace
      //检查私有命名空间不能和公共的相同
      checkPublicAppNamespaceGlobalUniqueness(appNamespace);
    }
   //保存 AppNamespace 到数据库
    AppNamespace createdAppNamespace = appNamespaceRepository.save(appNamespace);

    //初始化 Namespace 的 Role 们
    roleInitializationService.initNamespaceRoles(appNamespace.getAppId(), appNamespace.getName(), operator);
    roleInitializationService.initNamespaceEnvRoles(appNamespace.getAppId(), appNamespace.getName(), operator);

    return createdAppNamespace;
  }
  @PreAuthorize(value = "@permissionValidator.hasCreateClusterPermission(#appId)")
  @PostMapping(value = "apps/{appId}/envs/{env}/clusters")
  public ClusterDTO createCluster(@PathVariable String appId, @PathVariable String env,
                                  @Valid @RequestBody ClusterDTO cluster) {
    //设置 ClusterDTO 的创建和修改人为当前管理员
    String operator = userInfoHolder.getUser().getUserId();
    cluster.setDataChangeLastModifiedBy(operator);
    cluster.setDataChangeCreatedBy(operator);
    //创建 Cluster 到 Admin Service
    return clusterService.createCluster(Env.valueOf(env), cluster);
  }
  1. ClusterService#createCluster

这里就是直接远程调用admin server来进行保存了

  public ClusterDTO createCluster(Env env, ClusterDTO cluster) {
    //根据`appId` 和 `name` 校验 Cluster 的唯一性,这里是远程调用Admin Service的api
    if (!clusterAPI.isClusterUnique(cluster.getAppId(), env, cluster.getName())) {
      throw new BadRequestException(String.format("cluster %s already exists.", cluster.getName()));
    }
    //创建 Cluster 到 Admin Service
    ClusterDTO clusterDTO = clusterAPI.create(env, cluster);

    //Trace 日志
    Tracer.logEvent(TracerEventType.CREATE_CLUSTER, cluster.getAppId(), "0", cluster.getName());

    return clusterDTO;
  }

3. CreationListener#onAppNamespaceCreationEvent

AppNamespaceCreationEvents事件的消费者,这里会调用到对应的Admin Service创建AppNamespace对象

  @EventListener
  public void onAppNamespaceCreationEvent(AppNamespaceCreationEvent event) {
    //将AppNamespace 转成 AppNamespaceDTO对象
    AppNamespaceDTO appNamespace = BeanUtils.transform(AppNamespaceDTO.class, event.getAppNamespace());
    //获得有效的 Env 数组
    List<Env> envs = portalSettings.getActiveEnvs();
    //循环 Env 数组,调用对应的Admin Service 的 API ,创建 AppNamespace对象
    for (Env env : envs) {
      try {
        namespaceAPI.createAppNamespace(env, appNamespace);
      } catch (Throwable e) {
        logger.error("Create appNamespace failed. appId = {}, env = {}", appNamespace.getAppId(), env, e);
        Tracer.logError(String.format("Create appNamespace failed. appId = %s, env = %s", appNamespace.getAppId(), env), e);
      }
    }
  }
  1. adminservice模块下的AppNamespaceController#create

这里就是做了唯一性校验,然后就调用servicecreateAppNamespace方法

  @PostMapping("/apps/{appId}/appnamespaces")
  public AppNamespaceDTO create(@RequestBody AppNamespaceDTO appNamespace,
                                @RequestParam(defaultValue = "false") boolean silentCreation) {

    //将 AppNamespaceDTO 转换成 AppNamespace 对象
    AppNamespace entity = BeanUtils.transform(AppNamespace.class, appNamespace);
    // 判断 `name` 在 App 下是否已经存在对应的 AppNamespace 对象。若已经存在,抛出 BadRequestException 异常。
    AppNamespace managedEntity = appNamespaceService.findOne(entity.getAppId(), entity.getName());

    if (managedEntity == null) {
      if (StringUtils.isEmpty(entity.getFormat())){
        entity.setFormat(ConfigFileFormat.Properties.getValue());
      }
      //保存 AppNamespace 对象到数据库
      entity = appNamespaceService.createAppNamespace(entity);
    } else if (silentCreation) {
      appNamespaceService.createNamespaceForAppNamespaceInAllCluster(appNamespace.getAppId(), appNamespace.getName(),
          appNamespace.getDataChangeCreatedBy());

      entity = managedEntity;
    } else {
      throw new BadRequestException("app namespaces already exist.");
    }

    return BeanUtils.transform(AppNamespaceDTO.class, entity);
  }
  1. AppNamespaceService#createAppNamespace

做一下唯一性校验,然后保存AppNamespace到数据,并且给App下的所有Cluster都创建Namespace,最后记录下操作日志

  @Transactional
  public AppNamespace createAppNamespace(AppNamespace appNamespace) {
    //判断 `name` 在 App 下是否已经存在对应的 AppNamespace 对象。若已经存在,抛出异常
    String createBy = appNamespace.getDataChangeCreatedBy();
    if (!isAppNamespaceNameUnique(appNamespace.getAppId(), appNamespace.getName())) {
      throw new ServiceException("appnamespace not unique");
    }
    appNamespace.setId(0);//protection
    appNamespace.setDataChangeCreatedBy(createBy);
    appNamespace.setDataChangeLastModifiedBy(createBy);
    //保存 AppNamespace 到数据
    appNamespace = appNamespaceRepository.save(appNamespace);
     //创建 AppNamespace 在app下每个 Cluster 的Namespace对象
    createNamespaceForAppNamespaceInAllCluster(appNamespace.getAppId(), appNamespace.getName(), createBy);
    //记录 Audit 到数据库
    auditService.audit(AppNamespace.class.getSimpleName(), appNamespace.getId(), Audit.OP.INSERT, createBy);
    return appNamespace;
  }

6. createNamespaceForAppNamespaceInAllCluster方法

这里就是遍历App下的所有Cluster数组,然后创建对应的Namespace

  public void createNamespaceForAppNamespaceInAllCluster(String appId, String namespaceName, String createBy) {
    // 获得 App 下所有的 Cluster 数组
    List<Cluster> clusters = clusterService.findParentClusters(appId);

    // 循环 Cluster 数组, 保存并创建 Namespace 到数据库
    for (Cluster cluster : clusters) {

      // in case there is some dirty data, e.g. public namespace deleted in other app and now created in this app
      if (!namespaceService.isNamespaceUnique(appId, cluster.getName(), namespaceName)) {
        continue;
      }

      Namespace namespace = new Namespace();
      namespace.setClusterName(cluster.getName());
      namespace.setAppId(appId);
      namespace.setNamespaceName(namespaceName);
      namespace.setDataChangeCreatedBy(createBy);
      namespace.setDataChangeLastModifiedBy(createBy);

      namespaceService.save(namespace);
    }
  }
  1. AppNamespace和Namespace的关系图
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值