提交 e4572e13 编写于 作者: N nobodyiam

allow users to create missing private namespaces

上级 9655981d
......@@ -31,20 +31,26 @@ public class AppNamespaceController {
private NamespaceService namespaceService;
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST)
public AppNamespaceDTO create(@RequestBody AppNamespaceDTO appNamespace) {
public AppNamespaceDTO create(@RequestBody AppNamespaceDTO appNamespace,
@RequestParam(defaultValue = "false") boolean silentCreation) {
AppNamespace entity = BeanUtils.transfrom(AppNamespace.class, appNamespace);
AppNamespace managedEntity = appNamespaceService.findOne(entity.getAppId(), entity.getName());
if (managedEntity != null) {
throw new BadRequestException("app namespaces already exist.");
}
if (managedEntity == null) {
if (StringUtils.isEmpty(entity.getFormat())){
entity.setFormat(ConfigFileFormat.Properties.getValue());
}
if (StringUtils.isEmpty(entity.getFormat())){
entity.setFormat(ConfigFileFormat.Properties.getValue());
}
entity = appNamespaceService.createAppNamespace(entity);
} else if (silentCreation) {
appNamespaceService.createNamespaceForAppNamespaceInAllCluster(appNamespace.getAppId(), appNamespace.getName(),
appNamespace.getDataChangeCreatedBy());
entity = appNamespaceService.createAppNamespace(entity);
entity = managedEntity;
} else {
throw new BadRequestException("app namespaces already exist.");
}
return BeanUtils.transfrom(AppNamespaceDTO.class, entity);
}
......@@ -72,4 +78,11 @@ public class AppNamespaceController {
return namespaceService.countPublicAppNamespaceAssociatedNamespaces(publicNamespaceName);
}
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.GET)
public List<AppNamespaceDTO> getAppNamespaces(@PathVariable("appId") String appId) {
List<AppNamespace> appNamespaces = appNamespaceService.findByAppId(appId);
return BeanUtils.batchTransform(AppNamespaceDTO.class, appNamespaces);
}
}
......@@ -110,7 +110,7 @@ public class AppNamespaceService {
appNamespace = appNamespaceRepository.save(appNamespace);
instanceOfAppNamespaceInAllCluster(appNamespace.getAppId(), appNamespace.getName(), createBy);
createNamespaceForAppNamespaceInAllCluster(appNamespace.getAppId(), appNamespace.getName(), createBy);
auditService.audit(AppNamespace.class.getSimpleName(), appNamespace.getId(), Audit.OP.INSERT, createBy);
return appNamespace;
......@@ -127,7 +127,7 @@ public class AppNamespaceService {
return managedNs;
}
private void instanceOfAppNamespaceInAllCluster(String appId, String namespaceName, String createBy) {
public void createNamespaceForAppNamespaceInAllCluster(String appId, String namespaceName, String createBy) {
List<Cluster> clusters = clusterService.findParentClusters(appId);
for (Cluster cluster : clusters) {
......
......@@ -105,6 +105,17 @@ public class AdminServiceAPI {
.post(env, "apps/{appId}/appnamespaces", appNamespace, AppNamespaceDTO.class, appNamespace.getAppId());
}
public AppNamespaceDTO createMissingAppNamespace(Env env, AppNamespaceDTO appNamespace) {
return restTemplate
.post(env, "apps/{appId}/appnamespaces?silentCreation=true", appNamespace, AppNamespaceDTO.class,
appNamespace.getAppId());
}
public List<AppNamespaceDTO> getAppNamespaces(String appId, Env env) {
AppNamespaceDTO[] appNamespaceDTOs = restTemplate.get(env, "apps/{appId}/appnamespaces", AppNamespaceDTO[].class, appId);
return Arrays.asList(appNamespaceDTOs);
}
public void deleteNamespace(Env env, String appId, String clusterName, String namespaceName, String operator) {
restTemplate
.delete(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}?operator={operator}", appId,
......
package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
import com.ctrip.framework.apollo.common.http.MultiResponseEntity;
import com.ctrip.framework.apollo.common.http.RichResponseEntity;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.listener.AppNamespaceDeletionEvent;
import com.google.common.collect.Sets;
......@@ -25,6 +28,8 @@ import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.util.RoleUtils;
import com.ctrip.framework.apollo.tracer.Tracer;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -65,6 +70,8 @@ public class NamespaceController {
private PortalConfig portalConfig;
@Autowired
private PermissionValidator permissionValidator;
@Autowired
private AdminServiceAPI.NamespaceAPI namespaceAPI;
@RequestMapping(value = "/appnamespaces/public", method = RequestMethod.GET)
......@@ -222,6 +229,61 @@ public class NamespaceController {
}
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/missing-namespaces", method = RequestMethod.GET)
public MultiResponseEntity<String> findMissingNamespaces(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName) {
MultiResponseEntity<String> response = MultiResponseEntity.ok();
Set<String> missingNamespaces = findMissingNamespaceNames(appId, env, clusterName);
for (String missingNamespace : missingNamespaces) {
response.addResponseEntity(RichResponseEntity.ok(missingNamespace));
}
return response;
}
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/missing-namespaces", method = RequestMethod.POST)
public ResponseEntity<Void> createMissingNamespaces(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName) {
Set<String> missingNamespaces = findMissingNamespaceNames(appId, env, clusterName);
for (String missingNamespace : missingNamespaces) {
namespaceAPI.createMissingAppNamespace(Env.fromString(env), findAppNamespace(appId, missingNamespace));
}
return ResponseEntity.ok().build();
}
private Set<String> findMissingNamespaceNames(String appId, String env, String clusterName) {
List<AppNamespaceDTO> configDbAppNamespaces = namespaceAPI.getAppNamespaces(appId, Env.fromString(env));
List<NamespaceDTO> configDbNamespaces = namespaceService.findNamespaces(appId, Env.fromString(env), clusterName);
List<AppNamespace> portalDbAppNamespaces = appNamespaceService.findByAppId(appId);
Set<String> configDbAppNamespaceNames = configDbAppNamespaces.stream().map(AppNamespaceDTO::getName)
.collect(Collectors.toSet());
Set<String> configDbNamespaceNames = configDbNamespaces.stream().map(NamespaceDTO::getNamespaceName)
.collect(Collectors.toSet());
Set<String> portalDbAllAppNamespaceNames = Sets.newHashSet();
Set<String> portalDbPrivateAppNamespaceNames = Sets.newHashSet();
for (AppNamespace appNamespace : portalDbAppNamespaces) {
portalDbAllAppNamespaceNames.add(appNamespace.getName());
if (!appNamespace.isPublic()) {
portalDbPrivateAppNamespaceNames.add(appNamespace.getName());
}
}
// AppNamespaces should be the same
Set<String> missingAppNamespaceNames = Sets.difference(portalDbAllAppNamespaceNames, configDbAppNamespaceNames);
// Private namespaces should all exist
Set<String> missingNamespaceNames = Sets.difference(portalDbPrivateAppNamespaceNames, configDbNamespaceNames);
return Sets.union(missingAppNamespaceNames, missingNamespaceNames);
}
private void assignNamespaceRoleToOperator(String appId, String namespaceName) {
//default assign modify、release namespace role to namespace creator
String operator = userInfoHolder.getUser().getUserId();
......
......@@ -16,6 +16,8 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository<AppNa
List<AppNamespace> findByIsPublicTrue();
List<AppNamespace> findByAppId(String appId);
@Modifying
@Query("UPDATE AppNamespace SET IsDeleted=1,DataChange_LastModifiedBy=?2 WHERE AppId=?1")
int batchDeleteByAppId(String appId, String operator);
......
......@@ -62,6 +62,10 @@ public class AppNamespaceService {
return appNamespaceRepository.findByAppIdAndName(appId, namespaceName);
}
public List<AppNamespace> findByAppId(String appId) {
return appNamespaceRepository.findByAppId(appId);
}
@Transactional
public void createDefaultAppNamespace(String appId) {
if (!isAppNamespaceNameUnique(appId, ConfigConsts.NAMESPACE_APPLICATION)) {
......
......@@ -133,6 +133,10 @@ public class NamespaceService {
return namespaceBOs;
}
public List<NamespaceDTO> findNamespaces(String appId, Env env, String clusterName) {
return namespaceAPI.findNamespaceByCluster(appId, env, clusterName);
}
public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(Env env, String publicNamespaceName, int page,
int size) {
return namespaceAPI.getPublicAppNamespaceAllNamespaces(env, publicNamespaceName, page, size);
......
......@@ -99,6 +99,13 @@
</span>
</td>
</tr>
<tr ng-show="missingNamespaces.length > 0">
<th>缺失的Namespace:</th>
<td>
<span ng-repeat="namespace in missingNamespaces" ng-bind="namespace">
</span>
</td>
</tr>
</tbody>
</table>
......@@ -116,6 +123,12 @@
</div>
</a>
<a class="list-group-item" ng-show="missingNamespaces.length > 0" ng-click="createMissingNamespaces()">
<div class="row icon-text icon-plus-orange">
<p class="btn-title ng-binding">补缺Namespace</p>
</div>
</a>
<apolloentrance apollo-title="'添加集群'" apollo-img-src="'plus-orange'"
apollo-href="'cluster.html?#/appid=' + pageContext.appId"
ng-show="hasCreateClusterPermission"></apolloentrance>
......
......@@ -89,13 +89,41 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
});
};
$scope.createMissingNamespaces = function () {
AppService.create_missing_namespaces($rootScope.pageContext.appId, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName).then(function (result) {
toastr.success("创建成功");
location.reload(true);
}, function (result) {
toastr.error(AppUtil.errorMsg(result), "创建失败");
}
);
};
function findMissEnvs() {
$scope.missEnvs = [];
AppService.find_miss_envs($rootScope.pageContext.appId).then(function (result) {
$scope.missEnvs = AppUtil.collectData(result);
});
$scope.findMissingNamespaces();
});
}
EventManager.subscribe(EventManager.EventType.CHANGE_ENV_CLUSTER, function () {
$scope.findMissingNamespaces();
});
$scope.findMissingNamespaces = function () {
$scope.missingNamespaces = [];
// only check missing private namespaces when app exists in current env
if ($scope.missEnvs.indexOf($rootScope.pageContext.env) === -1) {
AppService.find_missing_namespaces($rootScope.pageContext.appId, $rootScope.pageContext.env,
$rootScope.pageContext.clusterName).then(function (result) {
$scope.missingNamespaces = AppUtil.collectData(result);
});
}
};
function recordVisitApp() {
//save user recent visited apps
var VISITED_APPS_STORAGE_KEY = "VisitedAppsV2";
......@@ -229,6 +257,7 @@ function ConfigBaseInfoController($rootScope, $scope, $window, $location, toastr
+ "&cluster=" + $rootScope.pageContext.clusterName;
EventManager.emit(EventManager.EventType.REFRESH_NAMESPACE);
EventManager.emit(EventManager.EventType.CHANGE_ENV_CLUSTER);
$rootScope.showSideBar = false;
}
});
......
......@@ -35,6 +35,14 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
method: 'GET',
url: '/apps/:appId/miss_envs'
},
create_missing_namespaces: {
method: 'POST',
url: '/apps/:appId/envs/:env/clusters/:clusterName/missing-namespaces'
},
find_missing_namespaces: {
method: 'GET',
url: '/apps/:appId/envs/:env/clusters/:clusterName/missing-namespaces'
},
delete_app: {
method: 'DELETE',
isArray: false
......@@ -128,6 +136,32 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
});
return d.promise;
},
create_missing_namespaces: function (appId, env, clusterName) {
var d = $q.defer();
app_resource.create_missing_namespaces({
appId: appId,
env: env,
clusterName: clusterName
}, null, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
},
find_missing_namespaces: function (appId, env, clusterName) {
var d = $q.defer();
app_resource.find_missing_namespaces({
appId: appId,
env: env,
clusterName: clusterName
}, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
},
delete_app: function (appId) {
var d = $q.defer();
app_resource.delete_app({
......
......@@ -136,7 +136,8 @@ appService.service('EventManager', [function () {
EMERGENCY_PUBLISH: 'emergency_publish',
PRE_DELETE_NAMESPACE: 'pre_delete_namespace',
DELETE_NAMESPACE: 'delete_namespace',
DELETE_NAMESPACE_FAILED: 'delete_namespace_failed'
DELETE_NAMESPACE_FAILED: 'delete_namespace_failed',
CHANGE_ENV_CLUSTER: "change_env_cluster"
}
}
......
......@@ -298,7 +298,7 @@ table th {
.project-info th {
text-align: right;
padding: 4px 6px;
white-space: nowrap;
width: 5em;
}
.project-info td {
......@@ -306,6 +306,10 @@ table th {
padding: 4px 6px;
}
.project-info td span {
margin-right: 5px;
}
#config-info {
min-height: 500px;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册