一、概述
Patrol
创建Namespace
的流程
二、创建流程
1.页面流程
2.代码流程
patrol
模块下的NamespaceController#createAppNamespace
- 保存
AppNamespace
到数据库- 发布
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;
}
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);
}
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);
}
}
}
adminservice
模块下的AppNamespaceController#create
这里就是做了唯一性校验,然后就调用
service
的createAppNamespace
方法
@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);
}
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);
}
}
- AppNamespace和Namespace的关系图