未验证 提交 1cf49996 编写于 作者: J Jason Song 提交者: GitHub

Merge pull request #1279 from nobodyiam/delete-app-cluster-namespace-page

add admin page to delete app, cluster and app namespace
......@@ -52,9 +52,14 @@ public class ClusterController {
@RequestMapping(value = "apps/{appId}/envs/{env}/clusters/{clusterName:.+}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deleteCluster(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName){
clusterService.deleteCluster(Env.valueOf(env), appId, clusterName);
clusterService.deleteCluster(Env.fromString(env), appId, clusterName);
return ResponseEntity.ok().build();
}
@RequestMapping(value = "apps/{appId}/envs/{env}/clusters/{clusterName:.+}", method = RequestMethod.GET)
public ClusterDTO loadCluster(@PathVariable("appId") String appId, @PathVariable String env, @PathVariable("clusterName") String clusterName) {
return clusterService.loadCluster(appId, Env.fromString(env), clusterName);
}
}
package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.portal.listener.AppNamespaceDeletionEvent;
import com.google.common.collect.Sets;
......@@ -144,6 +146,18 @@ public class NamespaceController {
return ResponseEntity.ok().build();
}
@RequestMapping(value = "/apps/{appId}/appnamespaces/{namespaceName:.+}", method = RequestMethod.GET)
public AppNamespaceDTO findAppNamespace(@PathVariable String appId, @PathVariable String namespaceName) {
AppNamespace appNamespace = appNamespaceService.findByAppIdAndName(appId, namespaceName);
if (appNamespace == null) {
throw new BadRequestException(
String.format("AppNamespace not exists. AppId = %s, NamespaceName = %s", appId, namespaceName));
}
return BeanUtils.transfrom(AppNamespaceDTO.class, appNamespace);
}
@PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)")
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST)
public AppNamespace createAppNamespace(@PathVariable String appId, @RequestBody AppNamespace appNamespace) {
......
......@@ -74,26 +74,22 @@ public class NamespaceService {
@Transactional
public void deleteNamespace(String appId, Env env, String clusterName, String namespaceName) {
//1. check private namespace
AppNamespace appNamespace = appNamespaceService.findByAppIdAndName(appId, namespaceName);
if (appNamespace != null && !appNamespace.isPublic()) {
throw new BadRequestException("Private namespace can not be deleted");
}
//2. check parent namespace has not instances
//1. check parent namespace has not instances
if (namespaceHasInstances(appId, env, clusterName, namespaceName)) {
throw new BadRequestException("Can not delete namespace because namespace has active instances");
}
//3. check child namespace has not instances
//2. check child namespace has not instances
NamespaceDTO childNamespace = branchService.findBranchBaseInfo(appId, env, clusterName, namespaceName);
if (childNamespace != null &&
namespaceHasInstances(appId, env, childNamespace.getClusterName(), namespaceName)) {
throw new BadRequestException("Can not delete namespace because namespace's branch has active instances");
}
//4. check public namespace has not associated namespace
if (appNamespace != null && publicAppNamespaceHasAssociatedNamespace(namespaceName, env)) {
//3. check public namespace has not associated namespace
if (appNamespace != null && appNamespace.isPublic() && publicAppNamespaceHasAssociatedNamespace(namespaceName, env)) {
throw new BadRequestException("Can not delete public namespace which has associated namespaces");
}
......
......@@ -288,8 +288,7 @@
apollo-detail="'发现有 <b>' + deleteNamespaceContext.namespace.instancesCount +
'</b> 个实例正在使用Namespace(' + deleteNamespaceContext.namespace.baseInfo.namespaceName +
'),删除Namespace将导致实例获取不到配置。<br>
请到 <ins>“实例列表”</ins> 确认实例信息,如已确认删除Namespace将不会导致实例异常,
请联系Apollo相关负责人删除Namespace'"
请到 <ins>“实例列表”</ins> 确认实例信息,如确认相关实例都已经不再使用该Namespace配置,可以联系Apollo相关负责人删除实例信息(InstanceConfig)或等待实例24小时自动过期后再来删除。'"
apollo-confirm="continueDeleteNamespace">
</apolloconfirmdialog>
......@@ -298,8 +297,7 @@
apollo-detail="'发现有 <b>' + deleteNamespaceContext.namespace.branch.latestReleaseInstances.total
+ '</b> 个实例正在使用Namespace(' + deleteNamespaceContext.namespace.baseInfo.namespaceName +
')灰度版本的配置,删除Namespace将导致实例获取不到配置。<br>
请到 <ins>“灰度版本” => “实例列表”</ins> 确认实例信息,如已确认删除Namespace将不会导致实例异常,
请联系Apollo相关负责人删除Namespace'"
请到 <ins>“灰度版本” => “实例列表”</ins> 确认实例信息,如确认相关实例都已经不再使用该Namespace配置,可以联系Apollo相关负责人删除实例信息(InstanceConfig)或等待实例24小时自动过期后再来删除。'"
apollo-confirm="continueDeleteNamespace">
</apolloconfirmdialog>
......
<!doctype html>
<html ng-app="delete_app_cluster_namespace">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="icon" href="../img/config.png">
<!-- styles -->
<link rel="stylesheet" type="text/css" href="../vendor/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../vendor/angular/angular-toastr-1.4.1.min.css">
<link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
<link rel="stylesheet" type="text/css" href="../styles/common-style.css">
<link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
<title>删除应用、集群、AppNamespace</title>
</head>
<body>
<apollonav></apollonav>
<div class="container-fluid" ng-controller="DeleteAppClusterNamespaceController">
<div class="col-md-10 col-md-offset-1 panel">
<section class="panel-body" ng-show="isRootUser">
<!-- delete app -->
<section class="row">
<h5>删除应用
<small>
(由于删除应用影响面较大,所以现在暂时只允许系统管理员删除,请确保没有客户端读取该应用的配置后再做删除动作)
</small>
</h5>
<hr>
<form class="form-horizontal">
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
应用AppId</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="app.appId">
<small>(删除前请先查询应用信息)</small>
</div>
<div class="col-sm-1">
<button class="btn btn-info" ng-click="getAppInfo()">查询</button>
</div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
应用信息</label>
<div class="col-sm-5">
<h5 ng-show="app.info" ng-bind="app.info"></h5>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary"
ng-disabled="deleteAppBtnDisabled"
ng-click="deleteApp()">
删除应用
</button>
</div>
</div>
</form>
</section>
<!-- delete cluster -->
<section class="row">
<h5>删除集群
<small>
(由于删除集群影响面较大,所以现在暂时只允许系统管理员删除,请确保没有客户端读取该集群的配置后再做删除动作)
</small>
</h5>
<hr>
<form class="form-horizontal">
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
应用AppId</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="cluster.appId">
</div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
环境名称</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="cluster.env">
</div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
集群名称</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="cluster.name">
<small>(删除前请先查询应用集群信息)</small>
</div>
<div class="col-sm-1">
<button class="btn btn-info" ng-click="getClusterInfo()">查询</button>
</div>
</div>
<div class="form-group" viv clform-group>
<label class="col-sm-2 control-label">
集群信息</label>
<div class="col-sm-5">
<h5 ng-show="cluster.info" ng-bind="cluster.info"></h5>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary"
ng-disabled="deleteClusterBtnDisabled"
ng-click="deleteCluster()">
删除集群
</button>
</div>
</div>
</form>
</section>
<!-- delete app namespace -->
<section class="row">
<h5>删除AppNamespace
<small>(注意,所有环境的Namespace和AppNamespace都会被删除!如果只是要删除某个环境的Namespace,让用户到项目页面中自行删除!)</small>
</h5>
<small>
目前用户可以自行删除关联的Namespace和私有的Namespace,不过无法删除AppNamespace元信息,因为删除AppNamespace影响面较大,所以现在暂时只允许系统管理员删除,对于公共Namespace需要确保没有应用关联了该AppNamespace。
</small>
<hr>
<form class="form-horizontal">
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
应用AppId</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="appNamespace.appId">
</div>
</div>
<div class="form-group" valdr-form-group>
<label class="col-sm-2 control-label">
<apollorequiredfield></apollorequiredfield>
AppNamespace名称</label>
<div class="col-sm-5">
<input type="text" class="form-control" ng-model="appNamespace.name">
<small>(非properties类型的namespace请加上类型后缀,例如apollo.xml)</small>
</div>
<div class="col-sm-1">
<button class="btn btn-info" ng-click="getAppNamespaceInfo()">查询</button>
</div>
</div>
<div class="form-group" viv clform-group>
<label class="col-sm-2 control-label">
集群信息</label>
<div class="col-sm-5">
<h5 ng-show="appNamespace.info" ng-bind="appNamespace.info"></h5>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-9">
<button type="submit" class="btn btn-primary"
ng-disabled="deleteAppNamespaceBtnDisabled"
ng-click="deleteAppNamespace()">
删除AppNamespace
</button>
</div>
</div>
</form>
</section>
</section>
<section class="panel-body text-center" ng-if="!isRootUser">
<h4>当前页面只对Apollo管理员开放</h4>
</section>
</div>
</div>
<div ng-include="'../views/common/footer.html'"></div>
<!-- jquery.js -->
<script src="../vendor/jquery.min.js" type="text/javascript"></script>
<!--angular-->
<script src="../vendor/angular/angular.min.js"></script>
<script src="../vendor/angular/angular-route.min.js"></script>
<script src="../vendor/angular/angular-resource.min.js"></script>
<script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
<script src="../vendor/angular/loading-bar.min.js"></script>
<!--valdr-->
<script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
<script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
<!-- bootstrap.js -->
<script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<!--nicescroll-->
<script src="../vendor/jquery.nicescroll.min.js"></script>
<script src="../vendor/lodash.min.js"></script>
<script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
<!--biz-->
<!--must import-->
<script type="application/javascript" src="../scripts/app.js"></script>
<script type="application/javascript" src="../scripts/services/AppService.js"></script>
<script type="application/javascript" src="../scripts/services/EnvService.js"></script>
<script type="application/javascript" src="../scripts/services/UserService.js"></script>
<script type="application/javascript" src="../scripts/services/CommonService.js"></script>
<script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
<script type="application/javascript" src="../scripts/services/ClusterService.js"></script>
<script type="application/javascript" src="../scripts/services/NamespaceService.js"></script>
<script type="application/javascript" src="../scripts/AppUtils.js"></script>
<script type="application/javascript" src="../scripts/PageCommon.js"></script>
<script type="application/javascript" src="../scripts/directive/directive.js"></script>
<script type="application/javascript" src="../scripts/valdr.js"></script>
<script type="application/javascript" src="../scripts/controller/DeleteAppClusterNamespaceController.js"></script>
</body>
</html>
......@@ -34,6 +34,5 @@ var open_manage_module = angular.module('open_manage', ['app.service', 'apollo.d
var user_module = angular.module('user', ['apollo.directive', 'toastr', 'app.service', 'app.util', 'angular-loading-bar', 'valdr']);
//login
var login_module = angular.module('login', ['toastr', 'app.util']);
//delete app cluster namespace
var delete_app_cluster_namespace_module = angular.module('delete_app_cluster_namespace', ['app.service', 'apollo.directive', 'app.util', 'toastr', 'angular-loading-bar']);
delete_app_cluster_namespace_module.controller('DeleteAppClusterNamespaceController',
['$scope', 'toastr', 'AppUtil', 'AppService', 'ClusterService', 'NamespaceService', 'PermissionService',
DeleteAppClusterNamespaceController]);
function DeleteAppClusterNamespaceController($scope, toastr, AppUtil, AppService, ClusterService, NamespaceService, PermissionService) {
$scope.app = {};
$scope.deleteAppBtnDisabled = true;
$scope.getAppInfo = getAppInfo;
$scope.deleteApp = deleteApp;
$scope.cluster = {};
$scope.deleteClusterBtnDisabled = true;
$scope.getClusterInfo = getClusterInfo;
$scope.deleteCluster = deleteCluster;
$scope.appNamespace = {};
$scope.deleteAppNamespaceBtnDisabled = true;
$scope.getAppNamespaceInfo = getAppNamespaceInfo;
$scope.deleteAppNamespace = deleteAppNamespace;
initPermission();
function initPermission() {
PermissionService.has_root_permission()
.then(function (result) {
$scope.isRootUser = result.hasPermission;
})
}
function getAppInfo() {
if (!$scope.app.appId) {
toastr.warning("请输入appId");
return;
}
$scope.app.info = "";
AppService.load($scope.app.appId).then(function (result) {
if (!result.appId) {
toastr.warning("AppId: " + $scope.app.appId + " 不存在!");
$scope.deleteAppBtnDisabled = true;
return;
}
$scope.app.info = "应用名:" + result.name + " 部门:" + result.orgName + '(' + result.orgId + ')' + " 负责人:" + result.ownerName;
$scope.deleteAppBtnDisabled = false;
}, function (result) {
AppUtil.showErrorMsg(result);
});
}
function deleteApp() {
if (!$scope.app.appId) {
toastr.warning("请输入appId");
return;
}
if (confirm("确认删除AppId: " + $scope.app.appId + "")) {
AppService.delete_app($scope.app.appId).then(function (result) {
toastr.success("删除成功");
$scope.deleteAppBtnDisabled = true;
}, function (result) {
AppUtil.showErrorMsg(result);
})
}
}
function getClusterInfo() {
if (!$scope.cluster.appId || !$scope.cluster.env || !$scope.cluster.name) {
toastr.warning("请输入appId、环境和集群名称");
return;
}
$scope.cluster.info = "";
ClusterService.load_cluster($scope.cluster.appId, $scope.cluster.env, $scope.cluster.name).then(function (result) {
$scope.cluster.info = "AppId:" + result.appId+ " 环境:" + $scope.cluster.env + " 集群名称:" + result.name;
$scope.deleteClusterBtnDisabled = false;
}, function (result) {
AppUtil.showErrorMsg(result);
});
}
function deleteCluster() {
if (!$scope.cluster.appId || !$scope.cluster.env || !$scope.cluster.name) {
toastr.warning("请输入appId、环境和集群名称");
return;
}
if (confirm("确认删除集群?appId: " + $scope.cluster.appId + " 环境:" + $scope.cluster.env + " 集群名称:" + $scope.cluster.name)) {
ClusterService.delete_cluster($scope.cluster.appId, $scope.cluster.env, $scope.cluster.name).then(function (result) {
toastr.success("删除成功");
$scope.deleteClusterBtnDisabled = true;
}, function (result) {
AppUtil.showErrorMsg(result);
})
}
}
function getAppNamespaceInfo() {
if (!$scope.appNamespace.appId || !$scope.appNamespace.name) {
toastr.warning("请输入appId和AppNamespace名称");
return;
}
$scope.appNamespace.info = "";
NamespaceService.loadAppNamespace($scope.appNamespace.appId, $scope.appNamespace.name).then(function (result) {
$scope.appNamespace.info = "AppId:" + result.appId+ " AppNamespace名称:" + result.name + " isPublic:" + result.isPublic;
$scope.deleteAppNamespaceBtnDisabled = false;
}, function (result) {
AppUtil.showErrorMsg(result);
});
}
function deleteAppNamespace() {
if (!$scope.appNamespace.appId || !$scope.appNamespace.name) {
toastr.warning("请输入appId和AppNamespace名称");
return;
}
if (confirm("确认删除所有环境的AppNamespace和Namespace?appId: " + $scope.appNamespace.appId + " 环境:所有环境" + " AppNamespace名称:" + $scope.appNamespace.name)) {
NamespaceService.deleteAppNamespace($scope.appNamespace.appId, $scope.appNamespace.name).then(function (result) {
toastr.success("删除成功");
$scope.deleteAppNamespaceBtnDisabled = true;
}, function (result) {
AppUtil.showErrorMsg(result);
})
}
}
}
......@@ -18,25 +18,20 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
var toDeleteNamespace = context.namespace;
scope.toDeleteNamespace = toDeleteNamespace;
//1. check namespace is not private
if (!checkNotPrivateNamespace(toDeleteNamespace)) {
return;
}
//2. check operator has master permission
//1. check operator has master permission
checkPermission(toDeleteNamespace).then(function () {
//3. check namespace's master branch has not instances
//2. check namespace's master branch has not instances
if (!checkMasterInstance(toDeleteNamespace)) {
return;
}
//4. check namespace's gray branch has not instances
//3. check namespace's gray branch has not instances
if (!checkBranchInstance(toDeleteNamespace)) {
return;
}
if (toDeleteNamespace.isLinkedNamespace) {
if (!toDeleteNamespace.isPublic || toDeleteNamespace.isLinkedNamespace) {
showDeleteNamespaceConfirmDialog();
} else {
//5. check public namespace has not associated namespace
......@@ -48,15 +43,6 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
});
function checkNotPrivateNamespace(namespace) {
if (!namespace.isPublic) {
toastr.error("不能删除私有的Namespace", "删除失败");
return false;
}
return true;
}
function checkPermission(namespace) {
var d = $q.defer();
......@@ -153,7 +139,6 @@ function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManage
function showDeleteNamespaceConfirmDialog() {
AppUtil.showModal('#deleteNamespaceModal');
}
function doDeleteNamespace() {
......
......@@ -34,6 +34,10 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
find_miss_envs: {
method: 'GET',
url: '/apps/:appId/miss_envs'
},
delete_app: {
method: 'DELETE',
isArray: false
}
});
return {
......@@ -123,6 +127,17 @@ appService.service('AppService', ['$resource', '$q', function ($resource, $q) {
d.reject(result);
});
return d.promise;
},
delete_app: function (appId) {
var d = $q.defer();
app_resource.delete_app({
appId: appId
}, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
}
}
}]);
......@@ -3,6 +3,14 @@ appService.service('ClusterService', ['$resource', '$q', function ($resource, $q
create_cluster: {
method: 'POST',
url: 'apps/:appId/envs/:env/clusters'
},
load_cluster: {
method: 'GET',
url: 'apps/:appId/envs/:env/clusters/:clusterName'
},
delete_cluster: {
method: 'DELETE',
url: 'apps/:appId/envs/:env/clusters/:clusterName'
}
});
return {
......@@ -18,6 +26,34 @@ appService.service('ClusterService', ['$resource', '$q', function ($resource, $q
d.reject(result);
});
return d.promise;
},
load_cluster: function (appId, env, clusterName) {
var d = $q.defer();
cluster_resource.load_cluster({
appId: appId,
env: env,
clusterName: clusterName
},
function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
},
delete_cluster: function (appId, env, clusterName) {
var d = $q.defer();
cluster_resource.delete_cluster({
appId: appId,
env: env,
clusterName: clusterName
},
function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
}
}
}]);
......@@ -27,6 +27,14 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
method: 'GET',
url: '/envs/:env/appnamespaces/:publicNamespaceName/namespaces',
isArray: true
},
loadAppNamespace: {
method: 'GET',
url: '/apps/:appId/appnamespaces/:namespaceName'
},
deleteAppNamespace: {
method: 'DELETE',
url: '/apps/:appId/appnamespaces/:namespaceName'
}
});
......@@ -112,13 +120,47 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
}
function loadAppNamespace(appId, namespaceName) {
var d = $q.defer();
namespace_source.loadAppNamespace({
appId: appId,
namespaceName: namespaceName
},
function (result) {
d.resolve(result);
},
function (result) {
d.reject(result);
});
return d.promise;
}
function deleteAppNamespace(appId, namespaceName) {
var d = $q.defer();
namespace_source.deleteAppNamespace({
appId: appId,
namespaceName: namespaceName
},
function (result) {
d.resolve(result);
},
function (result) {
d.reject(result);
});
return d.promise;
}
return {
find_public_namespaces: find_public_namespaces,
createNamespace: createNamespace,
createAppNamespace: createAppNamespace,
getNamespacePublishInfo: getNamespacePublishInfo,
deleteNamespace: deleteNamespace,
getPublicAppNamespaceAllNamespaces: getPublicAppNamespaceAllNamespaces
getPublicAppNamespaceAllNamespaces: getPublicAppNamespaceAllNamespaces,
loadAppNamespace: loadAppNamespace,
deleteAppNamespace: deleteAppNamespace
}
}]);
......@@ -33,6 +33,7 @@
<li><a href="/user-manage.html" target="_blank">用户管理</a></li>
<li><a href="/open/manage.html" target="_blank">开放平台授权管理</a></li>
<li><a href="/server_config.html" target="_blank">系统参数</a></li>
<li><a href="/delete_app_cluster_namespace.html" target="_blank">删除应用、集群、AppNamespace</a></li>
</ul>
</li>
<li class="dropdown">
......
......@@ -8,9 +8,12 @@
删除Namespace
</h4>
</div>
<div class="modal-body form-horizontal">
<div class="modal-body form-horizontal" ng-show="toDeleteNamespace.isPublic">
删除Namespace将导致实例获取不到此Namespace的配置,确定要删除吗?
</div>
<div class="modal-body form-horizontal" ng-show="!toDeleteNamespace.isPublic">
删除私有Namespace将导致实例获取不到此Namespace的配置,而且无法在当前集群重新创建该Namespace(除非使用管理员工具把所有环境的AppNamespace删除后重建),确定要删除吗?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
取消
......
......@@ -111,13 +111,18 @@ public class NamespaceServiceTest extends AbstractUnitTest {
}
@Test(expected = BadRequestException.class)
@Test
public void testDeletePrivateNamespace() {
String operator = "user";
AppNamespace privateNamespace = createAppNamespace(testAppId, testNamespaceName, false);
when(appNamespaceService.findByAppIdAndName(testAppId, testNamespaceName)).thenReturn(privateNamespace);
when(userInfoHolder.getUser()).thenReturn(createUser(operator));
namespaceService.deleteNamespace(testAppId, testEnv, testClusterName, testNamespaceName);
verify(namespaceAPI, times(1)).deleteNamespace(testEnv, testAppId, testClusterName, testNamespaceName, operator);
}
@Test(expected = BadRequestException.class)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册