Commit a684730f authored by lepdou's avatar lepdou

delete namespace

parent 202363b5
package com.ctrip.framework.apollo.adminservice.controller; package com.ctrip.framework.apollo.adminservice.controller;
import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.service.AppNamespaceService; import com.ctrip.framework.apollo.biz.service.AppNamespaceService;
import com.ctrip.framework.apollo.biz.service.NamespaceService;
import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO; import com.ctrip.framework.apollo.common.dto.AppNamespaceDTO;
import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
import com.ctrip.framework.apollo.common.entity.AppNamespace; import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.common.utils.BeanUtils;
...@@ -9,16 +12,22 @@ import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; ...@@ -9,16 +12,22 @@ import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController @RestController
public class AppNamespaceController { public class AppNamespaceController {
@Autowired @Autowired
private AppNamespaceService appNamespaceService; private AppNamespaceService appNamespaceService;
@Autowired
private NamespaceService namespaceService;
@RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST) @RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST)
public AppNamespaceDTO create(@RequestBody AppNamespaceDTO appNamespace) { public AppNamespaceDTO create(@RequestBody AppNamespaceDTO appNamespace) {
...@@ -40,4 +49,17 @@ public class AppNamespaceController { ...@@ -40,4 +49,17 @@ public class AppNamespaceController {
} }
@RequestMapping(value = "/appnamespaces/{publicNamespaceName}/namespaces", method = RequestMethod.GET)
public List<NamespaceDTO> findPublicAppNamespaceAllNamespaces(@PathVariable String publicNamespaceName, Pageable pageable) {
List<Namespace> namespaces = namespaceService.findPublicAppNamespaceAllNamespaces(publicNamespaceName, pageable);
return BeanUtils.batchTransform(NamespaceDTO.class, namespaces);
}
@RequestMapping(value = "/appnamespaces/{publicNamespaceName}/associated-namespaces/count", method = RequestMethod.GET)
public int countPublicAppNamespaceAssociatedNamespaces(@PathVariable String publicNamespaceName) {
return namespaceService.countPublicAppNamespaceAssociatedNamespaces(publicNamespaceName);
}
} }
...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.biz.repository; ...@@ -2,6 +2,8 @@ package com.ctrip.framework.apollo.biz.repository;
import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.biz.entity.Namespace;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
...@@ -19,4 +21,9 @@ public interface NamespaceRepository extends PagingAndSortingRepository<Namespac ...@@ -19,4 +21,9 @@ public interface NamespaceRepository extends PagingAndSortingRepository<Namespac
int batchDelete(String appId, String clusterName, String operator); int batchDelete(String appId, String clusterName, String operator);
List<Namespace> findByAppIdAndNamespaceName(String appId, String namespaceName); List<Namespace> findByAppIdAndNamespaceName(String appId, String namespaceName);
List<Namespace> findByNamespaceName(String namespaceName, Pageable page);
int countByNamespaceNameAndAppIdNot(String namespaceName, String appId);
} }
...@@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.biz.entity.Cluster; ...@@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.biz.entity.Cluster;
import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.repository.AppNamespaceRepository; import com.ctrip.framework.apollo.biz.repository.AppNamespaceRepository;
import com.ctrip.framework.apollo.common.entity.AppNamespace; import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.exception.ServiceException; import com.ctrip.framework.apollo.common.exception.ServiceException;
import com.ctrip.framework.apollo.common.utils.BeanUtils; import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
...@@ -54,12 +55,13 @@ public class AppNamespaceService { ...@@ -54,12 +55,13 @@ public class AppNamespaceService {
return appNamespaceRepository.findByNameInAndIsPublicTrue(namespaceNames); return appNamespaceRepository.findByNameInAndIsPublicTrue(namespaceNames);
} }
public List<AppNamespace> findPrivateAppNamespace(String appId){ public List<AppNamespace> findPrivateAppNamespace(String appId) {
return appNamespaceRepository.findByAppIdAndIsPublic(appId, false); return appNamespaceRepository.findByAppIdAndIsPublic(appId, false);
} }
public AppNamespace findOne(String appId, String namespaceName){ public AppNamespace findOne(String appId, String namespaceName) {
Preconditions.checkArgument(!StringUtils.isContainEmpty(appId, namespaceName), "appId or Namespace must not be null"); Preconditions
.checkArgument(!StringUtils.isContainEmpty(appId, namespaceName), "appId or Namespace must not be null");
return appNamespaceRepository.findByAppIdAndName(appId, namespaceName); return appNamespaceRepository.findByAppIdAndName(appId, namespaceName);
} }
...@@ -90,7 +92,7 @@ public class AppNamespaceService { ...@@ -90,7 +92,7 @@ public class AppNamespaceService {
} }
@Transactional @Transactional
public AppNamespace createAppNamespace(AppNamespace appNamespace){ public AppNamespace createAppNamespace(AppNamespace appNamespace) {
String createBy = appNamespace.getDataChangeCreatedBy(); String createBy = appNamespace.getDataChangeCreatedBy();
if (!isAppNamespaceNameUnique(appNamespace.getAppId(), appNamespace.getName())) { if (!isAppNamespaceNameUnique(appNamespace.getAppId(), appNamespace.getName())) {
throw new ServiceException("appnamespace not unique"); throw new ServiceException("appnamespace not unique");
...@@ -109,12 +111,13 @@ public class AppNamespaceService { ...@@ -109,12 +111,13 @@ public class AppNamespaceService {
return appNamespace; return appNamespace;
} }
public AppNamespace update(AppNamespace appNamespace){ public AppNamespace update(AppNamespace appNamespace) {
AppNamespace managedNs = appNamespaceRepository.findByAppIdAndName(appNamespace.getAppId(), appNamespace.getName()); AppNamespace managedNs = appNamespaceRepository.findByAppIdAndName(appNamespace.getAppId(), appNamespace.getName());
BeanUtils.copyEntityProperties(appNamespace, managedNs); BeanUtils.copyEntityProperties(appNamespace, managedNs);
managedNs = appNamespaceRepository.save(managedNs); managedNs = appNamespaceRepository.save(managedNs);
auditService.audit(AppNamespace.class.getSimpleName(), managedNs.getId(), Audit.OP.UPDATE, managedNs.getDataChangeLastModifiedBy()); auditService.audit(AppNamespace.class.getSimpleName(), managedNs.getId(), Audit.OP.UPDATE,
managedNs.getDataChangeLastModifiedBy());
return managedNs; return managedNs;
} }
......
...@@ -18,12 +18,14 @@ import com.ctrip.framework.apollo.common.utils.BeanUtils; ...@@ -18,12 +18,14 @@ import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
...@@ -117,7 +119,46 @@ public class NamespaceService { ...@@ -117,7 +119,46 @@ public class NamespaceService {
//and default cluster's namespace exist but never published. //and default cluster's namespace exist but never published.
//return custom cluster's namespace //return custom cluster's namespace
return namespace; return namespace;
}
public List<Namespace> findPublicAppNamespaceAllNamespaces(String namespaceName, Pageable page) {
AppNamespace publicAppNamespace = appNamespaceService.findPublicNamespaceByName(namespaceName);
if (publicAppNamespace == null) {
throw new BadRequestException(
String.format("Public appNamespace not exists. NamespaceName = %s", namespaceName));
}
List<Namespace> namespaces = namespaceRepository.findByNamespaceName(namespaceName, page);
return filterChildNamespace(namespaces);
}
private List<Namespace> filterChildNamespace(List<Namespace> namespaces) {
List<Namespace> result = new LinkedList<>();
if (CollectionUtils.isEmpty(namespaces)) {
return result;
}
for (Namespace namespace : namespaces) {
if (!isChildNamespace(namespace)) {
result.add(namespace);
}
}
return result;
}
public int countPublicAppNamespaceAssociatedNamespaces(String publicNamespaceName) {
AppNamespace publicAppNamespace = appNamespaceService.findPublicNamespaceByName(publicNamespaceName);
if (publicAppNamespace == null) {
throw new BadRequestException(
String.format("Public appNamespace not exists. NamespaceName = %s", publicNamespaceName));
}
return namespaceRepository.countByNamespaceNameAndAppIdNot(publicNamespaceName, publicAppNamespace.getAppId());
} }
public List<Namespace> findNamespaces(String appId, String clusterName) { public List<Namespace> findNamespaces(String appId, String clusterName) {
......
...@@ -12,6 +12,7 @@ import com.ctrip.framework.apollo.biz.service.ClusterServiceTest; ...@@ -12,6 +12,7 @@ import com.ctrip.framework.apollo.biz.service.ClusterServiceTest;
import com.ctrip.framework.apollo.biz.service.InstanceServiceTest; import com.ctrip.framework.apollo.biz.service.InstanceServiceTest;
import com.ctrip.framework.apollo.biz.service.NamespaceBranchServiceTest; import com.ctrip.framework.apollo.biz.service.NamespaceBranchServiceTest;
import com.ctrip.framework.apollo.biz.service.NamespacePublishInfoTest; import com.ctrip.framework.apollo.biz.service.NamespacePublishInfoTest;
import com.ctrip.framework.apollo.biz.service.NamespaceServiceIntegrationTest;
import com.ctrip.framework.apollo.biz.service.NamespaceServiceTest; import com.ctrip.framework.apollo.biz.service.NamespaceServiceTest;
import com.ctrip.framework.apollo.biz.service.ReleaseCreationTest; import com.ctrip.framework.apollo.biz.service.ReleaseCreationTest;
import com.ctrip.framework.apollo.biz.service.ReleaseServiceTest; import com.ctrip.framework.apollo.biz.service.ReleaseServiceTest;
...@@ -39,8 +40,9 @@ import org.junit.runners.Suite.SuiteClasses; ...@@ -39,8 +40,9 @@ import org.junit.runners.Suite.SuiteClasses;
NamespaceBranchServiceTest.class, NamespaceBranchServiceTest.class,
ReleaseCreationTest.class, ReleaseCreationTest.class,
NamespacePublishInfoTest.class, NamespacePublishInfoTest.class,
NamespaceServiceTest.class, NamespaceServiceIntegrationTest.class,
BizConfigTest.class BizConfigTest.class,
NamespaceServiceTest.class
}) })
public class AllTests { public class AllTests {
......
package com.ctrip.framework.apollo.biz;
import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.entity.Release;
import com.ctrip.framework.apollo.biz.entity.ServerConfig;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
public class MockBeanFactory {
public static Namespace mockNamespace(String appId, String clusterName, String namespaceName) {
Namespace instance = new Namespace();
instance.setAppId(appId);
instance.setClusterName(clusterName);
instance.setNamespaceName(namespaceName);
return instance;
}
public static AppNamespace mockAppNamespace(String appId, String name, boolean isPublic) {
AppNamespace instance = new AppNamespace();
instance.setAppId(appId);
instance.setName(name);
instance.setPublic(isPublic);
return instance;
}
public static ServerConfig mockServerConfig(String key, String value, String cluster) {
ServerConfig instance = new ServerConfig();
instance.setKey(key);
instance.setValue(value);
instance.setCluster(cluster);
return instance;
}
public static Release mockRelease(long releaseId, String releaseKey, String appId,
String clusterName, String groupName, String configurations) {
Release instance = new Release();
instance.setId(releaseId);
instance.setReleaseKey(releaseKey);
instance.setAppId(appId);
instance.setClusterName(clusterName);
instance.setNamespaceName(groupName);
instance.setConfigurations(configurations);
return instance;
}
}
...@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.biz.service; ...@@ -3,6 +3,7 @@ package com.ctrip.framework.apollo.biz.service;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.ctrip.framework.apollo.biz.AbstractUnitTest; import com.ctrip.framework.apollo.biz.AbstractUnitTest;
import com.ctrip.framework.apollo.biz.MockBeanFactory;
import com.ctrip.framework.apollo.biz.entity.ServerConfig; import com.ctrip.framework.apollo.biz.entity.ServerConfig;
import com.ctrip.framework.apollo.biz.repository.ServerConfigRepository; import com.ctrip.framework.apollo.biz.repository.ServerConfigRepository;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
...@@ -45,19 +46,19 @@ public class BizDBPropertySourceTest extends AbstractUnitTest { ...@@ -45,19 +46,19 @@ public class BizDBPropertySourceTest extends AbstractUnitTest {
//cluster config //cluster config
String cluster = "cluster"; String cluster = "cluster";
configs.add(createServerConfig(clusterConfigKey, clusterConfigValue, cluster)); configs.add(MockBeanFactory.mockServerConfig(clusterConfigKey, clusterConfigValue, cluster));
String dc = "dc"; String dc = "dc";
configs.add(createServerConfig(clusterConfigKey, clusterConfigValue + "dc", dc)); configs.add(MockBeanFactory.mockServerConfig(clusterConfigKey, clusterConfigValue + "dc", dc));
configs.add(createServerConfig(clusterConfigKey, clusterConfigValue + ConfigConsts.CLUSTER_NAME_DEFAULT, configs.add(MockBeanFactory.mockServerConfig(clusterConfigKey, clusterConfigValue + ConfigConsts.CLUSTER_NAME_DEFAULT,
ConfigConsts.CLUSTER_NAME_DEFAULT)); ConfigConsts.CLUSTER_NAME_DEFAULT));
//dc config //dc config
configs.add(createServerConfig(dcConfigKey, dcConfigValue, dc)); configs.add(MockBeanFactory.mockServerConfig(dcConfigKey, dcConfigValue, dc));
configs.add(createServerConfig(dcConfigKey, dcConfigValue + ConfigConsts.CLUSTER_NAME_DEFAULT, configs.add(MockBeanFactory.mockServerConfig(dcConfigKey, dcConfigValue + ConfigConsts.CLUSTER_NAME_DEFAULT,
ConfigConsts.CLUSTER_NAME_DEFAULT)); ConfigConsts.CLUSTER_NAME_DEFAULT));
//default config //default config
configs.add(createServerConfig(defaultKey, defaultValue, ConfigConsts.CLUSTER_NAME_DEFAULT)); configs.add(MockBeanFactory.mockServerConfig(defaultKey, defaultValue, ConfigConsts.CLUSTER_NAME_DEFAULT));
System.setProperty(ConfigConsts.APOLLO_CLUSTER_KEY, cluster); System.setProperty(ConfigConsts.APOLLO_CLUSTER_KEY, cluster);
...@@ -99,14 +100,5 @@ public class BizDBPropertySourceTest extends AbstractUnitTest { ...@@ -99,14 +100,5 @@ public class BizDBPropertySourceTest extends AbstractUnitTest {
assertNull(propertySource.getProperty("noKey")); assertNull(propertySource.getProperty("noKey"));
} }
private ServerConfig createServerConfig(String key, String value, String cluster) {
ServerConfig config = new ServerConfig();
config.setKey(key);
config.setValue(value);
config.setCluster(cluster);
return config;
}
} }
package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.AbstractIntegrationTest;
import com.ctrip.framework.apollo.biz.entity.Cluster;
import com.ctrip.framework.apollo.biz.entity.Commit;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import com.ctrip.framework.apollo.biz.entity.Item;
import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.entity.Release;
import com.ctrip.framework.apollo.biz.entity.ReleaseHistory;
import com.ctrip.framework.apollo.biz.repository.InstanceConfigRepository;
import com.ctrip.framework.apollo.common.entity.AppNamespace;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class NamespaceServiceIntegrationTest extends AbstractIntegrationTest {
@Autowired
private NamespaceService namespaceService;
@Autowired
private ItemService itemService;
@Autowired
private CommitService commitService;
@Autowired
private AppNamespaceService appNamespaceService;
@Autowired
private ClusterService clusterService;
@Autowired
private ReleaseService releaseService;
@Autowired
private ReleaseHistoryService releaseHistoryService;
@Autowired
private InstanceConfigRepository instanceConfigRepository;
private String testApp = "testApp";
private String testCluster = "default";
private String testChildCluster = "child-cluster";
private String testPrivateNamespace = "application";
private String testUser = "apollo";
@Test
@Sql(scripts = "/sql/namespace-test.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testDeleteNamespace() {
Namespace namespace = new Namespace();
namespace.setAppId(testApp);
namespace.setClusterName(testCluster);
namespace.setNamespaceName(testPrivateNamespace);
namespace.setId(1);
namespaceService.deleteNamespace(namespace, testUser);
List<Item> items = itemService.findItems(testApp, testCluster, testPrivateNamespace);
List<Commit> commits = commitService.find(testApp, testCluster, testPrivateNamespace, new PageRequest(0, 10));
AppNamespace appNamespace = appNamespaceService.findOne(testApp, testPrivateNamespace);
List<Cluster> childClusters = clusterService.findChildClusters(testApp, testCluster);
InstanceConfig instanceConfig = instanceConfigRepository.findOne(1L);
List<Release> parentNamespaceReleases = releaseService.findActiveReleases(testApp, testCluster,
testPrivateNamespace,
new PageRequest(0, 10));
List<Release> childNamespaceReleases = releaseService.findActiveReleases(testApp, testChildCluster,
testPrivateNamespace,
new PageRequest(0, 10));
Page<ReleaseHistory> releaseHistories =
releaseHistoryService
.findReleaseHistoriesByNamespace(testApp, testCluster, testPrivateNamespace, new PageRequest(0, 10));
assertEquals(0, items.size());
assertEquals(0, commits.size());
assertNotNull(appNamespace);
assertEquals(0, childClusters.size());
assertEquals(0, parentNamespaceReleases.size());
assertEquals(0, childNamespaceReleases.size());
assertTrue(!releaseHistories.hasContent());
assertNull(instanceConfig);
}
}
package com.ctrip.framework.apollo.biz.service; package com.ctrip.framework.apollo.biz.service;
import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; import com.ctrip.framework.apollo.biz.AbstractUnitTest;
import com.ctrip.framework.apollo.biz.entity.Cluster; import com.ctrip.framework.apollo.biz.MockBeanFactory;
import com.ctrip.framework.apollo.biz.entity.Commit;
import com.ctrip.framework.apollo.biz.entity.InstanceConfig;
import com.ctrip.framework.apollo.biz.entity.Item;
import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.entity.Release; import com.ctrip.framework.apollo.biz.repository.NamespaceRepository;
import com.ctrip.framework.apollo.biz.entity.ReleaseHistory;
import com.ctrip.framework.apollo.biz.repository.InstanceConfigRepository;
import com.ctrip.framework.apollo.common.entity.AppNamespace; import com.ctrip.framework.apollo.common.entity.AppNamespace;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.core.ConfigConsts;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.mockito.InjectMocks;
import org.springframework.data.domain.Page; import org.mockito.Mock;
import org.mockito.Spy;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.jdbc.Sql; import org.springframework.data.domain.Pageable;
import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.doReturn;
import static org.junit.Assert.assertNull; import static org.mockito.Mockito.when;
import static org.junit.Assert.assertTrue;
public class NamespaceServiceTest extends AbstractIntegrationTest { public class NamespaceServiceTest extends AbstractUnitTest {
@Mock
private AppNamespaceService appNamespaceService;
@Mock
private NamespaceRepository namespaceRepository;
@Autowired @Spy
@InjectMocks
private NamespaceService namespaceService; private NamespaceService namespaceService;
@Autowired
private ItemService itemService; private String testPublicAppNamespace = "publicAppNamespace";
@Autowired
private CommitService commitService;
@Autowired @Test(expected = BadRequestException.class)
private AppNamespaceService appNamespaceService; public void testFindPublicAppNamespaceWithWrongNamespace() {
@Autowired Pageable page = new PageRequest(0, 10);
private ClusterService clusterService;
@Autowired when(appNamespaceService.findPublicNamespaceByName(testPublicAppNamespace)).thenReturn(null);
private ReleaseService releaseService;
@Autowired namespaceService.findPublicAppNamespaceAllNamespaces(testPublicAppNamespace, page);
private ReleaseHistoryService releaseHistoryService; }
@Autowired
private InstanceConfigRepository instanceConfigRepository;
private String testApp = "testApp";
private String testCluster = "default";
private String testChildCluster = "child-cluster";
private String testPrivateNamespace = "application";
private String testUser = "apollo";
@Test @Test
@Sql(scripts = "/sql/namespace-test.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) public void testFindPublicAppNamespace() {
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testDeleteNamespace() { AppNamespace publicAppNamespace = MockBeanFactory.mockAppNamespace(null, testPublicAppNamespace, true);
when(appNamespaceService.findPublicNamespaceByName(testPublicAppNamespace)).thenReturn(publicAppNamespace);
Namespace namespace = new Namespace();
namespace.setAppId(testApp); Namespace firstParentNamespace =
namespace.setClusterName(testCluster); MockBeanFactory.mockNamespace("app", ConfigConsts.CLUSTER_NAME_DEFAULT, testPublicAppNamespace);
namespace.setNamespaceName(testPrivateNamespace); Namespace secondParentNamespace =
namespace.setId(1); MockBeanFactory.mockNamespace("app1", ConfigConsts.CLUSTER_NAME_DEFAULT, testPublicAppNamespace);
Namespace childNamespace =
namespaceService.deleteNamespace(namespace, testUser); MockBeanFactory.mockNamespace("app2", ConfigConsts.CLUSTER_NAME_DEFAULT, testPublicAppNamespace);
List<Item> items = itemService.findItems(testApp, testCluster, testPrivateNamespace);
List<Commit> commits = commitService.find(testApp, testCluster, testPrivateNamespace, new PageRequest(0, 10)); Pageable page = new PageRequest(0, 10);
AppNamespace appNamespace = appNamespaceService.findOne(testApp, testPrivateNamespace);
List<Cluster> childClusters = clusterService.findChildClusters(testApp, testCluster); when(namespaceRepository.findByNamespaceName(testPublicAppNamespace, page))
InstanceConfig instanceConfig = instanceConfigRepository.findOne(1L); .thenReturn(Arrays.asList(firstParentNamespace, secondParentNamespace));
List<Release> parentNamespaceReleases = releaseService.findActiveReleases(testApp, testCluster,
testPrivateNamespace, doReturn(false).when(namespaceService).isChildNamespace(firstParentNamespace);
new PageRequest(0, 10)); doReturn(false).when(namespaceService).isChildNamespace(secondParentNamespace);
List<Release> childNamespaceReleases = releaseService.findActiveReleases(testApp, testChildCluster, doReturn(true).when(namespaceService).isChildNamespace(childNamespace);
testPrivateNamespace,
new PageRequest(0, 10)); List<Namespace> namespaces = namespaceService.findPublicAppNamespaceAllNamespaces(testPublicAppNamespace, page);
Page<ReleaseHistory> releaseHistories =
releaseHistoryService assertEquals(2, namespaces.size());
.findReleaseHistoriesByNamespace(testApp, testCluster, testPrivateNamespace, new PageRequest(0, 10));
assertEquals(0, items.size());
assertEquals(0, commits.size());
assertNotNull(appNamespace);
assertEquals(0, childClusters.size());
assertEquals(0, parentNamespaceReleases.size());
assertEquals(0, childNamespaceReleases.size());
assertTrue(!releaseHistories.hasContent());
assertNull(instanceConfig);
} }
} }
...@@ -4,6 +4,7 @@ import com.google.common.collect.Lists; ...@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.ctrip.framework.apollo.biz.AbstractUnitTest; import com.ctrip.framework.apollo.biz.AbstractUnitTest;
import com.ctrip.framework.apollo.biz.MockBeanFactory;
import com.ctrip.framework.apollo.biz.entity.Release; import com.ctrip.framework.apollo.biz.entity.Release;
import com.ctrip.framework.apollo.biz.repository.ReleaseRepository; import com.ctrip.framework.apollo.biz.repository.ReleaseRepository;
import com.ctrip.framework.apollo.common.exception.BadRequestException; import com.ctrip.framework.apollo.common.exception.BadRequestException;
...@@ -116,9 +117,8 @@ public class ReleaseServiceTest extends AbstractUnitTest { ...@@ -116,9 +117,8 @@ public class ReleaseServiceTest extends AbstractUnitTest {
String someReleaseKey = "someKey"; String someReleaseKey = "someKey";
String someValidConfiguration = "{\"apollo.bar\": \"foo\"}"; String someValidConfiguration = "{\"apollo.bar\": \"foo\"}";
Release Release someRelease =
someRelease = MockBeanFactory.mockRelease(someReleaseId, someReleaseKey, someAppId, someClusterName,
assembleRelease(someReleaseId, someReleaseKey, someAppId, someClusterName,
someNamespaceName, someNamespaceName,
someValidConfiguration); someValidConfiguration);
...@@ -189,18 +189,5 @@ public class ReleaseServiceTest extends AbstractUnitTest { ...@@ -189,18 +189,5 @@ public class ReleaseServiceTest extends AbstractUnitTest {
assertEquals(someReleases, result); assertEquals(someReleases, result);
} }
private Release assembleRelease(long releaseId, String releaseKey, String appId,
String clusterName,
String groupName, String configurations) {
Release release = new Release();
release.setId(releaseId);
release.setReleaseKey(releaseKey);
release.setAppId(appId);
release.setClusterName(clusterName);
release.setNamespaceName(groupName);
release.setConfigurations(configurations);
return release;
}
} }
...@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo.biz.utils; ...@@ -2,6 +2,7 @@ package com.ctrip.framework.apollo.biz.utils;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.ctrip.framework.apollo.biz.MockBeanFactory;
import com.ctrip.framework.apollo.biz.entity.Namespace; import com.ctrip.framework.apollo.biz.entity.Namespace;
import org.junit.Test; import org.junit.Test;
...@@ -29,8 +30,8 @@ public class ReleaseKeyGeneratorTest { ...@@ -29,8 +30,8 @@ public class ReleaseKeyGeneratorTest {
String anotherAppId = "anotherAppId"; String anotherAppId = "anotherAppId";
Namespace namespace = assembleNamespace(someAppId, someCluster, someNamespace); Namespace namespace = MockBeanFactory.mockNamespace(someAppId, someCluster, someNamespace);
Namespace anotherNamespace = assembleNamespace(anotherAppId, someCluster, someNamespace); Namespace anotherNamespace = MockBeanFactory.mockNamespace(anotherAppId, someCluster, someNamespace);
int generateTimes = 50000; int generateTimes = 50000;
Set<String> releaseKeys = Sets.newConcurrentHashSet(); Set<String> releaseKeys = Sets.newConcurrentHashSet();
...@@ -63,11 +64,4 @@ public class ReleaseKeyGeneratorTest { ...@@ -63,11 +64,4 @@ public class ReleaseKeyGeneratorTest {
}; };
} }
private Namespace assembleNamespace(String appId, String cluster, String namespaceName) {
Namespace namespace = new Namespace();
namespace.setAppId(appId);
namespace.setClusterName(cluster);
namespace.setNamespaceName(namespaceName);
return namespace;
}
} }
...@@ -20,6 +20,7 @@ import com.ctrip.framework.apollo.core.enums.Env; ...@@ -20,6 +20,7 @@ import com.ctrip.framework.apollo.core.enums.Env;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
...@@ -81,10 +82,12 @@ public class AdminServiceAPI { ...@@ -81,10 +82,12 @@ public class AdminServiceAPI {
NamespaceDTO.class, appId, clusterName, namespaceName); NamespaceDTO.class, appId, clusterName, namespaceName);
} }
public NamespaceDTO findPublicNamespaceForAssociatedNamespace(Env env, String appId, String clusterName, String namespaceName) { public NamespaceDTO findPublicNamespaceForAssociatedNamespace(Env env, String appId, String clusterName,
String namespaceName) {
return return
restTemplate.get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/associated-public-namespace", restTemplate
NamespaceDTO.class, appId, clusterName, namespaceName); .get(env, "apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/associated-public-namespace",
NamespaceDTO.class, appId, clusterName, namespaceName);
} }
public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) { public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) {
...@@ -109,6 +112,22 @@ public class AdminServiceAPI { ...@@ -109,6 +112,22 @@ public class AdminServiceAPI {
return restTemplate.get(env, "apps/{appId}/namespaces/publish_info", typeReference, appId).getBody(); return restTemplate.get(env, "apps/{appId}/namespaces/publish_info", typeReference, appId).getBody();
} }
public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(Env env, String publicNamespaceName,
int page, int size) {
NamespaceDTO[] namespaceDTOs =
restTemplate.get(env, "/appnamespaces/{publicNamespaceName}/namespaces?page={page}&size={size}",
NamespaceDTO[].class, publicNamespaceName, page, size);
return Arrays.asList(namespaceDTOs);
}
public int countPublicAppNamespaceAssociatedNamespaces(Env env, String publicNamesapceName) {
Integer count =
restTemplate.get(env, "/appnamespaces/{publicNamespaceName}/associated-namespaces/count", Integer.class,
publicNamesapceName);
return count == null ? 0 : count;
}
} }
@Service @Service
...@@ -230,7 +249,8 @@ public class AdminServiceAPI { ...@@ -230,7 +249,8 @@ public class AdminServiceAPI {
} }
public ReleaseDTO createRelease(String appId, Env env, String clusterName, String namespace, public ReleaseDTO createRelease(String appId, Env env, String clusterName, String namespace,
String releaseName, String releaseComment, String operator, boolean isEmergencyPublish) { String releaseName, String releaseComment, String operator,
boolean isEmergencyPublish) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")); headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"));
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(); MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
......
...@@ -21,14 +21,16 @@ public class PermissionValidator { ...@@ -21,14 +21,16 @@ public class PermissionValidator {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(), return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.MODIFY_NAMESPACE, PermissionType.MODIFY_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName)); RoleUtils.buildNamespaceTargetId(appId, namespaceName));
} }
public boolean hasReleaseNamespacePermission(String appId, String namespaceName) { public boolean hasReleaseNamespacePermission(String appId, String namespaceName) {
return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(), return rolePermissionService.userHasPermission(userInfoHolder.getUser().getUserId(),
PermissionType.RELEASE_NAMESPACE, PermissionType.RELEASE_NAMESPACE,
RoleUtils.buildNamespaceTargetId(appId, namespaceName)); RoleUtils.buildNamespaceTargetId(appId, namespaceName));
}
public boolean hasDeleteNamespacePermission(String appId) {
return hasAssignRolePermission(appId) || isSuperAdmin();
} }
public boolean hasOperateNamespacePermission(String appId, String namespaceName){ public boolean hasOperateNamespacePermission(String appId, String namespaceName){
......
...@@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.PathVariable; ...@@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
...@@ -45,7 +46,7 @@ import static com.ctrip.framework.apollo.common.utils.RequestPrecondition.checkM ...@@ -45,7 +46,7 @@ import static com.ctrip.framework.apollo.common.utils.RequestPrecondition.checkM
@RestController @RestController
public class NamespaceController { public class NamespaceController {
Logger logger = LoggerFactory.getLogger(NamespaceController.class); private static final Logger logger = LoggerFactory.getLogger(NamespaceController.class);
@Autowired @Autowired
private AppService appService; private AppService appService;
...@@ -130,11 +131,13 @@ public class NamespaceController { ...@@ -130,11 +131,13 @@ public class NamespaceController {
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
@PreAuthorize(value = "@permissionValidator.isSuperAdmin()") @PreAuthorize(value = "@permissionValidator.hasDeleteNamespacePermission(#appId)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName:.+}", method = RequestMethod.DELETE) @RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName:.+}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deleteNamespace(@PathVariable String appId, @PathVariable String env, public ResponseEntity<Void> deleteNamespace(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName) { @PathVariable String clusterName, @PathVariable String namespaceName) {
namespaceService.deleteNamespace(appId, Env.valueOf(env), clusterName, namespaceName); namespaceService.deleteNamespace(appId, Env.valueOf(env), clusterName, namespaceName);
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }
...@@ -183,4 +186,14 @@ public class NamespaceController { ...@@ -183,4 +186,14 @@ public class NamespaceController {
return namespaceService.getNamespacesPublishInfo(appId); return namespaceService.getNamespacesPublishInfo(appId);
} }
@RequestMapping(value = "/envs/{env}/appnamespaces/{publicNamespaceName}/namespaces", method = RequestMethod.GET)
public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(@PathVariable String env,
@PathVariable String publicNamespaceName,
@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "size", defaultValue = "10") int size) {
return namespaceService.getPublicAppNamespaceAllNamespaces(Env.fromString(env), publicNamespaceName, page, size);
}
} }
...@@ -9,7 +9,6 @@ import com.ctrip.framework.apollo.common.exception.BadRequestException; ...@@ -9,7 +9,6 @@ import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.component.ItemsComparator; import com.ctrip.framework.apollo.portal.component.ItemsComparator;
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
import com.ctrip.framework.apollo.portal.constant.CatEventType; import com.ctrip.framework.apollo.portal.constant.CatEventType;
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO; import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
...@@ -37,8 +36,6 @@ public class NamespaceBranchService { ...@@ -37,8 +36,6 @@ public class NamespaceBranchService {
private AdminServiceAPI.NamespaceBranchAPI namespaceBranchAPI; private AdminServiceAPI.NamespaceBranchAPI namespaceBranchAPI;
@Autowired @Autowired
private ReleaseService releaseService; private ReleaseService releaseService;
@Autowired
private PermissionValidator permissionValidator;
@Transactional @Transactional
......
package com.ctrip.framework.apollo.portal.service; package com.ctrip.framework.apollo.portal.service;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig; import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gson.Gson; import com.google.gson.Gson;
...@@ -36,20 +37,24 @@ public class NamespaceService { ...@@ -36,20 +37,24 @@ public class NamespaceService {
private Logger logger = LoggerFactory.getLogger(NamespaceService.class); private Logger logger = LoggerFactory.getLogger(NamespaceService.class);
private Gson gson = new Gson(); private Gson gson = new Gson();
@Autowired
private PortalConfig portalConfig;
@Autowired
private PortalSettings portalSettings;
@Autowired @Autowired
private UserInfoHolder userInfoHolder; private UserInfoHolder userInfoHolder;
@Autowired @Autowired
private AdminServiceAPI.NamespaceAPI namespaceAPI;
@Autowired
private ItemService itemService; private ItemService itemService;
@Autowired @Autowired
private ReleaseService releaseService; private ReleaseService releaseService;
@Autowired @Autowired
private AdminServiceAPI.NamespaceAPI namespaceAPI;
@Autowired
private AppNamespaceService appNamespaceService; private AppNamespaceService appNamespaceService;
@Autowired @Autowired
private PortalConfig portalConfig; private InstanceService instanceService;
@Autowired @Autowired
private PortalSettings portalSettings; private NamespaceBranchService branchService;
public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) { public NamespaceDTO createNamespace(Env env, NamespaceDTO namespace) {
...@@ -69,9 +74,27 @@ public class NamespaceService { ...@@ -69,9 +74,27 @@ public class NamespaceService {
@Transactional @Transactional
public void deleteNamespace(String appId, Env env, String clusterName, String namespaceName) { public void deleteNamespace(String appId, Env env, String clusterName, String namespaceName) {
//1. check private namespace
AppNamespace appNamespace = appNamespaceService.findByAppIdAndName(appId, namespaceName); AppNamespace appNamespace = appNamespaceService.findByAppIdAndName(appId, namespaceName);
if (appNamespace != null && !appNamespace.isPublic()) { if (appNamespace != null && !appNamespace.isPublic()) {
throw new BadRequestException("private namespace can not be deleted"); throw new BadRequestException("Private namespace can not be deleted");
}
//2. 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
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)) {
throw new BadRequestException("Can not delete public namespace which has associated namespaces");
} }
String operator = userInfoHolder.getUser().getUserId(); String operator = userInfoHolder.getUser().getUserId();
...@@ -79,7 +102,6 @@ public class NamespaceService { ...@@ -79,7 +102,6 @@ public class NamespaceService {
namespaceAPI.deleteNamespace(env, appId, clusterName, namespaceName, operator); namespaceAPI.deleteNamespace(env, appId, clusterName, namespaceName, operator);
} }
public NamespaceDTO loadNamespaceBaseInfo(String appId, Env env, String clusterName, String namespaceName) { public NamespaceDTO loadNamespaceBaseInfo(String appId, Env env, String clusterName, String namespaceName) {
NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName); NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
if (namespace == null) { if (namespace == null) {
...@@ -115,6 +137,11 @@ public class NamespaceService { ...@@ -115,6 +137,11 @@ public class NamespaceService {
return namespaceBOs; return namespaceBOs;
} }
public List<NamespaceDTO> getPublicAppNamespaceAllNamespaces(Env env, String publicNamespaceName, int page,
int size) {
return namespaceAPI.getPublicAppNamespaceAllNamespaces(env, publicNamespaceName, page, size);
}
public NamespaceBO loadNamespaceBO(String appId, Env env, String clusterName, String namespaceName) { public NamespaceBO loadNamespaceBO(String appId, Env env, String clusterName, String namespaceName) {
NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName); NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
if (namespace == null) { if (namespace == null) {
...@@ -123,10 +150,18 @@ public class NamespaceService { ...@@ -123,10 +150,18 @@ public class NamespaceService {
return transformNamespace2BO(env, namespace); return transformNamespace2BO(env, namespace);
} }
public boolean namespaceHasInstances(String appId, Env env, String clusterName, String namespaceName) {
return instanceService.getInstanceCountByNamepsace(appId, env, clusterName, namespaceName) > 0;
}
public boolean publicAppNamespaceHasAssociatedNamespace(String publicNamespaceName, Env env) {
return namespaceAPI.countPublicAppNamespaceAssociatedNamespaces(env, publicNamespaceName) > 0;
}
public NamespaceBO findPublicNamespaceForAssociatedNamespace(Env env, String appId, public NamespaceBO findPublicNamespaceForAssociatedNamespace(Env env, String appId,
String clusterName, String namespaceName) { String clusterName, String namespaceName) {
NamespaceDTO namespace = namespaceAPI.findPublicNamespaceForAssociatedNamespace(env, appId, clusterName, namespaceName); NamespaceDTO namespace =
namespaceAPI.findPublicNamespaceForAssociatedNamespace(env, appId, clusterName, namespaceName);
return transformNamespace2BO(env, namespace); return transformNamespace2BO(env, namespace);
} }
...@@ -135,7 +170,7 @@ public class NamespaceService { ...@@ -135,7 +170,7 @@ public class NamespaceService {
Map<String, Map<String, Boolean>> result = Maps.newHashMap(); Map<String, Map<String, Boolean>> result = Maps.newHashMap();
Set<Env> envs = portalConfig.publishTipsSupportedEnvs(); Set<Env> envs = portalConfig.publishTipsSupportedEnvs();
for (Env env: envs) { for (Env env : envs) {
if (portalSettings.isEnvActive(env)) { if (portalSettings.isEnvActive(env)) {
result.put(env.toString(), namespaceAPI.getNamespacePublishInfo(env, appId)); result.put(env.toString(), namespaceAPI.getNamespacePublishInfo(env, appId));
} }
......
...@@ -231,6 +231,8 @@ ...@@ -231,6 +231,8 @@
<publishdenymodal env="pageContext.env"></publishdenymodal> <publishdenymodal env="pageContext.env"></publishdenymodal>
<deletenamespacemodal env="pageContext.env"></deletenamespacemodal>
<apolloconfirmdialog apollo-dialog-id="'deleteConfirmDialog'" apollo-title="'删除配置'" <apolloconfirmdialog apollo-dialog-id="'deleteConfirmDialog'" apollo-title="'删除配置'"
apollo-detail="'确定要删除配置吗?'" apollo-detail="'确定要删除配置吗?'"
apollo-show-cancel-btn="true" apollo-confirm="deleteItem"></apolloconfirmdialog> apollo-show-cancel-btn="true" apollo-confirm="deleteItem"></apolloconfirmdialog>
...@@ -274,6 +276,31 @@ ...@@ -274,6 +276,31 @@
apollo-detail="'灰度版本还没有配置任何灰度规则,请配置灰度规则'"> apollo-detail="'灰度版本还没有配置任何灰度规则,请配置灰度规则'">
</apolloconfirmdialog> </apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForMasterInstanceDialog'"
apollo-title="'删除Namespace警告信息'"
apollo-detail="'发现有 <b>' + deleteNamespaceContext.namespace.instancesCount +
'</b> 个实例正在使用Namespace(' + deleteNamespaceContext.namespace.baseInfo.namespaceName +
'),删除Namespace将导致实例获取不到配置。<br>
请到 <ins>“实例列表”</ins> 确认实例信息,如已确认删除Namespace将不会导致实例异常,
请发送邮件至<ins> <a href=\'mailto:rdkjapollo@ctrip.com\'>Apollo团队(rdkjapollo@ctrip.com)</a></ins> 删除Namespace。'"
apollo-confirm="continueDeleteNamespace">
</apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForBranchInstanceDialog'"
apollo-title="'删除Namespace警告信息'"
apollo-detail="'发现有 <b>' + deleteNamespaceContext.namespace.branch.latestReleaseInstances.total
+ '</b> 个实例正在使用Namespace(' + deleteNamespaceContext.namespace.baseInfo.namespaceName +
')灰度版本的配置,删除Namespace将导致实例获取不到配置。<br>
请到 <ins>“灰度版本” => “实例列表”</ins> 确认实例信息,如已确认删除Namespace将不会导致实例异常,
请发送邮件至<ins> <a href=\'mailto:rdkjapollo@ctrip.com\'>Apollo团队(rdkjapollo@ctrip.com)</a></ins> 删除Namespace。'"
apollo-confirm="continueDeleteNamespace">
</apolloconfirmdialog>
<apolloconfirmdialog apollo-dialog-id="'deleteNamespaceDenyForPublicNamespaceDialog'"
apollo-title="'删除Namespace失败提示'"
apollo-detail="deleteNamespaceContext.detailReason">
</apolloconfirmdialog>
<div class="modal fade" id="createBranchTips" tabindex="-1" role="dialog"> <div class="modal fade" id="createBranchTips" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
...@@ -375,6 +402,7 @@ ...@@ -375,6 +402,7 @@
<script type="application/javascript" src="scripts/directive/gray-release-rules-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/gray-release-rules-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/merge-and-publish-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/merge-and-publish-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/publish-deny-modal-directive.js"></script> <script type="application/javascript" src="scripts/directive/publish-deny-modal-directive.js"></script>
<script type="application/javascript" src="scripts/directive/delete-namespace-modal-directive.js"></script>
<!--controller--> <!--controller-->
<script type="application/javascript" src="scripts/controller/config/ConfigNamespaceController.js"></script> <script type="application/javascript" src="scripts/controller/config/ConfigNamespaceController.js"></script>
......
...@@ -337,6 +337,36 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer ...@@ -337,6 +337,36 @@ function controller($rootScope, $scope, toastr, AppUtil, EventManager, ConfigSer
} }
EventManager.subscribe(EventManager.EventType.DELETE_NAMESPACE_FAILED, function (context) {
$scope.deleteNamespaceContext = context;
if (context.reason == 'master_instance') {
AppUtil.showModal('#deleteNamespaceDenyForMasterInstanceDialog');
} else if (context.reason == 'branch_instance') {
AppUtil.showModal('#deleteNamespaceDenyForBranchInstanceDialog');
} else if (context.reason == 'public_namespace') {
var otherAppAssociatedNamespaces = context.otherAppAssociatedNamespaces;
var namespaceTips = [];
otherAppAssociatedNamespaces.forEach(function (namespace) {
var appId = namespace.appId;
var clusterName = namespace.clusterName;
var url = '/config.html?#/appid=' + appId + '&env=' + $scope.pageContext.env + '&cluster='
+ clusterName;
namespaceTips.push("<a target='_blank' href=\'" + url + "\'>AppId = " + appId + ", 集群 = " + clusterName
+ ", Namespace = " + namespace.namespaceName + "</a>");
});
$scope.deleteNamespaceContext.detailReason =
"以下应用已关联此公共Namespace,必须先删除全部已关联的Namespace才能删除公共Namespace。<br>"
+ namespaceTips.join("<br>");
AppUtil.showModal('#deleteNamespaceDenyForPublicNamespaceDialog');
}
});
new Clipboard('.clipboard'); new Clipboard('.clipboard');
} }
......
directive_module.directive('deletenamespacemodal', deleteNamespaceModalDirective);
function deleteNamespaceModalDirective($window, $q, toastr, AppUtil, EventManager,
PermissionService, UserService, NamespaceService) {
return {
restrict: 'E',
templateUrl: '../../views/component/delete-namespace-modal.html',
transclude: true,
replace: true,
scope: {
env: '='
},
link: function (scope) {
scope.doDeleteNamespace = doDeleteNamespace;
EventManager.subscribe(EventManager.EventType.PRE_DELETE_NAMESPACE, function (context) {
var toDeleteNamespace = context.namespace;
scope.toDeleteNamespace = toDeleteNamespace;
//1. check namespace is not private
if (!checkNotPrivateNamespace(toDeleteNamespace)) {
return;
}
//2. check operator has master permission
checkPermission(toDeleteNamespace).then(function () {
//3. check namespace's master branch has not instances
if (!checkMasterInstance(toDeleteNamespace)) {
return;
}
//4. check namespace's gray branch has not instances
if (!checkBranchInstance(toDeleteNamespace)) {
return;
}
if (toDeleteNamespace.isLinkedNamespace) {
showDeleteNamespaceConfirmDialog();
} else {
//5. check public namespace has not associated namespace
checkPublicNamespace(toDeleteNamespace).then(function () {
showDeleteNamespaceConfirmDialog();
});
}
})
});
function checkNotPrivateNamespace(namespace) {
if (!namespace.isPublic) {
toastr.error("不能删除私有的Namespace", "删除失败");
return false;
}
return true;
}
function checkPermission(namespace) {
var d = $q.defer();
UserService.load_user().then(function (currentUser) {
var isAppMasterUser = false;
PermissionService.get_app_role_users(namespace.baseInfo.appId)
.then(function (appRoleUsers) {
var masterUsers = [];
appRoleUsers.masterUsers.forEach(function (user) {
masterUsers.push(user.userId);
if (currentUser.userId == user.userId) {
isAppMasterUser = true;
}
});
scope.masterUsers = masterUsers;
scope.isAppMasterUser = isAppMasterUser;
if (!isAppMasterUser) {
toastr.error("您没有项目管理员权限,只有管理员才能删除Namespace,请找项目管理员 [" + scope.masterUsers.join("")
+ "] 删除Namespace", "删除失败");
d.reject();
} else {
d.resolve();
}
});
});
return d.promise;
}
function checkMasterInstance(namespace) {
if (namespace.instancesCount > 0) {
EventManager.emit(EventManager.EventType.DELETE_NAMESPACE_FAILED, {
namespace: namespace,
reason: 'master_instance'
});
return false;
}
return true;
}
function checkBranchInstance(namespace) {
if (namespace.hasBranch && namespace.branch.latestReleaseInstances.total > 0) {
EventManager.emit(EventManager.EventType.DELETE_NAMESPACE_FAILED, {
namespace: namespace,
reason: 'branch_instance'
});
return false;
}
return true;
}
function checkPublicNamespace(namespace) {
var d = $q.defer();
var publicAppId = namespace.baseInfo.appId;
NamespaceService.getPublicAppNamespaceAllNamespaces(scope.env,
namespace.baseInfo.namespaceName,
0, 20)
.then(function (associatedNamespaces) {
var otherAppAssociatedNamespaces = [];
associatedNamespaces.forEach(function (associatedNamespace) {
if (associatedNamespace.appId != publicAppId) {
otherAppAssociatedNamespaces.push(associatedNamespace);
}
});
if (otherAppAssociatedNamespaces.length) {
EventManager.emit(EventManager.EventType.DELETE_NAMESPACE_FAILED, {
namespace: namespace,
reason: 'public_namespace',
otherAppAssociatedNamespaces: otherAppAssociatedNamespaces
});
d.reject();
} else {
d.resolve();
}
});
return d.promise;
}
function showDeleteNamespaceConfirmDialog() {
AppUtil.showModal('#deleteNamespaceModal');
}
function doDeleteNamespace() {
var toDeleteNamespace = scope.toDeleteNamespace;
NamespaceService.deleteNamespace(toDeleteNamespace.baseInfo.appId, scope.env,
toDeleteNamespace.baseInfo.clusterName,
toDeleteNamespace.baseInfo.namespaceName)
.then(function () {
toastr.success("删除成功");
setTimeout(function () {
$window.location.reload();
}, 1000);
}, function (result) {
AppUtil.showErrorMsg(result, "删除失败");
})
}
}
}
}
...@@ -213,7 +213,7 @@ directive_module.directive('apollorequiredfield', function ($compile, $window) { ...@@ -213,7 +213,7 @@ directive_module.directive('apollorequiredfield', function ($compile, $window) {
}); });
/** 确认框 */ /** 确认框 */
directive_module.directive('apolloconfirmdialog', function ($compile, $window) { directive_module.directive('apolloconfirmdialog', function ($compile, $window, $sce) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: '../../views/component/confirm-dialog.html', templateUrl: '../../views/component/confirm-dialog.html',
...@@ -225,15 +225,26 @@ directive_module.directive('apolloconfirmdialog', function ($compile, $window) { ...@@ -225,15 +225,26 @@ directive_module.directive('apolloconfirmdialog', function ($compile, $window) {
detail: '=apolloDetail', detail: '=apolloDetail',
showCancelBtn: '=apolloShowCancelBtn', showCancelBtn: '=apolloShowCancelBtn',
doConfirm: '=apolloConfirm', doConfirm: '=apolloConfirm',
confirmBtnText: '=?',
cancel: '=' cancel: '='
}, },
link: function (scope, element, attrs) { link: function (scope, element, attrs) {
scope.$watch("detail", function () {
scope.detailAsHtml = $sce.trustAsHtml(scope.detail);
});
if (!scope.confirmBtnText) {
scope.confirmBtnText = '确认';
}
scope.confirm = function () { scope.confirm = function () {
if (scope.doConfirm) { if (scope.doConfirm) {
scope.doConfirm(); scope.doConfirm();
} }
} };
} }
} }
......
...@@ -62,6 +62,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -62,6 +62,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
scope.addRuleItem = addRuleItem; scope.addRuleItem = addRuleItem;
scope.editRuleItem = editRuleItem; scope.editRuleItem = editRuleItem;
scope.deleteNamespace = deleteNamespace;
var subscriberId = EventManager.subscribe(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES, var subscriberId = EventManager.subscribe(EventManager.EventType.UPDATE_GRAY_RELEASE_RULES,
function (context) { function (context) {
useRules(context.branch); useRules(context.branch);
...@@ -81,11 +83,13 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -81,11 +83,13 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function initNamespace(namespace, viewType) { function initNamespace(namespace, viewType) {
namespace.hasBranch = false; namespace.hasBranch = false;
namespace.currentOperateBranch = 'master';
namespace.isBranch = false; namespace.isBranch = false;
namespace.isLinkedNamespace = namespace.isLinkedNamespace =
namespace.isPublic ? namespace.parentAppId != namespace.baseInfo.appId : false; namespace.isPublic ? namespace.parentAppId != namespace.baseInfo.appId : false;
namespace.showSearchInput = false; namespace.displayControl = {
currentOperateBranch: 'master',
showSearchInput: false
};
namespace.viewItems = namespace.items; namespace.viewItems = namespace.items;
namespace.isPropertiesFormat = namespace.format == 'properties'; namespace.isPropertiesFormat = namespace.format == 'properties';
namespace.isTextEditing = false; namespace.isTextEditing = false;
...@@ -336,7 +340,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -336,7 +340,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
if (branchName != 'master') { if (branchName != 'master') {
initRules(scope.namespace.branch); initRules(scope.namespace.branch);
} }
scope.namespace.currentOperateBranch = branchName; scope.namespace.displayControl.currentOperateBranch = branchName;
//save to local storage //save to local storage
var operateBranchStorage = JSON.parse(localStorage.getItem(operate_branch_storage_key)); var operateBranchStorage = JSON.parse(localStorage.getItem(operate_branch_storage_key));
...@@ -398,6 +402,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -398,6 +402,7 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
} }
function loadInstanceInfo(namespace) { function loadInstanceInfo(namespace) {
var size = 20; var size = 20;
if (namespace.isBranch) { if (namespace.isBranch) {
size = 2000; size = 2000;
...@@ -780,6 +785,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na ...@@ -780,6 +785,10 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
function rollback(namespace) { function rollback(namespace) {
EventManager.emit(EventManager.EventType.PRE_ROLLBACK_NAMESPACE, {namespace: namespace}); EventManager.emit(EventManager.EventType.PRE_ROLLBACK_NAMESPACE, {namespace: namespace});
} }
function deleteNamespace(namespace) {
EventManager.emit(EventManager.EventType.PRE_DELETE_NAMESPACE, {namespace: namespace});
}
setTimeout(function () { setTimeout(function () {
scope.namespace.show = true; scope.namespace.show = true;
......
...@@ -133,7 +133,10 @@ appService.service('EventManager', [function () { ...@@ -133,7 +133,10 @@ appService.service('EventManager', [function () {
EDIT_GRAY_RELEASE_RULES: 'edit_gray_release_rules', EDIT_GRAY_RELEASE_RULES: 'edit_gray_release_rules',
UPDATE_GRAY_RELEASE_RULES: 'update_gray_release_rules', UPDATE_GRAY_RELEASE_RULES: 'update_gray_release_rules',
PUBLISH_DENY: 'publish_deny', PUBLISH_DENY: 'publish_deny',
EMERGENCY_PUBLISH: 'emergency_publish' EMERGENCY_PUBLISH: 'emergency_publish',
PRE_DELETE_NAMESPACE: 'pre_delete_namespace',
DELETE_NAMESPACE: 'delete_namespace',
DELETE_NAMESPACE_FAILED: 'delete_namespace_failed'
} }
} }
......
...@@ -18,6 +18,15 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource, ...@@ -18,6 +18,15 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
getNamespacePublishInfo: { getNamespacePublishInfo: {
method: 'GET', method: 'GET',
url: '/apps/:appId/namespaces/publish_info' url: '/apps/:appId/namespaces/publish_info'
},
deleteNamespace: {
method: 'DELETE',
url: '/apps/:appId/envs/:env/clusters/:clusterName/namespaces/:namespaceName'
},
getPublicAppNamespaceAllNamespaces: {
method: 'GET',
url: '/envs/:env/appnamespaces/:publicNamespaceName/namespaces',
isArray: true
} }
}); });
...@@ -63,16 +72,53 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource, ...@@ -63,16 +72,53 @@ appService.service("NamespaceService", ['$resource', '$q', function ($resource,
d.resolve(result); d.resolve(result);
}, function (result) { }, function (result) {
d.reject(result); d.reject(result);
}) });
return d.promise;
}
function deleteNamespace(appId, env, clusterName, namespaceName) {
var d = $q.defer();
namespace_source.deleteNamespace({
appId: appId,
env: env,
clusterName: clusterName,
namespaceName: namespaceName
},
function (result) {
d.resolve(result);
},
function (result) {
d.reject(result);
});
return d.promise; return d.promise;
} }
function getPublicAppNamespaceAllNamespaces(env, publicNamespaceName, page, size) {
var d = $q.defer();
namespace_source.getPublicAppNamespaceAllNamespaces({
env: env,
publicNamespaceName: publicNamespaceName,
page: page,
size: size
}, function (result) {
d.resolve(result);
}, function (result) {
d.reject(result);
});
return d.promise;
}
return { return {
find_public_namespaces: find_public_namespaces, find_public_namespaces: find_public_namespaces,
createNamespace: createNamespace, createNamespace: createNamespace,
createAppNamespace: createAppNamespace, createAppNamespace: createAppNamespace,
getNamespacePublishInfo: getNamespacePublishInfo getNamespacePublishInfo: getNamespacePublishInfo,
deleteNamespace: deleteNamespace,
getPublicAppNamespaceAllNamespaces: getPublicAppNamespaceAllNamespaces
} }
}]); }]);
appService.service('UserService', ['$resource', '$q', function ($resource, $q) { appService.service('UserService', ['$resource', '$q', function ($resource, $q) {
var user_resource = $resource('', {}, { var user_resource = $resource('', {}, {
load_user:{ load_user: {
method: 'GET', method: 'GET',
url:'/user' url: '/user'
}, },
find_users: { find_users: {
method: 'GET', method: 'GET',
...@@ -11,26 +11,30 @@ appService.service('UserService', ['$resource', '$q', function ($resource, $q) { ...@@ -11,26 +11,30 @@ appService.service('UserService', ['$resource', '$q', function ($resource, $q) {
}); });
return { return {
load_user: function () { load_user: function () {
var finished = false;
var d = $q.defer(); var d = $q.defer();
user_resource.load_user({ user_resource.load_user({},
},
function (result) { function (result) {
finished = true;
d.resolve(result); d.resolve(result);
}, function (result) { },
d.reject(result); function (result) {
}); finished = true;
d.reject(result);
});
return d.promise; return d.promise;
}, },
find_users: function (keyword) { find_users: function (keyword) {
var d = $q.defer(); var d = $q.defer();
user_resource.find_users({ user_resource.find_users({
keyword: keyword keyword: keyword
}, },
function (result) { function (result) {
d.resolve(result); d.resolve(result);
}, function (result) { },
d.reject(result); function (result) {
}); d.reject(result);
});
return d.promise; return d.promise;
} }
} }
......
...@@ -790,3 +790,7 @@ table th { ...@@ -790,3 +790,7 @@ table th {
background: #fff; background: #fff;
} }
.dropdown:hover .dropdown-menu {
display: block;
margin-top: 0;
}
...@@ -6,15 +6,14 @@ ...@@ -6,15 +6,14 @@
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
<h4 class="modal-title">{{title}}</h4> <h4 class="modal-title">{{title}}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body" ng-bind-html="detailAsHtml">
{{detail}}
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" <button type="button" class="btn btn-default" data-dismiss="modal"
ng-show="showCancelBtn" ng-click="cancel()">取消</button> ng-show="showCancelBtn" ng-click="cancel()">取消</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" <button type="button" class="btn btn-danger" data-dismiss="modal"
ng-click="confirm()"> ng-click="confirm()">
确定 {{confirmBtnText}}
</button> </button>
</div> </div>
</div> </div>
......
<div id="deleteNamespaceModal" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header panel-primary">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title">
删除Namespace
</h4>
</div>
<div class="modal-body form-horizontal">
删除Namespace将导致实例获取不到此Namespace的配置,确定要删除吗?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
取消
</button>
<button type="button" class="btn btn-danger" data-dismiss="modal"
ng-click="doDeleteNamespace()">
确认
</button>
</div>
</div>
</div>
</div>
<section class="branch-panel-body" ng-if="namespace.hasBranch && namespace.currentOperateBranch != 'master'"> <section class="branch-panel-body" ng-if="namespace.hasBranch && namespace.displayControl.currentOperateBranch != 'master'">
<!--main header--> <!--main header-->
<header class="panel-heading"> <header class="panel-heading">
......
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
<div class="col-md-8 pull-left"> <div class="col-md-8 pull-left">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li role="presentation"> <li role="presentation">
<a ng-class="{'node_active': namespace.currentOperateBranch == 'master'}" <a ng-class="{'node_active': namespace.displayControl.currentOperateBranch == 'master'}"
ng-click="switchBranch('master')"> ng-click="switchBranch('master')">
<img src="img/branch.png"> <img src="img/branch.png">
主版本 主版本
</a> </a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a ng-class="{'node_active': namespace.currentOperateBranch != 'master'}" <a ng-class="{'node_active': namespace.displayControl.currentOperateBranch != 'master'}"
ng-click="switchBranch(namespace.branchName)"> ng-click="switchBranch(namespace.branchName)">
<img src="img/branch.png"> <img src="img/branch.png">
灰度版本 灰度版本
......
...@@ -6,6 +6,7 @@ import com.ctrip.framework.apollo.common.dto.NamespaceDTO; ...@@ -6,6 +6,7 @@ import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.enums.Env; import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.AbstractUnitTest;
import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI;
import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder;
import com.ctrip.framework.apollo.portal.entity.bo.UserInfo; import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
...@@ -17,10 +18,8 @@ import com.ctrip.framework.apollo.portal.entity.vo.NamespaceIdentifier; ...@@ -17,10 +18,8 @@ import com.ctrip.framework.apollo.portal.entity.vo.NamespaceIdentifier;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import java.util.Arrays; import java.util.Arrays;
...@@ -29,8 +28,7 @@ import java.util.List; ...@@ -29,8 +28,7 @@ import java.util.List;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class) public class ConfigServiceTest extends AbstractUnitTest {
public class ConfigServiceTest {
@Mock @Mock
private AdminServiceAPI.NamespaceAPI namespaceAPI; private AdminServiceAPI.NamespaceAPI namespaceAPI;
...@@ -77,7 +75,7 @@ public class ConfigServiceTest { ...@@ -77,7 +75,7 @@ public class ConfigServiceTest {
try { try {
configService.updateConfigItemByText(model); configService.updateConfigItemByText(model);
}catch (Exception e){ } catch (Exception e) {
Assert.fail(); Assert.fail();
} }
} }
...@@ -94,13 +92,15 @@ public class ConfigServiceTest { ...@@ -94,13 +92,15 @@ public class ConfigServiceTest {
} }
@Test @Test
public void testCompareTargetNamespaceHasNoItems(){ public void testCompareTargetNamespaceHasNoItems() {
ItemDTO sourceItem1 = new ItemDTO("a","b","comment",1); ItemDTO sourceItem1 = new ItemDTO("a", "b", "comment", 1);
List<ItemDTO> sourceItems = Arrays.asList(sourceItem1); List<ItemDTO> sourceItems = Arrays.asList(sourceItem1);
String appId = "6666", env = "LOCAL", clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT, String appId = "6666", env = "LOCAL", clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT,
namespaceName = ConfigConsts.NAMESPACE_APPLICATION; namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
List<NamespaceIdentifier> namespaceIdentifiers = generateNamespaceIdentifer(appId, env, clusterName, namespaceName); List<NamespaceIdentifier>
namespaceIdentifiers =
generateNamespaceIdentifier(appId, env, clusterName, namespaceName);
NamespaceDTO namespaceDTO = generateNamespaceDTO(appId, clusterName, namespaceName); NamespaceDTO namespaceDTO = generateNamespaceDTO(appId, clusterName, namespaceName);
when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO); when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO);
...@@ -112,7 +112,7 @@ public class ConfigServiceTest { ...@@ -112,7 +112,7 @@ public class ConfigServiceTest {
List<ItemDiffs> itemDiffses = configService.compare(namespaceIdentifiers, sourceItems); List<ItemDiffs> itemDiffses = configService.compare(namespaceIdentifiers, sourceItems);
assertEquals(1,itemDiffses.size()); assertEquals(1, itemDiffses.size());
ItemDiffs itemDiffs = itemDiffses.get(0); ItemDiffs itemDiffs = itemDiffses.get(0);
ItemChangeSets changeSets = itemDiffs.getDiffs(); ItemChangeSets changeSets = itemDiffs.getDiffs();
assertEquals(0, changeSets.getUpdateItems().size()); assertEquals(0, changeSets.getUpdateItems().size());
...@@ -127,21 +127,23 @@ public class ConfigServiceTest { ...@@ -127,21 +127,23 @@ public class ConfigServiceTest {
} }
@Test @Test
public void testCompare(){ public void testCompare() {
ItemDTO sourceItem1 = new ItemDTO("a","b","comment",1);//not modified ItemDTO sourceItem1 = new ItemDTO("a", "b", "comment", 1);//not modified
ItemDTO sourceItem2 = new ItemDTO("newKey","c","comment",2);//new item ItemDTO sourceItem2 = new ItemDTO("newKey", "c", "comment", 2);//new item
ItemDTO sourceItem3 = new ItemDTO("c","newValue","comment",3);// update value ItemDTO sourceItem3 = new ItemDTO("c", "newValue", "comment", 3);// update value
ItemDTO sourceItem4 = new ItemDTO("d","b","newComment",4);// update comment ItemDTO sourceItem4 = new ItemDTO("d", "b", "newComment", 4);// update comment
List<ItemDTO> sourceItems = Arrays.asList(sourceItem1, sourceItem2, sourceItem3, sourceItem4); List<ItemDTO> sourceItems = Arrays.asList(sourceItem1, sourceItem2, sourceItem3, sourceItem4);
ItemDTO targetItem1 = new ItemDTO("a","b","comment",1); ItemDTO targetItem1 = new ItemDTO("a", "b", "comment", 1);
ItemDTO targetItem2 = new ItemDTO("c","oldValue","comment",2); ItemDTO targetItem2 = new ItemDTO("c", "oldValue", "comment", 2);
ItemDTO targetItem3 = new ItemDTO("d","b","oldComment",3); ItemDTO targetItem3 = new ItemDTO("d", "b", "oldComment", 3);
List<ItemDTO> targetItems = Arrays.asList(targetItem1, targetItem2, targetItem3); List<ItemDTO> targetItems = Arrays.asList(targetItem1, targetItem2, targetItem3);
String appId = "6666", env = "LOCAL", clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT, String appId = "6666", env = "LOCAL", clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT,
namespaceName = ConfigConsts.NAMESPACE_APPLICATION; namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
List<NamespaceIdentifier> namespaceIdentifiers = generateNamespaceIdentifer(appId, env, clusterName, namespaceName); List<NamespaceIdentifier>
namespaceIdentifiers =
generateNamespaceIdentifier(appId, env, clusterName, namespaceName);
NamespaceDTO namespaceDTO = generateNamespaceDTO(appId, clusterName, namespaceName); NamespaceDTO namespaceDTO = generateNamespaceDTO(appId, clusterName, namespaceName);
when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO); when(namespaceAPI.loadNamespace(appId, Env.valueOf(env), clusterName, namespaceName)).thenReturn(namespaceDTO);
...@@ -189,7 +191,7 @@ public class ConfigServiceTest { ...@@ -189,7 +191,7 @@ public class ConfigServiceTest {
} }
private NamespaceDTO generateNamespaceDTO(String appId, String clusterName, String namespaceName){ private NamespaceDTO generateNamespaceDTO(String appId, String clusterName, String namespaceName) {
NamespaceDTO namespaceDTO = new NamespaceDTO(); NamespaceDTO namespaceDTO = new NamespaceDTO();
namespaceDTO.setAppId(appId); namespaceDTO.setAppId(appId);
namespaceDTO.setId(1); namespaceDTO.setId(1);
...@@ -198,7 +200,8 @@ public class ConfigServiceTest { ...@@ -198,7 +200,8 @@ public class ConfigServiceTest {
return namespaceDTO; return namespaceDTO;
} }
private List<NamespaceIdentifier> generateNamespaceIdentifer(String appId, String env, String clusterName, String namespaceName){ private List<NamespaceIdentifier> generateNamespaceIdentifier(String appId, String env, String clusterName,
String namespaceName) {
NamespaceIdentifier targetNamespace = new NamespaceIdentifier(); NamespaceIdentifier targetNamespace = new NamespaceIdentifier();
targetNamespace.setAppId(appId); targetNamespace.setAppId(appId);
targetNamespace.setEnv(env); targetNamespace.setEnv(env);
......
...@@ -243,7 +243,8 @@ CREATE TABLE `Namespace` ( ...@@ -243,7 +243,8 @@ CREATE TABLE `Namespace` (
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`), PRIMARY KEY (`Id`),
KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)), KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`) KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment