Skip to content

Commit

Permalink
allow users to create missing private namespaces
Browse files Browse the repository at this point in the history
  • Loading branch information
nobodyiam committed Nov 25, 2018
1 parent 9655981 commit e4572e1
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -72,4 +78,11 @@ public int countPublicAppNamespaceAssociatedNamespaces(@PathVariable String publ
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public AppNamespace createAppNamespace(AppNamespace appNamespace) {

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;
Expand All @@ -127,7 +127,7 @@ public AppNamespace update(AppNamespace appNamespace) {
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ public AppNamespaceDTO createAppNamespace(Env env, AppNamespaceDTO appNamespace)
.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,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
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;
Expand All @@ -25,6 +28,8 @@
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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -222,6 +229,61 @@ public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(@PathVariable Strin

}

@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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ public AppNamespace findByAppIdAndName(String appId, String namespaceName) {
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)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ public List<NamespaceBO> findNamespaceBOs(String appId, Env env, String clusterN
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);
Expand Down
13 changes: 13 additions & 0 deletions apollo-portal/src/main/resources/static/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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;
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,14 +298,18 @@ table th {
.project-info th {
text-align: right;
padding: 4px 6px;
white-space: nowrap;
width: 5em;
}

.project-info td {
border-bottom: 1px dotted gray;
padding: 4px 6px;
}

.project-info td span {
margin-right: 5px;
}

#config-info {
min-height: 500px;
}
Expand Down

0 comments on commit e4572e1

Please sign in to comment.