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