diff --git a/sentinel-dashboard/pom.xml b/sentinel-dashboard/pom.xml index 7545265004..4df4ee5354 100644 --- a/sentinel-dashboard/pom.xml +++ b/sentinel-dashboard/pom.xml @@ -100,11 +100,10 @@ fastjson - + com.alibaba.csp sentinel-datasource-nacos - test diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java index df6c90e53a..4cc23078f3 100644 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java @@ -23,6 +23,8 @@ import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.util.StringUtil; @@ -59,6 +61,10 @@ public class AuthorityRuleController { private RuleRepository repository; @Autowired private AppManagement appManagement; + @Autowired + private DynamicRuleProvider> authorityRuleNacosProvider; + @Autowired + private DynamicRulePublisher> authorityRuleNacosPublisher; @GetMapping("/rules") @AuthAction(PrivilegeType.READ_RULE) @@ -78,8 +84,7 @@ public Result> apiQueryAllRulesForMachine(@RequestPara return Result.ofFail(-1, "given ip does not belong to given app"); } try { - List rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port); - rules = repository.saveAll(rules); + List rules = authorityRuleNacosProvider.getRules(app); return Result.ofSuccess(rules); } catch (Throwable throwable) { logger.error("Error when querying authority rules", throwable); @@ -192,6 +197,12 @@ public Result apiDeleteRule(@PathVariable("id") Long id) { private boolean publishRules(String app, String ip, Integer port) { List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); - return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules); + try { + authorityRuleNacosPublisher.publish(app, rules); + return true; + } catch (Exception e) { + logger.error("Publish authority rules to Nacos error", e); + return false; + } } } diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java index 4668f55caa..3c74666783 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/DegradeController.java @@ -19,10 +19,8 @@ import java.util.List; import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; -import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; -import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement; -import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType; +import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy; @@ -30,10 +28,13 @@ import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; import com.alibaba.csp.sentinel.dashboard.domain.Result; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -41,6 +42,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -58,27 +60,22 @@ public class DegradeController { @Autowired private RuleRepository repository; @Autowired - private SentinelApiClient sentinelApiClient; - @Autowired private AppManagement appManagement; + @Autowired + @Qualifier("degradeRuleNacosProvider") + private DynamicRuleProvider> ruleProvider; + @Autowired + @Qualifier("degradeRuleNacosPublisher") + private DynamicRulePublisher> rulePublisher; @GetMapping("/rules.json") @AuthAction(PrivilegeType.READ_RULE) - public Result> apiQueryMachineRules(String app, String ip, Integer port) { + public Result> apiQueryMachineRules(@RequestParam String app) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } - if (StringUtil.isEmpty(ip)) { - return Result.ofFail(-1, "ip can't be null or empty"); - } - if (port == null) { - return Result.ofFail(-1, "port can't be null"); - } - if (!appManagement.isValidMachineOfApp(app, ip)) { - return Result.ofFail(-1, "given ip does not belong to given app"); - } try { - List rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port); + List rules = ruleProvider.getRules(app); rules = repository.saveAll(rules); return Result.ofSuccess(rules); } catch (Throwable throwable) { @@ -99,13 +96,11 @@ public Result apiAddRule(@RequestBody DegradeRuleEntity entit entity.setGmtModified(date); try { entity = repository.save(entity); + publishRules(entity.getApp()); } catch (Throwable t) { logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t); return Result.ofThrowable(-1, t); } - if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { - logger.warn("Publish degrade rules failed, app={}", entity.getApp()); - } return Result.ofSuccess(entity); } @@ -133,13 +128,11 @@ public Result apiUpdateRule(@PathVariable("id") Long id, entity.setGmtModified(new Date()); try { entity = repository.save(entity); + publishRules(oldEntity.getApp()); } catch (Throwable t) { logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t); return Result.ofThrowable(-1, t); } - if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { - logger.warn("Publish degrade rules failed, app={}", entity.getApp()); - } return Result.ofSuccess(entity); } @@ -157,19 +150,17 @@ public Result delete(@PathVariable("id") Long id) { try { repository.delete(id); + publishRules(oldEntity.getApp()); } catch (Throwable throwable) { logger.error("Failed to delete degrade rule, id={}", id, throwable); return Result.ofThrowable(-1, throwable); } - if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { - logger.warn("Publish degrade rules failed, app={}", oldEntity.getApp()); - } return Result.ofSuccess(id); } - private boolean publishRules(String app, String ip, Integer port) { - List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); - return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules); + private void publishRules(String app) throws Exception { + List rules = repository.findAllByApp(app); + rulePublisher.publish(app, rules); } private Result checkEntityInternal(DegradeRuleEntity entity) { diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java index 513b44dd58..8ea0122cf4 100644 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java @@ -17,28 +17,23 @@ import java.util.Date; import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; -import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException; -import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; -import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement; -import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.auth.AuthService; import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.util.StringUtil; -import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion; + import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; -import com.alibaba.csp.sentinel.dashboard.util.VersionUtils; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -60,67 +55,30 @@ public class ParamFlowRuleController { private final Logger logger = LoggerFactory.getLogger(ParamFlowRuleController.class); @Autowired - private SentinelApiClient sentinelApiClient; + private RuleRepository repository; @Autowired - private AppManagement appManagement; + @Qualifier("paramFlowRuleNacosProvider") + private DynamicRuleProvider> ruleProvider; @Autowired - private RuleRepository repository; - - private boolean checkIfSupported(String app, String ip, int port) { - try { - return Optional.ofNullable(appManagement.getDetailApp(app)) - .flatMap(e -> e.getMachine(ip, port)) - .flatMap(m -> VersionUtils.parseVersion(m.getVersion()) - .map(v -> v.greaterOrEqual(version020))) - .orElse(true); - // If error occurred or cannot retrieve machine info, return true. - } catch (Exception ex) { - return true; - } - } + @Qualifier("paramFlowRuleNacosPublisher") + private DynamicRulePublisher> rulePublisher; @GetMapping("/rules") @AuthAction(PrivilegeType.READ_RULE) - public Result> apiQueryAllRulesForMachine(@RequestParam String app, - @RequestParam String ip, - @RequestParam Integer port) { + public Result> apiQueryAllRulesForMachine(@RequestParam String app) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app cannot be null or empty"); } - if (StringUtil.isEmpty(ip)) { - return Result.ofFail(-1, "ip cannot be null or empty"); - } - if (port == null || port <= 0) { - return Result.ofFail(-1, "Invalid parameter: port"); - } - if (!appManagement.isValidMachineOfApp(app, ip)) { - return Result.ofFail(-1, "given ip does not belong to given app"); - } - if (!checkIfSupported(app, ip, port)) { - return unsupportedVersion(); - } try { - return sentinelApiClient.fetchParamFlowRulesOfMachine(app, ip, port) - .thenApply(repository::saveAll) - .thenApply(Result::ofSuccess) - .get(); - } catch (ExecutionException ex) { - logger.error("Error when querying parameter flow rules", ex.getCause()); - if (isNotSupported(ex.getCause())) { - return unsupportedVersion(); - } else { - return Result.ofThrowable(-1, ex.getCause()); - } + List rules = ruleProvider.getRules(app); + rules = repository.saveAll(rules); + return Result.ofSuccess(rules); } catch (Throwable throwable) { logger.error("Error when querying parameter flow rules", throwable); return Result.ofFail(-1, throwable.getMessage()); } } - private boolean isNotSupported(Throwable ex) { - return ex instanceof CommandNotFoundException; - } - @PostMapping("/rule") @AuthAction(AuthService.PrivilegeType.WRITE_RULE) public Result apiAddParamFlowRule(@RequestBody ParamFlowRuleEntity entity) { @@ -128,9 +86,6 @@ public Result apiAddParamFlowRule(@RequestBody ParamFlowRul if (checkResult != null) { return checkResult; } - if (!checkIfSupported(entity.getApp(), entity.getIp(), entity.getPort())) { - return unsupportedVersion(); - } entity.setId(null); entity.getRule().setResource(entity.getResource().trim()); Date date = new Date(); @@ -138,15 +93,8 @@ public Result apiAddParamFlowRule(@RequestBody ParamFlowRul entity.setGmtModified(date); try { entity = repository.save(entity); - publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(); + publishRules(entity.getApp()); return Result.ofSuccess(entity); - } catch (ExecutionException ex) { - logger.error("Error when adding new parameter flow rules", ex.getCause()); - if (isNotSupported(ex.getCause())) { - return unsupportedVersion(); - } else { - return Result.ofThrowable(-1, ex.getCause()); - } } catch (Throwable throwable) { logger.error("Error when adding new parameter flow rules", throwable); return Result.ofFail(-1, throwable.getMessage()); @@ -160,12 +108,6 @@ private Result checkEntityInternal(ParamFlowRuleEntity entity) { if (StringUtil.isBlank(entity.getApp())) { return Result.ofFail(-1, "app can't be null or empty"); } - if (StringUtil.isBlank(entity.getIp())) { - return Result.ofFail(-1, "ip can't be null or empty"); - } - if (entity.getPort() == null || entity.getPort() <= 0) { - return Result.ofFail(-1, "port can't be null"); - } if (entity.getRule() == null) { return Result.ofFail(-1, "rule can't be null"); } @@ -206,24 +148,14 @@ public Result apiUpdateParamFlowRule(@PathVariable("id") Lo if (checkResult != null) { return checkResult; } - if (!checkIfSupported(entity.getApp(), entity.getIp(), entity.getPort())) { - return unsupportedVersion(); - } entity.setId(id); Date date = new Date(); entity.setGmtCreate(oldEntity.getGmtCreate()); entity.setGmtModified(date); try { entity = repository.save(entity); - publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(); + publishRules(oldEntity.getApp()); return Result.ofSuccess(entity); - } catch (ExecutionException ex) { - logger.error("Error when updating parameter flow rules, id=" + id, ex.getCause()); - if (isNotSupported(ex.getCause())) { - return unsupportedVersion(); - } else { - return Result.ofThrowable(-1, ex.getCause()); - } } catch (Throwable throwable) { logger.error("Error when updating parameter flow rules, id=" + id, throwable); return Result.ofFail(-1, throwable.getMessage()); @@ -243,30 +175,16 @@ public Result apiDeleteRule(@PathVariable("id") Long id) { try { repository.delete(id); - publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(); + publishRules(oldEntity.getApp()); return Result.ofSuccess(id); - } catch (ExecutionException ex) { - logger.error("Error when deleting parameter flow rules", ex.getCause()); - if (isNotSupported(ex.getCause())) { - return unsupportedVersion(); - } else { - return Result.ofThrowable(-1, ex.getCause()); - } } catch (Throwable throwable) { logger.error("Error when deleting parameter flow rules", throwable); return Result.ofFail(-1, throwable.getMessage()); } } - private CompletableFuture publishRules(String app, String ip, Integer port) { - List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); - return sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules); + private void publishRules(String app) throws Exception { + List rules = repository.findAllByApp(app); + rulePublisher.publish(app, rules); } - - private Result unsupportedVersion() { - return Result.ofFail(4041, - "Sentinel client not supported for parameter flow control (unsupported version or dependency absent)"); - } - - private final SentinelVersion version020 = new SentinelVersion().setMinorVersion(2); } diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java index b3f3577ee3..6b6c001093 100755 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java @@ -22,6 +22,8 @@ import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType; import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity; @@ -51,6 +53,10 @@ public class SystemController { private SentinelApiClient sentinelApiClient; @Autowired private AppManagement appManagement; + @Autowired + private DynamicRuleProvider> systemRuleNacosProvider; + @Autowired + private DynamicRulePublisher> systemRuleNacosPublisher; private Result checkBasicParams(String app, String ip, Integer port) { if (StringUtil.isEmpty(app)) { @@ -80,7 +86,11 @@ public Result> apiQueryMachineRules(String app, String ip return checkResult; } try { - List rules = sentinelApiClient.fetchSystemRuleOfMachine(app, ip, port); + List rules = systemRuleNacosProvider.getRules(app); + rules.forEach(rule -> { + rule.setIp(ip); + rule.setPort(port); + }); rules = repository.saveAll(rules); return Result.ofSuccess(rules); } catch (Throwable throwable) { @@ -251,6 +261,12 @@ public Result delete(Long id) { private boolean publishRules(String app, String ip, Integer port) { List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); - return sentinelApiClient.setSystemRuleOfMachine(app, ip, port, rules); + try { + systemRuleNacosPublisher.publish(app, rules); + return true; + } catch (Exception e) { + logger.error("Publish system rules to Nacos error", e); + return false; + } } } diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiProvider.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiProvider.java index 9f9ce5cc1c..3b23583de7 100644 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiProvider.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiProvider.java @@ -32,7 +32,7 @@ /** * @author Eric Zhao */ -@Component("flowRuleDefaultProvider") +@Component("flowRuleApiProvider") public class FlowRuleApiProvider implements DynamicRuleProvider> { @Autowired diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiPublisher.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiPublisher.java index 9afbcf3467..b905ef6d58 100644 --- a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiPublisher.java +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/FlowRuleApiPublisher.java @@ -31,7 +31,7 @@ * @author Eric Zhao * @since 1.4.0 */ -@Component("flowRuleDefaultPublisher") +@Component("flowRuleApiPublisher") public class FlowRuleApiPublisher implements DynamicRulePublisher> { @Autowired diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/AuthorityRuleNacosProvider.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/AuthorityRuleNacosProvider.java new file mode 100644 index 0000000000..95ddf7e39a --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/AuthorityRuleNacosProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; +import com.alibaba.csp.sentinel.util.StringUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("authorityRuleNacosProvider") +public class AuthorityRuleNacosProvider implements DynamicRuleProvider> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter> converter; + + @Override + public List getRules(String appName) throws Exception { + String rules = configService.getConfig(appName + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, 3000); + if (StringUtil.isEmpty(rules)) { + return new ArrayList<>(); + } + List authorityRules = converter.convert(rules); + return authorityRules.stream() + .map(rule -> AuthorityRuleEntity.fromAuthorityRule(appName, null, null, rule)) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/AuthorityRuleNacosPublisher.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/AuthorityRuleNacosPublisher.java new file mode 100644 index 0000000000..214b997e4f --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/AuthorityRuleNacosPublisher.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; +import com.alibaba.csp.sentinel.util.AssertUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("authorityRuleNacosPublisher") +public class AuthorityRuleNacosPublisher implements DynamicRulePublisher> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter, String> converter; + + @Override + public void publish(String app, List rules) throws Exception { + AssertUtil.notEmpty(app, "app name cannot be empty"); + if (rules == null) { + return; + } + List authorityRules = rules.stream() + .map(AuthorityRuleEntity::getRule) + .collect(Collectors.toList()); + configService.publishConfig(app + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, converter.convert(authorityRules)); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/DegradeRuleNacosProvider.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/DegradeRuleNacosProvider.java new file mode 100644 index 0000000000..9716eec906 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/DegradeRuleNacosProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; +import com.alibaba.csp.sentinel.util.StringUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("degradeRuleNacosProvider") +public class DegradeRuleNacosProvider implements DynamicRuleProvider> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter> converter; + + @Override + public List getRules(String appName) throws Exception { + String rules = configService.getConfig(appName + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, 3000); + if (StringUtil.isEmpty(rules)) { + return new ArrayList<>(); + } + List degradeRules = converter.convert(rules); + return degradeRules.stream() + .map(rule -> DegradeRuleEntity.fromDegradeRule(appName, null, null, rule)) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/DegradeRuleNacosPublisher.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/DegradeRuleNacosPublisher.java new file mode 100644 index 0000000000..182e8750da --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/DegradeRuleNacosPublisher.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; +import com.alibaba.csp.sentinel.util.AssertUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("degradeRuleNacosPublisher") +public class DegradeRuleNacosPublisher implements DynamicRulePublisher> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter, String> converter; + + @Override + public void publish(String app, List rules) throws Exception { + AssertUtil.notEmpty(app, "app name cannot be empty"); + if (rules == null) { + return; + } + List degradeRules = rules.stream() + .map(DegradeRuleEntity::toRule) + .collect(Collectors.toList()); + configService.publishConfig(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, converter.convert(degradeRules)); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/FlowRuleNacosProvider.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/FlowRuleNacosProvider.java new file mode 100644 index 0000000000..907767ebf1 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/FlowRuleNacosProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.util.StringUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Eric Zhao + * @since 1.4.0 + */ +@Component("flowRuleDefaultProvider") +public class FlowRuleNacosProvider implements DynamicRuleProvider> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter> converter; + + @Override + public List getRules(String appName) throws Exception { + String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, 3000); + if (StringUtil.isEmpty(rules)) { + return new ArrayList<>(); + } + List flowRules = converter.convert(rules); + return flowRules.stream() + .map(rule -> FlowRuleEntity.fromFlowRule(appName, null, null, rule)) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/FlowRuleNacosPublisher.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/FlowRuleNacosPublisher.java new file mode 100644 index 0000000000..643d0764ea --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/FlowRuleNacosPublisher.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.util.AssertUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Eric Zhao + * @since 1.4.0 + */ +@Component("flowRuleDefaultPublisher") +public class FlowRuleNacosPublisher implements DynamicRulePublisher> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter, String> converter; + + @Override + public void publish(String app, List rules) throws Exception { + AssertUtil.notEmpty(app, "app name cannot be empty"); + if (rules == null) { + return; + } + List flowRules = rules.stream() + .map(FlowRuleEntity::toRule) + .collect(Collectors.toList()); + configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, converter.convert(flowRules)); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfig.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfig.java new file mode 100644 index 0000000000..bd9d906d4a --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfig.java @@ -0,0 +1,132 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.List; +import java.util.Properties; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; +import com.alibaba.csp.sentinel.slots.system.SystemRule; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.alibaba.nacos.api.config.ConfigFactory; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Eric Zhao + * @since 1.4.0 + */ +@Configuration +public class NacosConfig { + + @Value("${spring.cloud.nacos.config.server-addr:localhost:8848}") + private String serverAddr; + + @Value("${spring.cloud.nacos.config.namespace:}") + private String namespace; + + @Value("${spring.cloud.nacos.config.username:}") + private String username; + + @Value("${spring.cloud.nacos.config.password:}") + private String password; + + @Bean + public Converter, String> flowRuleEntityEncoder() { + return JSON::toJSONString; + } + + @Bean + public Converter> flowRuleEntityDecoder() { + return s -> JSON.parseArray(s, FlowRuleEntity.class); + } + + @Bean + public Converter, String> flowRuleEncoder() { + return JSON::toJSONString; + } + + @Bean + public Converter> flowRuleDecoder() { + return s -> JSON.parseObject(s, new TypeReference>() {}); + } + + @Bean + public Converter, String> degradeRuleEncoder() { + return JSON::toJSONString; + } + + @Bean + public Converter> degradeRuleDecoder() { + return s -> JSON.parseObject(s, new TypeReference>() {}); + } + + @Bean + public Converter, String> paramFlowRuleEncoder() { + return JSON::toJSONString; + } + + @Bean + public Converter> paramFlowRuleDecoder() { + return s -> JSON.parseObject(s, new TypeReference>() {}); + } + + @Bean + public Converter, String> systemRuleEncoder() { + return JSON::toJSONString; + } + + @Bean + public Converter> systemRuleDecoder() { + return s -> JSON.parseObject(s, new TypeReference>() {}); + } + + @Bean + public Converter, String> authorityRuleEncoder() { + return JSON::toJSONString; + } + + @Bean + public Converter> authorityRuleDecoder() { + return s -> JSON.parseObject(s, new TypeReference>() {}); + } + + @Bean + public ConfigService nacosConfigService() throws Exception { + Properties properties = new Properties(); + properties.put("serverAddr", serverAddr); + if (!org.springframework.util.StringUtils.isEmpty(namespace)) { + properties.put("namespace", namespace); + } + if (!org.springframework.util.StringUtils.isEmpty(username)) { + properties.put("username", username); + } + if (!org.springframework.util.StringUtils.isEmpty(password)) { + properties.put("password", password); + } + return ConfigFactory.createConfigService(properties); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfigUtil.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfigUtil.java new file mode 100644 index 0000000000..072237e6c2 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/NacosConfigUtil.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +/** + * @author Eric Zhao + * @since 1.4.0 + */ +public final class NacosConfigUtil { + + public static final String GROUP_ID = "SENTINEL_GROUP"; + + public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules"; + public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules"; + public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules"; + public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules"; + public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules"; + public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map"; + + public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config"; + public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config"; + public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config"; + public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set"; + + private NacosConfigUtil() {} +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/ParamFlowRuleNacosProvider.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/ParamFlowRuleNacosProvider.java new file mode 100644 index 0000000000..14e605e7a1 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/ParamFlowRuleNacosProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; +import com.alibaba.csp.sentinel.util.StringUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("paramFlowRuleNacosProvider") +public class ParamFlowRuleNacosProvider implements DynamicRuleProvider> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter> converter; + + @Override + public List getRules(String appName) throws Exception { + String rules = configService.getConfig(appName + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, 3000); + if (StringUtil.isEmpty(rules)) { + return new ArrayList<>(); + } + List paramFlowRules = converter.convert(rules); + return paramFlowRules.stream() + .map(rule -> ParamFlowRuleEntity.fromParamFlowRule(appName, null, null, rule)) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/ParamFlowRuleNacosPublisher.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/ParamFlowRuleNacosPublisher.java new file mode 100644 index 0000000000..6918570235 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/ParamFlowRuleNacosPublisher.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; +import com.alibaba.csp.sentinel.util.AssertUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("paramFlowRuleNacosPublisher") +public class ParamFlowRuleNacosPublisher implements DynamicRulePublisher> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter, String> converter; + + @Override + public void publish(String app, List rules) throws Exception { + AssertUtil.notEmpty(app, "app name cannot be empty"); + if (rules == null) { + return; + } + List paramFlowRules = rules.stream() + .map(ParamFlowRuleEntity::getRule) + .collect(Collectors.toList()); + configService.publishConfig(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, converter.convert(paramFlowRules)); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/SystemRuleNacosProvider.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/SystemRuleNacosProvider.java new file mode 100644 index 0000000000..7207e39163 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/SystemRuleNacosProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.system.SystemRule; +import com.alibaba.csp.sentinel.util.StringUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("systemRuleNacosProvider") +public class SystemRuleNacosProvider implements DynamicRuleProvider> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter> converter; + + @Override + public List getRules(String appName) throws Exception { + String rules = configService.getConfig(appName + NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, 3000); + if (StringUtil.isEmpty(rules)) { + return new ArrayList<>(); + } + List systemRules = converter.convert(rules); + return systemRules.stream() + .map(rule -> SystemRuleEntity.fromSystemRule(appName, null, null, rule)) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/SystemRuleNacosPublisher.java b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/SystemRuleNacosPublisher.java new file mode 100644 index 0000000000..8be838d005 --- /dev/null +++ b/sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos/SystemRuleNacosPublisher.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.csp.sentinel.dashboard.rule.nacos; + +import java.util.List; +import java.util.stream.Collectors; + +import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity; +import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; +import com.alibaba.csp.sentinel.datasource.Converter; +import com.alibaba.csp.sentinel.slots.system.SystemRule; +import com.alibaba.csp.sentinel.util.AssertUtil; +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("systemRuleNacosPublisher") +public class SystemRuleNacosPublisher implements DynamicRulePublisher> { + + @Autowired + private ConfigService configService; + @Autowired + private Converter, String> converter; + + @Override + public void publish(String app, List rules) throws Exception { + AssertUtil.notEmpty(app, "app name cannot be empty"); + if (rules == null) { + return; + } + List systemRules = rules.stream() + .map(SystemRuleEntity::toRule) + .collect(Collectors.toList()); + configService.publishConfig(app + NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX, + NacosConfigUtil.GROUP_ID, converter.convert(systemRules)); + } +} \ No newline at end of file diff --git a/sentinel-dashboard/src/main/resources/application.properties b/sentinel-dashboard/src/main/resources/application.properties index 1bbb0819a6..2dbcc7eeb8 100755 --- a/sentinel-dashboard/src/main/resources/application.properties +++ b/sentinel-dashboard/src/main/resources/application.properties @@ -21,4 +21,10 @@ auth.password=sentinel # Inject the dashboard version. It's required to enable # filtering in pom.xml for this resource file. -sentinel.dashboard.version=@project.version@ \ No newline at end of file +sentinel.dashboard.version=@project.version@ + +# Nacos config +spring.cloud.nacos.config.server-addr=192.168.234.59:8848 +spring.cloud.nacos.config.namespace=public +spring.cloud.nacos.config.username=nacos +spring.cloud.nacos.config.password=nacos \ No newline at end of file diff --git a/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html b/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html index 40f68d3a83..bdd4722ca2 100755 --- a/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html +++ b/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html @@ -54,7 +54,7 @@
  • - +   流控规则
  • diff --git a/sentinel-dashboard/src/main/webapp/resources/dist/js/app.js b/sentinel-dashboard/src/main/webapp/resources/dist/js/app.js index 47f8b5704c..46bce1d834 100755 --- a/sentinel-dashboard/src/main/webapp/resources/dist/js/app.js +++ b/sentinel-dashboard/src/main/webapp/resources/dist/js/app.js @@ -1 +1 @@ -"use strict";var app;angular.module("sentinelDashboardApp",["oc.lazyLoad","ui.router","ui.bootstrap","angular-loading-bar","ngDialog","ui.bootstrap.datetimepicker","ui-notification","rzTable","angular-clipboard","selectize","angularUtils.directives.dirPagination"]).factory("AuthInterceptor",["$window","$state",function(r,t){return{responseError:function(e){return 401===e.status&&(r.localStorage.removeItem("session_sentinel_admin"),t.go("login")),e},response:function(e){return e},request:function(e){var t=r.document.getElementsByTagName("base")[0].href;return e.url=t+e.url,e},requestError:function(e){return e}}}]).config(["$stateProvider","$urlRouterProvider","$ocLazyLoadProvider","$httpProvider",function(e,t,r,a){a.interceptors.push("AuthInterceptor"),r.config({debug:!1,events:!0}),t.otherwise("/dashboard/home"),e.state("login",{url:"/login",templateUrl:"app/views/login.html",controller:"LoginCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/login.js"]})}]}}).state("dashboard",{url:"/dashboard",templateUrl:"app/views/dashboard/main.html",resolve:{loadMyDirectives:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/directives/header/header.js","app/scripts/directives/sidebar/sidebar.js","app/scripts/directives/sidebar/sidebar-search/sidebar-search.js"]})}]}}).state("dashboard.home",{url:"/home",templateUrl:"app/views/dashboard/home.html",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/main.js"]})}]}}).state("dashboard.flowV1",{templateUrl:"app/views/flow_v1.html",url:"/flow/:app",controller:"FlowControllerV1",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/flow_v1.js"]})}]}}).state("dashboard.flow",{templateUrl:"app/views/flow_v2.html",url:"/v2/flow/:app",controller:"FlowControllerV2",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/flow_v2.js"]})}]}}).state("dashboard.paramFlow",{templateUrl:"app/views/param_flow.html",url:"/paramFlow/:app",controller:"ParamFlowController",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/param_flow.js"]})}]}}).state("dashboard.clusterAppAssignManage",{templateUrl:"app/views/cluster_app_assign_manage.html",url:"/cluster/assign_manage/:app",controller:"SentinelClusterAppAssignManageController",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/cluster_app_assign_manage.js"]})}]}}).state("dashboard.clusterAppServerList",{templateUrl:"app/views/cluster_app_server_list.html",url:"/cluster/server/:app",controller:"SentinelClusterAppServerListController",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/cluster_app_server_list.js"]})}]}}).state("dashboard.clusterAppClientList",{templateUrl:"app/views/cluster_app_client_list.html",url:"/cluster/client/:app",controller:"SentinelClusterAppTokenClientListController",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/cluster_app_token_client_list.js"]})}]}}).state("dashboard.clusterSingle",{templateUrl:"app/views/cluster_single_config.html",url:"/cluster/single/:app",controller:"SentinelClusterSingleController",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/cluster_single.js"]})}]}}).state("dashboard.authority",{templateUrl:"app/views/authority.html",url:"/authority/:app",controller:"AuthorityRuleController",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/authority.js"]})}]}}).state("dashboard.degrade",{templateUrl:"app/views/degrade.html",url:"/degrade/:app",controller:"DegradeCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/degrade.js"]})}]}}).state("dashboard.system",{templateUrl:"app/views/system.html",url:"/system/:app",controller:"SystemCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/system.js"]})}]}}).state("dashboard.machine",{templateUrl:"app/views/machine.html",url:"/app/:app",controller:"MachineCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/machine.js"]})}]}}).state("dashboard.identity",{templateUrl:"app/views/identity.html",url:"/identity/:app",controller:"IdentityCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/identity.js"]})}]}}).state("dashboard.gatewayIdentity",{templateUrl:"app/views/gateway/identity.html",url:"/gateway/identity/:app",controller:"GatewayIdentityCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/gateway/identity.js"]})}]}}).state("dashboard.metric",{templateUrl:"app/views/metric.html",url:"/metric/:app",controller:"MetricCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/metric.js"]})}]}}).state("dashboard.gatewayApi",{templateUrl:"app/views/gateway/api.html",url:"/gateway/api/:app",controller:"GatewayApiCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/gateway/api.js"]})}]}}).state("dashboard.gatewayFlow",{templateUrl:"app/views/gateway/flow.html",url:"/gateway/flow/:app",controller:"GatewayFlowCtl",resolve:{loadMyFiles:["$ocLazyLoad",function(e){return e.load({name:"sentinelDashboardApp",files:["app/scripts/controllers/gateway/flow.js"]})}]}})}]),(app=angular.module("sentinelDashboardApp")).filter("range",[function(){return function(e,t){if(isNaN(t)||t<=0)return[];e=[];for(var r=1;r<=t;r++)e.push(r);return e}}]),(app=angular.module("sentinelDashboardApp")).service("VersionService",["$http",function(e){this.version=function(){return e({url:"/version",method:"GET"})}}]),(app=angular.module("sentinelDashboardApp")).service("AuthService",["$http",function(t){this.check=function(){return t({url:"/auth/check",method:"POST"})},this.login=function(e){return t({url:"/auth/login",params:e,method:"POST"})},this.logout=function(){return t({url:"/auth/logout",method:"POST"})}}]),(app=angular.module("sentinelDashboardApp")).service("AppService",["$http",function(e){this.getApps=function(){return e({url:"app/briefinfos.json",method:"GET"})}}]),(app=angular.module("sentinelDashboardApp")).service("FlowServiceV1",["$http",function(a){function t(e){return void 0===e||""===e||isNaN(e)||e<=0}this.queryMachineRules=function(e,t,r){return a({url:"/v1/flow/rules",params:{app:e,ip:t,port:r},method:"GET"})},this.newRule=function(e){e.resource,e.limitApp,e.grade,e.count,e.strategy,e.refResource,e.controlBehavior,e.warmUpPeriodSec,e.maxQueueingTimeMs,e.app,e.ip,e.port;return a({url:"/v1/flow/rule",data:e,method:"POST"})},this.saveRule=function(e){var t={id:e.id,resource:e.resource,limitApp:e.limitApp,grade:e.grade,count:e.count,strategy:e.strategy,refResource:e.refResource,controlBehavior:e.controlBehavior,warmUpPeriodSec:e.warmUpPeriodSec,maxQueueingTimeMs:e.maxQueueingTimeMs};return a({url:"/v1/flow/save.json",params:t,method:"PUT"})},this.deleteRule=function(e){var t={id:e.id,app:e.app};return a({url:"/v1/flow/delete.json",params:t,method:"DELETE"})},this.checkRuleValid=function(e){return void 0===e.resource||""===e.resource?(alert("资源名称不能为空"),!1):void 0===e.count||e.count<0?(alert("限流阈值必须大于等于 0"),!1):void 0===e.strategy||e.strategy<0?(alert("无效的流控模式"),!1):1!=e.strategy&&2!=e.strategy||void 0!==e.refResource&&""!=e.refResource?void 0===e.controlBehavior||e.controlBehavior<0?(alert("无效的流控整形方式"),!1):1==e.controlBehavior&&t(e.warmUpPeriodSec)?(alert("预热时长必须大于 0"),!1):2==e.controlBehavior&&t(e.maxQueueingTimeMs)?(alert("排队超时时间必须大于 0"),!1):!e.clusterMode||void 0!==e.clusterConfig&&void 0!==e.clusterConfig.thresholdType||(alert("集群限流配置不正确"),!1):(alert("请填写关联资源或入口"),!1)}}]),(app=angular.module("sentinelDashboardApp")).service("FlowServiceV2",["$http",function(a){function t(e){return void 0===e||""===e||isNaN(e)||e<=0}this.queryMachineRules=function(e,t,r){return a({url:"/v2/flow/rules",params:{app:e,ip:t,port:r},method:"GET"})},this.newRule=function(e){return a({url:"/v2/flow/rule",data:e,method:"POST"})},this.saveRule=function(e){return a({url:"/v2/flow/rule/"+e.id,data:e,method:"PUT"})},this.deleteRule=function(e){return a({url:"/v2/flow/rule/"+e.id,method:"DELETE"})},this.checkRuleValid=function(e){return void 0===e.resource||""===e.resource?(alert("资源名称不能为空"),!1):void 0===e.count||e.count<0?(alert("限流阈值必须大于等于 0"),!1):void 0===e.strategy||e.strategy<0?(alert("无效的流控模式"),!1):1!=e.strategy&&2!=e.strategy||void 0!==e.refResource&&""!=e.refResource?void 0===e.controlBehavior||e.controlBehavior<0?(alert("无效的流控整形方式"),!1):1==e.controlBehavior&&t(e.warmUpPeriodSec)?(alert("预热时长必须大于 0"),!1):2==e.controlBehavior&&t(e.maxQueueingTimeMs)?(alert("排队超时时间必须大于 0"),!1):!e.clusterMode||void 0!==e.clusterConfig&&void 0!==e.clusterConfig.thresholdType||(alert("集群限流配置不正确"),!1):(alert("请填写关联资源或入口"),!1)}}]),(app=angular.module("sentinelDashboardApp")).service("DegradeService",["$http",function(a){this.queryMachineRules=function(e,t,r){return a({url:"degrade/rules.json",params:{app:e,ip:t,port:r},method:"GET"})},this.newRule=function(e){return a({url:"/degrade/rule",data:e,method:"POST"})},this.saveRule=function(e){var t={id:e.id,resource:e.resource,limitApp:e.limitApp,grade:e.grade,count:e.count,timeWindow:e.timeWindow,statIntervalMs:e.statIntervalMs,minRequestAmount:e.minRequestAmount,slowRatioThreshold:e.slowRatioThreshold};return a({url:"/degrade/rule/"+e.id,data:t,method:"PUT"})},this.deleteRule=function(e){return a({url:"/degrade/rule/"+e.id,method:"DELETE"})},this.checkRuleValid=function(e){if(void 0===e.resource||""===e.resource)return alert("资源名称不能为空"),!1;if(void 0===e.grade||e.grade<0)return alert("未知的降级策略"),!1;if(void 0===e.count||""===e.count||e.count<0)return alert("降级阈值不能为空或小于 0"),!1;if(null==e.timeWindow||""===e.timeWindow||e.timeWindow<=0)return alert("熔断时长必须大于 0s"),!1;if(null==e.minRequestAmount||e.minRequestAmount<=0)return alert("最小请求数目需大于 0"),!1;if(null==e.statIntervalMs||e.statIntervalMs<=0)return alert("统计窗口时长需大于 0s"),!1;if(void 0!==e.statIntervalMs&&12e4