diff --git a/CHANGES.md b/CHANGES.md index f726c5815bd..7c743e003f3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ Release Notes. Apollo 2.4.0 ------------------ +* [Refactor: removed few of the code smells and refactored the code to improve readability](https://github.com/apolloconfig/apollo/pull/5284) * [Update the server config link in system info page](https://github.com/apolloconfig/apollo/pull/5204) * [Feature support portal restTemplate Client connection pool config](https://github.com/apolloconfig/apollo/pull/5200) * [Feature added the ability for administrators to globally search for Value](https://github.com/apolloconfig/apollo/pull/5182) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java index 437b9223046..735244df63f 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java @@ -72,15 +72,8 @@ public class BizConfig extends RefreshableConfig { new TypeToken>() { }.getType(); - private final BizDBPropertySource propertySource; - public BizConfig(final BizDBPropertySource propertySource) { - this.propertySource = propertySource; - } - - @Override - protected List getRefreshablePropertySources() { - return Collections.singletonList(propertySource); + super(propertySource); } public List eurekaServiceUrls() { diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/grayReleaseRule/GrayReleaseRulesHolder.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/grayReleaseRule/GrayReleaseRulesHolder.java index e7f3b904301..d6d56f57c19 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/grayReleaseRule/GrayReleaseRulesHolder.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/grayReleaseRule/GrayReleaseRulesHolder.java @@ -157,10 +157,17 @@ public Long findReleaseIdFromGrayReleaseRule(String clientAppId, String clientIp * load gray releases. Because gray release rules actually apply to one more dimension - cluster. */ public boolean hasGrayReleaseRule(String clientAppId, String clientIp, String namespaceName) { - return reversedGrayReleaseRuleCache.containsKey(assembleReversedGrayReleaseRuleKey(clientAppId, - namespaceName, clientIp)) || reversedGrayReleaseRuleCache.containsKey - (assembleReversedGrayReleaseRuleKey(clientAppId, namespaceName, GrayReleaseRuleItemDTO - .ALL_IP)); + + String ruleKeyViaClientIp = assembleReversedGrayReleaseRuleKey(clientAppId, + namespaceName, clientIp); + String ruleKeyViaItemDTO = assembleReversedGrayReleaseRuleKey(clientAppId, namespaceName, GrayReleaseRuleItemDTO + .ALL_IP); + + boolean hasScheduleForThisKey = reversedGrayReleaseRuleCache.containsKey(ruleKeyViaClientIp); + boolean hasScheduleForThatKey = reversedGrayReleaseRuleCache.containsKey + (ruleKeyViaItemDTO); + + return hasScheduleForThisKey || hasScheduleForThatKey; } private void scanGrayReleaseRules() { diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ReleaseHistoryService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ReleaseHistoryService.java index 804f1f77550..2112f249f81 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ReleaseHistoryService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ReleaseHistoryService.java @@ -45,7 +45,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; - import java.util.Date; import java.util.Map; import java.util.Set; diff --git a/apollo-build-sql-converter/pom.xml b/apollo-build-sql-converter/pom.xml index 82d91068ec2..6b9becb91fc 100644 --- a/apollo-build-sql-converter/pom.xml +++ b/apollo-build-sql-converter/pom.xml @@ -42,7 +42,7 @@ spring-boot-starter-jdbc test - + diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java index 3ad2b3bbc09..cfaad5a0191 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/config/RefreshableConfig.java @@ -28,6 +28,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.util.CollectionUtils; +import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -36,7 +37,7 @@ import javax.annotation.PostConstruct; -public abstract class RefreshableConfig { +public class RefreshableConfig { private static final Logger logger = LoggerFactory.getLogger(RefreshableConfig.class); @@ -49,18 +50,24 @@ public abstract class RefreshableConfig { @Autowired private ConfigurableEnvironment environment; - private List propertySources; - /** * register refreshable property source. * Notice: The front property source has higher priority. */ - protected abstract List getRefreshablePropertySources(); + private List propertySources; + + public RefreshableConfig(RefreshablePropertySource propertySources) { + this.propertySources = Collections.singletonList(propertySources); + } + + private List getPropertySources() { + return propertySources; + } @PostConstruct public void setup() { - propertySources = getRefreshablePropertySources(); + propertySources = getPropertySources(); if (CollectionUtils.isEmpty(propertySources)) { throw new IllegalStateException("Property sources can not be empty."); } diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCache.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCache.java index 00ca866b0ba..b3fb748f200 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCache.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/config/ConfigServiceWithCache.java @@ -112,9 +112,9 @@ protected Release findLatestActiveRelease(String appId, String clusterName, Stri ConfigCacheEntry cacheEntry = configCache.getUnchecked(cacheKey); - //cache is out-dated - if (clientMessages != null && clientMessages.has(messageKey) && - clientMessages.get(messageKey) > cacheEntry.getNotificationId()) { + // Checking if the cache is out-dated + boolean isCacheOutdated = outdatedCacheCheck(clientMessages, messageKey, cacheEntry); + if (isCacheOutdated) { //invalidate the cache and try to load from db again invalidate(cacheKey); cacheEntry = configCache.getUnchecked(cacheKey); @@ -123,6 +123,12 @@ protected Release findLatestActiveRelease(String appId, String clusterName, Stri return cacheEntry.getRelease(); } + private static boolean outdatedCacheCheck(ApolloNotificationMessages clientMessages, String messageKey, ConfigCacheEntry cacheEntry) { + boolean clientMessagesHasMessageKey = clientMessages != null && clientMessages.has(messageKey); + return clientMessagesHasMessageKey && + clientMessages.get(messageKey) > cacheEntry.getNotificationId(); + } + private void invalidate(String key) { configCache.invalidate(key); Tracer.logEvent(TRACER_EVENT_CACHE_INVALIDATE, key); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidator.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidator.java index 7480b77c5eb..223ff85a68f 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidator.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidator.java @@ -18,23 +18,39 @@ import static com.ctrip.framework.apollo.portal.service.SystemRoleManagerService.SYSTEM_PERMISSION_TARGET_ID; +import com.ctrip.framework.apollo.openapi.entity.ConsumerRole; +import com.ctrip.framework.apollo.openapi.repository.ConsumerRoleRepository; import com.ctrip.framework.apollo.openapi.service.ConsumerRolePermissionService; import com.ctrip.framework.apollo.openapi.util.ConsumerAuthUtil; import com.ctrip.framework.apollo.portal.constant.PermissionType; +import com.ctrip.framework.apollo.portal.entity.po.Permission; +import com.ctrip.framework.apollo.portal.entity.po.RolePermission; +import com.ctrip.framework.apollo.portal.repository.PermissionRepository; +import com.ctrip.framework.apollo.portal.repository.RolePermissionRepository; import com.ctrip.framework.apollo.portal.util.RoleUtils; +import com.nimbusds.oauth2.sdk.util.CollectionUtils; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; @Component public class ConsumerPermissionValidator { - private final ConsumerRolePermissionService permissionService; private final ConsumerAuthUtil consumerAuthUtil; + private final RolePermissionRepository rolePermissionRepository; + private final ConsumerRoleRepository consumerRoleRepository; + private final PermissionRepository permissionRepository; - public ConsumerPermissionValidator(final ConsumerRolePermissionService permissionService, - final ConsumerAuthUtil consumerAuthUtil) { - this.permissionService = permissionService; + public ConsumerPermissionValidator(final ConsumerAuthUtil consumerAuthUtil, + final RolePermissionRepository rolePermissionRepository + , final ConsumerRoleRepository consumerRoleRepository, + final PermissionRepository permissionRepository) { this.consumerAuthUtil = consumerAuthUtil; + this.rolePermissionRepository = rolePermissionRepository; + this.consumerRoleRepository = consumerRoleRepository; + this.permissionRepository = permissionRepository; } public boolean hasModifyNamespacePermission(HttpServletRequest request, String appId, @@ -42,9 +58,9 @@ public boolean hasModifyNamespacePermission(HttpServletRequest request, String a if (hasCreateNamespacePermission(request, appId)) { return true; } - return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), + return consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), PermissionType.MODIFY_NAMESPACE, RoleUtils.buildNamespaceTargetId(appId, namespaceName)) - || permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), + || consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), PermissionType.MODIFY_NAMESPACE, RoleUtils.buildNamespaceTargetId(appId, namespaceName, env)); @@ -55,26 +71,54 @@ public boolean hasReleaseNamespacePermission(HttpServletRequest request, String if (hasCreateNamespacePermission(request, appId)) { return true; } - return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), + return consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), PermissionType.RELEASE_NAMESPACE, RoleUtils.buildNamespaceTargetId(appId, namespaceName)) - || permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), + || consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), PermissionType.RELEASE_NAMESPACE, RoleUtils.buildNamespaceTargetId(appId, namespaceName, env)); } public boolean hasCreateNamespacePermission(HttpServletRequest request, String appId) { - return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), + return consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), PermissionType.CREATE_NAMESPACE, appId); } public boolean hasCreateClusterPermission(HttpServletRequest request, String appId) { - return permissionService.consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), + return consumerHasPermission(consumerAuthUtil.retrieveConsumerId(request), PermissionType.CREATE_CLUSTER, appId); } public boolean hasCreateApplicationPermission(HttpServletRequest request) { long consumerId = consumerAuthUtil.retrieveConsumerId(request); - return permissionService.consumerHasPermission(consumerId, PermissionType.CREATE_APPLICATION, SYSTEM_PERMISSION_TARGET_ID); + return consumerHasPermission(consumerId, PermissionType.CREATE_APPLICATION, SYSTEM_PERMISSION_TARGET_ID); + } + + public boolean consumerHasPermission(long consumerId, String permissionType, String targetId) { + Permission permission = + permissionRepository.findTopByPermissionTypeAndTargetId(permissionType, targetId); + if (permission == null) { + return false; + } + + List consumerRoles = consumerRoleRepository.findByConsumerId(consumerId); + if (CollectionUtils.isEmpty(consumerRoles)) { + return false; + } + + Set roleIds = + consumerRoles.stream().map(ConsumerRole::getRoleId).collect(Collectors.toSet()); + List rolePermissions = rolePermissionRepository.findByRoleIdIn(roleIds); + if (CollectionUtils.isEmpty(rolePermissions)) { + return false; + } + + for (RolePermission rolePermission : rolePermissions) { + if (rolePermission.getPermissionId() == permission.getId()) { + return true; + } + } + + return false; } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java index cb0d0ef9e14..f51dc83a842 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java @@ -75,9 +75,8 @@ public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable St @PathVariable String namespaceName, @RequestBody NamespaceReleaseDTO model, HttpServletRequest request) { - RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model - .getReleaseTitle()), - "Params(releaseTitle and releasedBy) can not be empty"); + boolean doesContainEmpty = StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()); + RequestPrecondition.checkArguments(!doesContainEmpty, "Params(releaseTitle and releasedBy) can not be empty"); if (userService.findByUserId(model.getReleasedBy()) == null) { throw BadRequestException.userNotExists(model.getReleasedBy()); @@ -99,9 +98,8 @@ public OpenReleaseDTO merge(@PathVariable String appId, @PathVariable String env @PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String branchName, @RequestParam(value = "deleteBranch", defaultValue = "true") boolean deleteBranch, @RequestBody NamespaceReleaseDTO model, HttpServletRequest request) { - RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model - .getReleaseTitle()), - "Params(releaseTitle and releasedBy) can not be empty"); + boolean doesContainEmpty = StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()); + RequestPrecondition.checkArguments(!doesContainEmpty, "Params(releaseTitle and releasedBy) can not be empty"); if (userService.findByUserId(model.getReleasedBy()) == null) { throw BadRequestException.userNotExists(model.getReleasedBy()); @@ -121,20 +119,15 @@ public OpenReleaseDTO createGrayRelease(@PathVariable String appId, @PathVariable String namespaceName, @PathVariable String branchName, @RequestBody NamespaceReleaseDTO model, HttpServletRequest request) { - RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model - .getReleaseTitle()), - "Params(releaseTitle and releasedBy) can not be empty"); + boolean doesContainEmpty = StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()); + RequestPrecondition.checkArguments(!doesContainEmpty, "Params(releaseTitle and releasedBy) can not be empty"); if (userService.findByUserId(model.getReleasedBy()) == null) { throw BadRequestException.userNotExists(model.getReleasedBy()); } NamespaceReleaseModel releaseModel = BeanUtils.transform(NamespaceReleaseModel.class, model); - - releaseModel.setAppId(appId); - releaseModel.setEnv(Env.valueOf(env).toString()); - releaseModel.setClusterName(branchName); - releaseModel.setNamespaceName(namespaceName); + populateReleaseModel(releaseModel, appId, Env.valueOf(env).toString(), branchName, namespaceName); return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel)); } @@ -146,9 +139,9 @@ public OpenReleaseDTO createGrayDelRelease(@PathVariable String appId, @PathVariable String namespaceName, @PathVariable String branchName, @RequestBody NamespaceGrayDelReleaseDTO model, HttpServletRequest request) { - RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(model.getReleasedBy(), model - .getReleaseTitle()), - "Params(releaseTitle and releasedBy) can not be empty"); + boolean doesContainEmpty = StringUtils.isContainEmpty(model.getReleasedBy(), model.getReleaseTitle()); + RequestPrecondition.checkArguments(!doesContainEmpty, "Params(releaseTitle and releasedBy) can not be empty"); + RequestPrecondition.checkArguments(model.getGrayDelKeys() != null, "Params(grayDelKeys) can not be null"); @@ -157,19 +150,17 @@ public OpenReleaseDTO createGrayDelRelease(@PathVariable String appId, } NamespaceGrayDelReleaseModel releaseModel = BeanUtils.transform(NamespaceGrayDelReleaseModel.class, model); - releaseModel.setAppId(appId); - releaseModel.setEnv(env.toUpperCase()); - releaseModel.setClusterName(branchName); - releaseModel.setNamespaceName(namespaceName); + populateReleaseModel(releaseModel, appId, env.toUpperCase(), branchName, namespaceName); - return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel, releaseModel.getReleasedBy())); + ReleaseDTO publish = releaseService.publish(releaseModel, releaseModel.getReleasedBy()); + return OpenApiBeanUtils.transformFromReleaseDTO(publish); } @PutMapping(path = "/releases/{releaseId}/rollback") public void rollback(@PathVariable String env, @PathVariable long releaseId, @RequestParam String operator, HttpServletRequest request) { - RequestPrecondition.checkArguments(!StringUtils.isContainEmpty(operator), - "Param operator can not be empty"); + boolean doesContainEmpty = StringUtils.isContainEmpty(operator); + RequestPrecondition.checkArguments(!doesContainEmpty, "Param operator can not be empty"); if (userService.findByUserId(operator) == null) { throw BadRequestException.userNotExists(operator); @@ -188,4 +179,11 @@ public void rollback(@PathVariable String env, this.releaseOpenApiService.rollbackRelease(env, releaseId, operator); } + private void populateReleaseModel(NamespaceReleaseModel releaseModel, String appId, String env, String branchName, String namespaceName) { + releaseModel.setAppId(appId); + releaseModel.setEnv(env.toUpperCase()); + releaseModel.setClusterName(branchName); + releaseModel.setNamespaceName(namespaceName); + } + } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/EmailConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/EmailConfig.java new file mode 100644 index 00000000000..010f3b109c6 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/EmailConfig.java @@ -0,0 +1,54 @@ +package com.ctrip.framework.apollo.portal.component.config; + +import com.ctrip.framework.apollo.common.config.RefreshableConfig; +import com.ctrip.framework.apollo.portal.service.PortalDBPropertySource; +import com.google.common.base.Strings; +import org.springframework.stereotype.Component; + +/** + * This class handled email related configs for portalConfig class + */ +@Component +public class EmailConfig extends RefreshableConfig { + + public EmailConfig(final PortalDBPropertySource portalDBPropertySource) { + super(portalDBPropertySource); + } + + public String emailSender() { + String value = getValue(PortalConfigConstants.EMAIL_SENDER, ""); + return Strings.isNullOrEmpty(value) ? emailConfigUser() : value; + } + + public String emailConfigHost() { + return getValue(PortalConfigConstants.EMAIL_CONFIG_HOST, ""); + } + + public String emailConfigPassword() { + return getValue(PortalConfigConstants.EMAIL_CONFIG_PASSWORD, ""); + } + + public String emailTemplateFramework() { + return getValue(PortalConfigConstants.EMAIL_TEMPLATE_FRAMEWORK, ""); + } + + public String emailReleaseDiffModuleTemplate() { + return getValue(PortalConfigConstants.EMAIL_RELEASE_MODULE_DIFF, ""); + } + + public String emailRollbackDiffModuleTemplate() { + return getValue(PortalConfigConstants.EMAIL_ROLLBACK_MODULE_DIFF, ""); + } + + public String emailGrayRulesModuleTemplate() { + return getValue(PortalConfigConstants.EMAIL_RELEASE_MODULE_RULES, ""); + } + + public String emailConfigUser() { + return getValue(PortalConfigConstants.EMAIL_CONFIG_USER, ""); + } + + public boolean isEmailEnabled() { + return getBooleanProperty(PortalConfigConstants.EMAIL_ENABLED, false); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/EnvConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/EnvConfig.java new file mode 100644 index 00000000000..d05fe95346a --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/EnvConfig.java @@ -0,0 +1,71 @@ +package com.ctrip.framework.apollo.portal.component.config; + +import com.ctrip.framework.apollo.common.config.RefreshableConfig; +import com.ctrip.framework.apollo.portal.environment.Env; +import com.ctrip.framework.apollo.portal.service.PortalDBPropertySource; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Set; + +/** + * This class handled environment related configs for portalConfig class + */ +@Component +public class EnvConfig extends RefreshableConfig { + + public EnvConfig(final PortalDBPropertySource portalDBPropertySource) { + super(portalDBPropertySource); + } + + public List portalSupportedEnvs() { + String[] configurations = getArrayProperty(PortalConfigConstants.APOLLO_PORTAL_ENVS, new String[]{"FAT", "UAT", "PRO"}); + List envs = Lists.newLinkedList(); + + for (String env : configurations) { + envs.add(Env.addEnvironment(env)); + } + + return envs; + } + + public int getPerEnvSearchMaxResults() { + return getIntProperty(PortalConfigConstants.PER_ENV_MAX_RESULTS, 200); + } + + public Set emailSupportedEnvs() { + return getSupportedEnvs(PortalConfigConstants.EMAIL_SUPPORTED_ENVS); + } + + public Set webHookSupportedEnvs() { + return getSupportedEnvs(PortalConfigConstants.WEBHOOK_SUPPORTED_ENVS); + } + + private Set getSupportedEnvs(String key) { + String[] configurations = getArrayProperty(key, null); + Set result = Sets.newHashSet(); + if (configurations != null) { + for (String env : configurations) { + result.add(Env.valueOf(env)); + } + } + return result; + } + + public Set publishTipsSupportedEnvs() { + String[] configurations = getArrayProperty(PortalConfigConstants.NAMESPACE_PUBLISH_TIPS_SUPPORTED_ENVS_KEY, null); + + Set result = Sets.newHashSet(); + if (configurations == null || configurations.length == 0) { + return result; + } + + for (String env : configurations) { + result.add(Env.valueOf(env)); + } + + return result; + } + +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java index 982515be490..c75b508c3d6 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfig.java @@ -15,314 +15,189 @@ * */ package com.ctrip.framework.apollo.portal.component.config; - -import com.ctrip.framework.apollo.common.config.RefreshableConfig; -import com.ctrip.framework.apollo.common.config.RefreshablePropertySource; import com.ctrip.framework.apollo.portal.entity.vo.Organization; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.service.PortalDBPropertySource; -import com.ctrip.framework.apollo.portal.service.SystemRoleManagerService; -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class PortalConfig extends RefreshableConfig { - - private static final Logger logger = LoggerFactory.getLogger(PortalConfig.class); - - private static final int DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_NORMAL_INTERVAL_IN_SECOND = 5 * 60; //5min - private static final int DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND = 10; //10s +public class PortalConfig { - private static final Gson GSON = new Gson(); - private static final Type ORGANIZATION = new TypeToken>() { - }.getType(); - - private static final List DEFAULT_USER_PASSWORD_NOT_ALLOW_LIST = Arrays.asList( - "111", "222", "333", "444", "555", "666", "777", "888", "999", "000", - "001122", "112233", "223344", "334455", "445566", "556677", "667788", "778899", "889900", - "009988", "998877", "887766", "776655", "665544", "554433", "443322", "332211", "221100", - "0123", "1234", "2345", "3456", "4567", "5678", "6789", "7890", - "0987", "9876", "8765", "7654", "6543", "5432", "4321", "3210", - "1q2w", "2w3e", "3e4r", "5t6y", "abcd", "qwer", "asdf", "zxcv" - ); - - /** - * meta servers config in "PortalDB.ServerConfig" - */ - private static final Type META_SERVERS = new TypeToken>(){}.getType(); - - private final PortalDBPropertySource portalDBPropertySource; + @Autowired + private final EmailConfig emailConfig; + @Autowired + private final ServerConfig serverConfig; + @Autowired + private final SecurityConfig securityConfig; + @Autowired + private final EnvConfig envConfig; public PortalConfig(final PortalDBPropertySource portalDBPropertySource) { - this.portalDBPropertySource = portalDBPropertySource; - } - - @Override - public List getRefreshablePropertySources() { - return Collections.singletonList(portalDBPropertySource); + this.emailConfig = new EmailConfig(portalDBPropertySource); + this.securityConfig = new SecurityConfig(portalDBPropertySource); + this.envConfig = new EnvConfig(portalDBPropertySource); + this.serverConfig = new ServerConfig(portalDBPropertySource); } /*** * Level: important **/ public List portalSupportedEnvs() { - String[] configurations = getArrayProperty("apollo.portal.envs", new String[]{"FAT", "UAT", "PRO"}); - List envs = Lists.newLinkedList(); - - for (String env : configurations) { - envs.add(Env.addEnvironment(env)); - } - - return envs; + return envConfig.portalSupportedEnvs(); } - public int getPerEnvSearchMaxResults() {return getIntProperty("apollo.portal.search.perEnvMaxResults", 200);} + public int getPerEnvSearchMaxResults() { + return envConfig.getPerEnvSearchMaxResults(); + } /** * @return the relationship between environment and its meta server. empty if meet exception */ public Map getMetaServers() { - final String key = "apollo.portal.meta.servers"; - String jsonContent = getValue(key); - if (null == jsonContent) { - return Collections.emptyMap(); - } - - // watch out that the format of content may be wrong - // that will cause exception - Map map = Collections.emptyMap(); - try { - // try to parse - map = GSON.fromJson(jsonContent, META_SERVERS); - } catch (Exception e) { - logger.error("Wrong format for: {}", key, e); - } - return map; + return serverConfig.getMetaServers(); } public List superAdmins() { - String superAdminConfig = getValue("superAdmin", ""); - if (Strings.isNullOrEmpty(superAdminConfig)) { - return Collections.emptyList(); - } - return splitter.splitToList(superAdminConfig); + return serverConfig.superAdmins(); } public Set emailSupportedEnvs() { - String[] configurations = getArrayProperty("email.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null || configurations.length == 0) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return envConfig.emailSupportedEnvs(); } public Set webHookSupportedEnvs() { - String[] configurations = getArrayProperty("webhook.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null || configurations.length == 0) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return envConfig.webHookSupportedEnvs(); } public boolean isConfigViewMemberOnly(String env) { - String[] configViewMemberOnlyEnvs = getArrayProperty("configView.memberOnly.envs", new String[0]); - - for (String memberOnlyEnv : configViewMemberOnlyEnvs) { - if (memberOnlyEnv.equalsIgnoreCase(env)) { - return true; - } - } - - return false; + return securityConfig.isConfigViewMemberOnly(env); } /*** * Level: normal **/ public int connectTimeout() { - return getIntProperty("api.connectTimeout", 3000); + return serverConfig.connectTimeout(); } public int readTimeout() { - return getIntProperty("api.readTimeout", 10000); + return serverConfig.readTimeout(); } public int connectionTimeToLive() { - return getIntProperty("api.connectionTimeToLive", -1); + return serverConfig.connectionTimeToLive(); } public int connectPoolMaxTotal() { - return getIntProperty("api.pool.max.total", 20); + return serverConfig.connectPoolMaxTotal(); } public int connectPoolMaxPerRoute() { - return getIntProperty("api.pool.max.per.route", 2); + return serverConfig.connectPoolMaxPerRoute(); } public List organizations() { - - String organizations = getValue("organizations"); - return organizations == null ? Collections.emptyList() : GSON.fromJson(organizations, ORGANIZATION); + return serverConfig.organizations(); } public String portalAddress() { - return getValue("apollo.portal.address"); + return serverConfig.portalAddress(); } public int refreshAdminServerAddressTaskNormalIntervalSecond() { - int interval = getIntProperty("refresh.admin.server.address.task.normal.interval.second", DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_NORMAL_INTERVAL_IN_SECOND); - return checkInt(interval, 5, Integer.MAX_VALUE, DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_NORMAL_INTERVAL_IN_SECOND); + return serverConfig.refreshAdminServerAddressTaskNormalIntervalSecond(); } public int refreshAdminServerAddressTaskOfflineIntervalSecond() { - int interval = getIntProperty("refresh.admin.server.address.task.offline.interval.second", DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND); - return checkInt(interval, 5, Integer.MAX_VALUE, DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND); + return serverConfig.refreshAdminServerAddressTaskOfflineIntervalSecond(); } public boolean isEmergencyPublishAllowed(Env env) { - String targetEnv = env.getName(); - - String[] emergencyPublishSupportedEnvs = getArrayProperty("emergencyPublish.supported.envs", new String[0]); - - for (String supportedEnv : emergencyPublishSupportedEnvs) { - if (Objects.equals(targetEnv, supportedEnv.toUpperCase().trim())) { - return true; - } - } - - return false; + return serverConfig.isEmergencyPublishAllowed(env); } /*** * Level: low **/ public Set publishTipsSupportedEnvs() { - String[] configurations = getArrayProperty("namespace.publish.tips.supported.envs", null); - - Set result = Sets.newHashSet(); - if (configurations == null || configurations.length == 0) { - return result; - } - - for (String env : configurations) { - result.add(Env.valueOf(env)); - } - - return result; + return envConfig.publishTipsSupportedEnvs(); } public String consumerTokenSalt() { - return getValue("consumer.token.salt", "apollo-portal"); + return serverConfig.consumerTokenSalt(); } public boolean isEmailEnabled() { - return getBooleanProperty("email.enabled", false); + return emailConfig.isEmailEnabled(); } public String emailConfigHost() { - return getValue("email.config.host", ""); + return emailConfig.emailConfigHost(); } public String emailConfigUser() { - return getValue("email.config.user", ""); + return emailConfig.emailConfigUser(); } public String emailConfigPassword() { - return getValue("email.config.password", ""); + return emailConfig.emailConfigPassword(); } public String emailSender() { - String value = getValue("email.sender", ""); - if (Strings.isNullOrEmpty(value)) { - value = emailConfigUser(); - } - return value; + return emailConfig.emailSender(); } public String emailTemplateFramework() { - return getValue("email.template.framework", ""); + return emailConfig.emailTemplateFramework(); } public String emailReleaseDiffModuleTemplate() { - return getValue("email.template.release.module.diff", ""); + return emailConfig.emailReleaseDiffModuleTemplate(); } public String emailRollbackDiffModuleTemplate() { - return getValue("email.template.rollback.module.diff", ""); + return emailConfig.emailRollbackDiffModuleTemplate(); } public String emailGrayRulesModuleTemplate() { - return getValue("email.template.release.module.rules", ""); + return emailConfig.emailGrayRulesModuleTemplate(); } public String wikiAddress() { - return getValue("wiki.address", "https://www.apolloconfig.com"); + return serverConfig.wikiAddress(); } public boolean canAppAdminCreatePrivateNamespace() { - return getBooleanProperty("admin.createPrivateNamespace.switch", true); + return securityConfig.canAppAdminCreatePrivateNamespace(); } public boolean isCreateApplicationPermissionEnabled() { - return getBooleanProperty(SystemRoleManagerService.CREATE_APPLICATION_LIMIT_SWITCH_KEY, false); + return securityConfig.isCreateApplicationPermissionEnabled(); } public boolean isManageAppMasterPermissionEnabled() { - return getBooleanProperty(SystemRoleManagerService.MANAGE_APP_MASTER_LIMIT_SWITCH_KEY, false); + return securityConfig.isManageAppMasterPermissionEnabled(); } public String getAdminServiceAccessTokens() { - return getValue("admin-service.access.tokens"); + return serverConfig.getAdminServiceAccessTokens(); } public String[] webHookUrls() { - return getArrayProperty("config.release.webhook.service.url", null); + return serverConfig.webHookUrls(); } public boolean supportSearchByItem() { - return getBooleanProperty("searchByItem.switch", true); + return serverConfig.supportSearchByItem(); } public List getUserPasswordNotAllowList() { - String[] value = getArrayProperty("apollo.portal.auth.user-password-not-allow-list", null); - if (value == null || value.length == 0) { - return DEFAULT_USER_PASSWORD_NOT_ALLOW_LIST; - } - return Arrays.asList(value); + return securityConfig.getUserPasswordNotAllowList(); } - private int checkInt(int value, int min, int max, int defaultValue) { - if (value >= min && value <= max) { - return value; - } - logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", value, min, max, defaultValue); - return defaultValue; - } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigConstants.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigConstants.java new file mode 100644 index 00000000000..251a920d2b5 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/PortalConfigConstants.java @@ -0,0 +1,64 @@ +package com.ctrip.framework.apollo.portal.component.config; + +/** + * This class holds all the constants used in the config classes + */ +class PortalConfigConstants { + + private PortalConfigConstants() {} + + // Configuration keys + static final String APOLLO_PORTAL_ENVS = "apollo.portal.envs"; + static final String PER_ENV_MAX_RESULTS = "apollo.portal.search.perEnvMaxResults"; + static final String APOLLO_META_SERVERS = "apollo.portal.meta.servers"; + static final String SUPER_ADMIN = "superAdmin"; + static final String EMAIL_SUPPORTED_ENVS = "email.supported.envs"; + static final String WEBHOOK_SUPPORTED_ENVS = "webhook.supported.envs"; + + // API properties + static final String API_CONNECTION_TIMEOUT = "api.connectTimeout"; + static final String API_READ_TIMEOUT = "api.readTimeout"; + static final String API_TIME_TO_LIVE = "api.connectionTimeToLive"; + static final String API_POOL_MAX_TOTAL = "api.pool.max.total"; + static final String API_POOL_MAX_PER_ROUTE = "api.pool.max.per.route"; + + // Email template properties + static final String EMAIL_TEMPLATE_FRAMEWORK = "email.template.framework"; + static final String EMAIL_RELEASE_MODULE_DIFF = "email.template.release.module.diff"; + static final String EMAIL_ROLLBACK_MODULE_DIFF = "email.template.rollback.module.diff"; + static final String EMAIL_RELEASE_MODULE_RULES = "email.template.release.module.rules"; + + // Email properties + static final String EMAIL_ENABLED = "email.enabled"; + static final String EMAIL_CONFIG_HOST = "email.config.host"; + static final String EMAIL_CONFIG_USER = "email.config.user"; + static final String EMAIL_CONFIG_PASSWORD= "email.config.password"; + static final String EMAIL_SENDER = "email.sender"; + + static final String DEFAULT_ORGANIZATION_KEY = "organizations"; + static final String DEFAULT_PORTAL_ADDRESS_KEY = "apollo.portal.address"; + + // Admin server keys + static final String REFRESH_ADMIN_SERVER_NORMAL_INTERVAL_KEY = "refresh.admin.server.address.task.normal.interval.second"; + static final String REFRESH_ADMIN_SERVER_OFFLINE_INTERVAL_KEY = "refresh.admin.server.address.task.offline.interval.second"; + static final String ADMIN_SERVICE_ACCESS_TOKENS_KEY = "admin-service.access.tokens"; + + // Other keys + static final String CONFIG_VIEW_MEMBER_ONLY_ENVS_KEY = "configView.memberOnly.envs"; + static final String EMERGENCY_PUBLISH_SUPPORTED_ENVS_KEY = "emergencyPublish.supported.envs"; + static final String NAMESPACE_PUBLISH_TIPS_SUPPORTED_ENVS_KEY = "namespace.publish.tips.supported.envs"; + static final String CONFIG_RELEASE_WEBHOOK_SERVICE_URL_KEY = "config.release.webhook.service.url"; + static final String SEARCH_BY_ITEM_SWITCH_KEY = "searchByItem.switch"; + + // Consumer keys + static final String CONSUMER_TOKEN_SALT_KEY = "consumer.token.salt"; + static final String CONSUMER_TOKEN_DEFAULT_VALUE = "apollo-portal"; + + // Wiki address keys + static final String WIKI_ADDRESS_KEY = "wiki.address"; + static final String WIKI_ADDRESS_DEFAULT_VALUE = "https://www.apolloconfig.com"; + static final String ADMIN_PRIVATE_NAMESPACE_SWITCH = "admin.createPrivateNamespace.switch"; + + // User password not allowed list key + static final String AUTH_USER_PASSWORD_NOT_ALLOW_LIST_KEY = "apollo.portal.auth.user-password-not-allow-list"; +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/SecurityConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/SecurityConfig.java new file mode 100644 index 00000000000..f06c8fe795b --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/SecurityConfig.java @@ -0,0 +1,63 @@ +package com.ctrip.framework.apollo.portal.component.config; + +import com.ctrip.framework.apollo.common.config.RefreshableConfig; +import com.ctrip.framework.apollo.portal.service.PortalDBPropertySource; +import com.ctrip.framework.apollo.portal.service.SystemRoleManagerService; +import com.google.common.collect.Lists; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * This class handled security related configs for portalConfig class + */ +@Component +public class SecurityConfig extends RefreshableConfig { + + private static final List DEFAULT_USER_PASSWORD_NOT_ALLOW_LIST = Arrays.asList( + "111", "222", "333", "444", "555", "666", "777", "888", "999", "000", + "001122", "112233", "223344", "334455", "445566", "556677", "667788", "778899", "889900", + "009988", "998877", "887766", "776655", "665544", "554433", "443322", "332211", "221100", + "0123", "1234", "2345", "3456", "4567", "5678", "6789", "7890", + "0987", "9876", "8765", "7654", "6543", "5432", "4321", "3210", + "1q2w", "2w3e", "3e4r", "5t6y", "abcd", "qwer", "asdf", "zxcv" + ); + + public SecurityConfig(final PortalDBPropertySource portalDBPropertySource) { + super(portalDBPropertySource); + } + + public List getUserPasswordNotAllowList() { + String[] value = getArrayProperty(PortalConfigConstants.AUTH_USER_PASSWORD_NOT_ALLOW_LIST_KEY, null); + if (value == null || value.length == 0) { + return DEFAULT_USER_PASSWORD_NOT_ALLOW_LIST; + } + return Lists.newArrayList(value); + } + + public boolean canAppAdminCreatePrivateNamespace() { + return getBooleanProperty(PortalConfigConstants.ADMIN_PRIVATE_NAMESPACE_SWITCH, true); + } + + public boolean isCreateApplicationPermissionEnabled() { + return getBooleanProperty(SystemRoleManagerService.CREATE_APPLICATION_LIMIT_SWITCH_KEY, false); + } + + public boolean isManageAppMasterPermissionEnabled() { + return getBooleanProperty(SystemRoleManagerService.MANAGE_APP_MASTER_LIMIT_SWITCH_KEY, false); + } + + public boolean isConfigViewMemberOnly(String env) { + String[] configViewMemberOnlyEnvs = getArrayProperty(PortalConfigConstants.CONFIG_VIEW_MEMBER_ONLY_ENVS_KEY, new String[0]); + + for (String memberOnlyEnv : configViewMemberOnlyEnvs) { + if (memberOnlyEnv.equalsIgnoreCase(env)) { + return true; + } + } + + return false; + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/ServerConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/ServerConfig.java new file mode 100644 index 00000000000..c8713ad16e9 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/config/ServerConfig.java @@ -0,0 +1,143 @@ +package com.ctrip.framework.apollo.portal.component.config; + +import com.ctrip.framework.apollo.common.config.RefreshableConfig; +import com.ctrip.framework.apollo.portal.entity.vo.Organization; +import com.ctrip.framework.apollo.portal.environment.Env; +import com.ctrip.framework.apollo.portal.service.PortalDBPropertySource; +import com.google.common.base.Strings; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * This class handled server related configs for portalConfig class + */ +@Component +public class ServerConfig extends RefreshableConfig { + + private static final Logger logger = LoggerFactory.getLogger(ServerConfig.class); + + private static final int DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_NORMAL_INTERVAL_IN_SECOND = 5 * 60; //5min + private static final int DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND = 10; //10s + + private static final Gson GSON = new Gson(); + + private static final Type ORGANIZATION = new TypeToken>() {}.getType(); + + /** + * meta servers config in "PortalDB.ServerConfig" + */ + private static final Type META_SERVERS = new TypeToken>() {}.getType(); + + public ServerConfig(final PortalDBPropertySource portalDBPropertySource) { + super(portalDBPropertySource); + } + + public String portalAddress() { + return getValue(PortalConfigConstants.DEFAULT_PORTAL_ADDRESS_KEY); + } + + public Map getMetaServers() { + final String key = PortalConfigConstants.APOLLO_META_SERVERS; + String jsonContent = getValue(key); + if (jsonContent == null) { + return Collections.emptyMap(); + } + try { + return GSON.fromJson(jsonContent, META_SERVERS); + } catch (Exception e) { + logger.error("Wrong format for: {}", key, e); + return Collections.emptyMap(); + } + } + + public int refreshAdminServerAddressTaskNormalIntervalSecond() { + int interval = getIntProperty(PortalConfigConstants.REFRESH_ADMIN_SERVER_NORMAL_INTERVAL_KEY, DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_NORMAL_INTERVAL_IN_SECOND); + return checkInt(interval, 5, Integer.MAX_VALUE, DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_NORMAL_INTERVAL_IN_SECOND); + } + + public int refreshAdminServerAddressTaskOfflineIntervalSecond() { + int interval = getIntProperty(PortalConfigConstants.REFRESH_ADMIN_SERVER_OFFLINE_INTERVAL_KEY, DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND); + return checkInt(interval, 5, Integer.MAX_VALUE, DEFAULT_REFRESH_ADMIN_SERVER_ADDRESS_TASK_OFFLINE_INTERVAL_IN_SECOND); + } + + private int checkInt(int value, int min, int max, int defaultValue) { + if (value >= min && value <= max) { + return value; + } + logger.warn("Configuration value '{}' is out of bounds [{} - {}]. Using default value '{}'.", value, min, max, defaultValue); + return defaultValue; + } + + public List superAdmins() { + String superAdminConfig = getValue(PortalConfigConstants.SUPER_ADMIN, ""); + if (Strings.isNullOrEmpty(superAdminConfig)) { + return Collections.emptyList(); + } + return splitter.splitToList(superAdminConfig); + } + + public String getAdminServiceAccessTokens() { + return getValue(PortalConfigConstants.ADMIN_SERVICE_ACCESS_TOKENS_KEY); + } + + public String[] webHookUrls() { + return getArrayProperty(PortalConfigConstants.CONFIG_RELEASE_WEBHOOK_SERVICE_URL_KEY, null); + } + + public boolean supportSearchByItem() { + return getBooleanProperty(PortalConfigConstants.SEARCH_BY_ITEM_SWITCH_KEY, true); + } + + public List organizations() { + + String organizations = getValue(PortalConfigConstants.DEFAULT_ORGANIZATION_KEY); + return organizations == null ? Collections.emptyList() : GSON.fromJson(organizations, ORGANIZATION); + } + + public int connectTimeout() { + return getIntProperty(PortalConfigConstants.API_CONNECTION_TIMEOUT, 3000); + } + + public int readTimeout() { + return getIntProperty(PortalConfigConstants.API_READ_TIMEOUT, 10000); + } + + public int connectionTimeToLive() { + return getIntProperty(PortalConfigConstants.API_TIME_TO_LIVE, -1); + } + + public int connectPoolMaxTotal() { + return getIntProperty(PortalConfigConstants.API_POOL_MAX_TOTAL, 20); + } + + public String consumerTokenSalt() { + return getValue(PortalConfigConstants.CONSUMER_TOKEN_SALT_KEY, PortalConfigConstants.CONSUMER_TOKEN_DEFAULT_VALUE); + } + + public String wikiAddress() { + return getValue(PortalConfigConstants.WIKI_ADDRESS_KEY, PortalConfigConstants.WIKI_ADDRESS_DEFAULT_VALUE); + } + + public int connectPoolMaxPerRoute() { + return getIntProperty(PortalConfigConstants.API_POOL_MAX_PER_ROUTE, 2); + } + + public boolean isEmergencyPublishAllowed(Env env) { + String targetEnv = env.getName(); + String[] emergencyPublishSupportedEnvs = getArrayProperty(PortalConfigConstants.EMERGENCY_PUBLISH_SUPPORTED_ENVS_KEY, new String[0]); + + for (String supportedEnv : emergencyPublishSupportedEnvs) { + if (targetEnv.equalsIgnoreCase(supportedEnv.trim())) { + return true; + } + } + return false; + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/emailbuilder/ConfigPublishEmailBuilder.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/emailbuilder/ConfigPublishEmailBuilder.java index c5f155a97c1..f59cc377377 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/emailbuilder/ConfigPublishEmailBuilder.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/emailbuilder/ConfigPublishEmailBuilder.java @@ -179,7 +179,7 @@ private String renderDiffModule(String bodyTemplate, Env env, ReleaseHistoryBO r return bodyTemplate.replaceAll(EMAIL_CONTENT_DIFF_MODULE, "

变更内容请点击链接到Apollo上查看

"); } - ReleaseCompareResult result = getReleaseCompareResult(env, releaseHistory); + ReleaseCompareResult result = releaseService.compareReleaseHistory(env, releaseHistory); if (!result.hasContent()) { return bodyTemplate.replaceAll(EMAIL_CONTENT_DIFF_MODULE, "

无配置变更

"); @@ -208,19 +208,6 @@ private String renderDiffModule(String bodyTemplate, Env env, ReleaseHistoryBO r return bodyTemplate.replaceAll(EMAIL_CONTENT_DIFF_MODULE, diffModuleRenderResult); } - private ReleaseCompareResult getReleaseCompareResult(Env env, ReleaseHistoryBO releaseHistory) { - if (releaseHistory.getOperation() == ReleaseOperation.GRAY_RELEASE - && releaseHistory.getPreviousReleaseId() == 0) { - ReleaseDTO masterLatestActiveRelease = releaseService.loadLatestRelease( - releaseHistory.getAppId(), env, releaseHistory.getClusterName(), releaseHistory.getNamespaceName()); - ReleaseDTO branchLatestActiveRelease = releaseService.findReleaseById(env, releaseHistory.getReleaseId()); - - return releaseService.compare(masterLatestActiveRelease, branchLatestActiveRelease); - } - - return releaseService.compare(env, releaseHistory.getPreviousReleaseId(), releaseHistory.getReleaseId()); - } - private List recipients(String appId, String namespaceName, String env) { Set modifyRoleUsers = rolePermissionService diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/listener/ConfigPublishListener.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/listener/ConfigPublishListener.java index 1c2f2a14a72..76281ce30e0 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/listener/ConfigPublishListener.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/listener/ConfigPublishListener.java @@ -32,6 +32,7 @@ import com.ctrip.framework.apollo.portal.spi.MQService; import com.ctrip.framework.apollo.tracer.Tracer; import org.springframework.context.event.EventListener; +import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsImportService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsImportService.java index 1dfd337a2e8..f9da6f2db47 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsImportService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsImportService.java @@ -173,76 +173,39 @@ public void importDataFromZipFile(List importEnvs, ZipInputStream dataZip, } } - private void doImport(List importEnvs, List toImportApps, List toImportAppNSs, - List toImportClusters, List toImportNSs) - throws InterruptedException { - LOGGER.info("Start to import app. size = {}", toImportApps.size()); - + private void doImport(List importEnvs, + List toImportApps, + List toImportAppNSs, + List toImportClusters, + List toImportNSs) throws InterruptedException { String operator = userInfoHolder.getUser().getUserId(); - long startTime = System.currentTimeMillis(); - CountDownLatch appLatch = new CountDownLatch(toImportApps.size()); - toImportApps.parallelStream().forEach(app -> { - try { - importApp(app, importEnvs, operator); - } catch (Exception e) { - LOGGER.error("import app error. app = {}", app, e); - } finally { - appLatch.countDown(); - } - }); - appLatch.await(); - - LOGGER.info("Finish to import app. duration = {}", System.currentTimeMillis() - startTime); - LOGGER.info("Start to import appnamespace. size = {}", toImportAppNSs.size()); - - startTime = System.currentTimeMillis(); - CountDownLatch appNSLatch = new CountDownLatch(toImportAppNSs.size()); - toImportAppNSs.parallelStream().forEach(appNS -> { - try { - importAppNamespace(appNS, operator); - } catch (Exception e) { - LOGGER.error("import appnamespace error. appnamespace = {}", appNS, e); - } finally { - appNSLatch.countDown(); - } - }); - appNSLatch.await(); - - LOGGER.info("Finish to import appnamespace. duration = {}", System.currentTimeMillis() - startTime); - LOGGER.info("Start to import cluster. size = {}", toImportClusters.size()); + importEntities("app", toImportApps, app -> importApp(app, importEnvs, operator)); + importEntities("appnamespace", toImportAppNSs, appNS -> importAppNamespace(appNS, operator)); + importEntities("cluster", toImportClusters, cluster -> importCluster(cluster, operator)); + importEntities("namespace", toImportNSs, namespace -> + importNamespaceFromText(namespace.getEnv(), namespace.getFileName(), namespace.getContent(), + namespace.isIgnoreConflictNamespace(), operator)); + } - startTime = System.currentTimeMillis(); - CountDownLatch clusterLatch = new CountDownLatch(toImportClusters.size()); - toImportClusters.parallelStream().forEach(cluster -> { - try { - importCluster(cluster, operator); - } catch (Exception e) { - LOGGER.error("import cluster error. cluster = {}", cluster, e); - } finally { - clusterLatch.countDown(); - } - }); - clusterLatch.await(); + private void importEntities(String entityName, List entities, ImportTaskService importTask) throws InterruptedException { + LOGGER.info("Start to import {}. size = {}", entityName, entities.size()); - LOGGER.info("Finish to import cluster. duration = {}", System.currentTimeMillis() - startTime); - LOGGER.info("Start to import namespace. size = {}", toImportNSs.size()); + long startTime = System.currentTimeMillis(); + CountDownLatch latch = new CountDownLatch(entities.size()); - startTime = System.currentTimeMillis(); - CountDownLatch nsLatch = new CountDownLatch(toImportNSs.size()); - toImportNSs.parallelStream().forEach(namespace -> { + entities.parallelStream().forEach(entity -> { try { - importNamespaceFromText(namespace.getEnv(), namespace.getFileName(), namespace.getContent(), - namespace.isIgnoreConflictNamespace(), operator); + importTask.execute(entity); } catch (Exception e) { - LOGGER.error("import namespace error. namespace = {}", namespace, e); + LOGGER.error("Import {} error. entity = {}", entityName, entity, e); } finally { - nsLatch.countDown(); + latch.countDown(); } }); - nsLatch.await(); - LOGGER.info("Finish to import namespace. duration = {}", System.currentTimeMillis() - startTime); + latch.await(); + LOGGER.info("Finish to import {}. duration = {}", entityName, System.currentTimeMillis() - startTime); } private void importApp(String appInfo, List importEnvs, String operator) { diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ImportTaskService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ImportTaskService.java new file mode 100644 index 00000000000..1bcff6c5b83 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ImportTaskService.java @@ -0,0 +1,10 @@ +package com.ctrip.framework.apollo.portal.service; + +/** + * + * Used in ConfigsImportService class to remove duplication from importEntities method + */ +@FunctionalInterface +public interface ImportTaskService { + void execute(T entity); +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseService.java index a21761dc19c..90073addcd3 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ReleaseService.java @@ -17,8 +17,10 @@ package com.ctrip.framework.apollo.portal.service; import com.ctrip.framework.apollo.common.constants.GsonType; +import com.ctrip.framework.apollo.common.constants.ReleaseOperation; import com.ctrip.framework.apollo.common.dto.ItemChangeSets; import com.ctrip.framework.apollo.common.dto.ReleaseDTO; +import com.ctrip.framework.apollo.portal.entity.bo.ReleaseHistoryBO; import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.portal.api.AdminServiceAPI; @@ -216,4 +218,19 @@ public ReleaseCompareResult compare(ReleaseDTO baseRelease, ReleaseDTO toCompare return compareResult; } + + public ReleaseCompareResult compareReleaseHistory(Env env, ReleaseHistoryBO releaseHistory) { + if (releaseHistory.getOperation() == ReleaseOperation.GRAY_RELEASE + && releaseHistory.getPreviousReleaseId() == 0) { + // Load the latest master release and branch release + ReleaseDTO masterLatestActiveRelease = loadLatestRelease( + releaseHistory.getAppId(), env, releaseHistory.getClusterName(), releaseHistory.getNamespaceName()); + ReleaseDTO branchLatestActiveRelease = findReleaseById(env, releaseHistory.getReleaseId()); + + return compare(masterLatestActiveRelease, branchLatestActiveRelease); + } + + // Compare based on previous release and current release + return compare(env, releaseHistory.getPreviousReleaseId(), releaseHistory.getReleaseId()); + } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRoleInitializationService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRoleInitializationService.java index 3c18b9dc0bd..970490e8aab 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRoleInitializationService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/defaultimpl/DefaultRoleInitializationService.java @@ -19,8 +19,8 @@ import com.ctrip.framework.apollo.common.entity.App; import com.ctrip.framework.apollo.common.entity.BaseEntity; import com.ctrip.framework.apollo.core.ConfigConsts; -import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.component.config.PortalConfig; +import com.ctrip.framework.apollo.portal.environment.Env; import com.ctrip.framework.apollo.portal.constant.PermissionType; import com.ctrip.framework.apollo.portal.constant.RoleType; import com.ctrip.framework.apollo.portal.entity.po.Permission; diff --git a/apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/service/ConsumerRolePermissionServiceTest.java b/apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidatorTest.java similarity index 67% rename from apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/service/ConsumerRolePermissionServiceTest.java rename to apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidatorTest.java index 0b81d3cdb4c..3af913feb75 100644 --- a/apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/service/ConsumerRolePermissionServiceTest.java +++ b/apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/auth/ConsumerPermissionValidatorTest.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.openapi.service; +package com.ctrip.framework.apollo.openapi.auth; import com.ctrip.framework.apollo.portal.AbstractIntegrationTest; @@ -29,9 +29,9 @@ /** * @author Jason Song(song_s@ctrip.com) */ -public class ConsumerRolePermissionServiceTest extends AbstractIntegrationTest { +public class ConsumerPermissionValidatorTest extends AbstractIntegrationTest { @Autowired - private ConsumerRolePermissionService consumerRolePermissionService; + private ConsumerPermissionValidator consumerPermissionValidator; @Before public void setUp() throws Exception { @@ -53,13 +53,13 @@ public void testConsumerHasPermission() throws Exception { long anotherConsumerId = 2; long someConsumerWithNoPermission = 3; - assertTrue(consumerRolePermissionService.consumerHasPermission(someConsumerId, somePermissionType, someTargetId)); - assertTrue(consumerRolePermissionService.consumerHasPermission(someConsumerId, anotherPermissionType, anotherTargetId)); - assertTrue(consumerRolePermissionService.consumerHasPermission(anotherConsumerId, somePermissionType, someTargetId)); - assertTrue(consumerRolePermissionService.consumerHasPermission(anotherConsumerId, anotherPermissionType, anotherTargetId)); + assertTrue(consumerPermissionValidator.consumerHasPermission(someConsumerId, somePermissionType, someTargetId)); + assertTrue(consumerPermissionValidator.consumerHasPermission(someConsumerId, anotherPermissionType, anotherTargetId)); + assertTrue(consumerPermissionValidator.consumerHasPermission(anotherConsumerId, somePermissionType, someTargetId)); + assertTrue(consumerPermissionValidator.consumerHasPermission(anotherConsumerId, anotherPermissionType, anotherTargetId)); - assertFalse(consumerRolePermissionService.consumerHasPermission(someConsumerWithNoPermission, somePermissionType, someTargetId)); - assertFalse(consumerRolePermissionService.consumerHasPermission(someConsumerWithNoPermission, anotherPermissionType, anotherTargetId)); + assertFalse(consumerPermissionValidator.consumerHasPermission(someConsumerWithNoPermission, somePermissionType, someTargetId)); + assertFalse(consumerPermissionValidator.consumerHasPermission(someConsumerWithNoPermission, anotherPermissionType, anotherTargetId)); } diff --git a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/config/ConfigTest.java b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/config/ConfigTest.java index f2835cb4458..ed77938242f 100644 --- a/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/config/ConfigTest.java +++ b/apollo-portal/src/test/java/com/ctrip/framework/apollo/portal/config/ConfigTest.java @@ -17,6 +17,7 @@ package com.ctrip.framework.apollo.portal.config; +import com.ctrip.framework.apollo.common.config.RefreshableConfig; import com.ctrip.framework.apollo.portal.AbstractUnitTest; import com.ctrip.framework.apollo.portal.component.config.PortalConfig; @@ -33,7 +34,7 @@ public class ConfigTest extends AbstractUnitTest{ @Mock private ConfigurableEnvironment environment; @InjectMocks - private PortalConfig config; + private RefreshableConfig config; @Test