Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -365,17 +365,44 @@ public class SentinelApiClient { | |||
params.put("type", type); | |||
params.put("data", data); | |||
String result = executeCommand(app, ip, port, SET_RULES_PATH, params, true).get(); | |||
logger.info("setRules: {}", result); | |||
logger.info("setRules result: {}, type={}", result, type); | |||
return true; | |||
} catch (InterruptedException | ExecutionException e) { | |||
logger.warn("setRules api failed: {}", type, e); | |||
} catch (InterruptedException e) { | |||
logger.warn("setRules API failed: {}", type, e); | |||
return false; | |||
} catch (ExecutionException e) { | |||
logger.warn("setRules API failed: {}", type, e.getCause()); | |||
return false; | |||
} catch (Exception e) { | |||
logger.warn("setRules failed", e); | |||
logger.error("setRules API failed, type={}", type, e); | |||
return false; | |||
} | |||
} | |||
private CompletableFuture<Void> setRulesAsync(String app, String ip, int port, String type, List<? extends RuleEntity> entities) { | |||
try { | |||
AssertUtil.notNull(entities, "rules cannot be null"); | |||
AssertUtil.notEmpty(app, "Bad app name"); | |||
AssertUtil.notEmpty(ip, "Bad machine IP"); | |||
AssertUtil.isTrue(port > 0, "Bad machine port"); | |||
String data = JSON.toJSONString( | |||
entities.stream().map(r -> r.toRule()).collect(Collectors.toList())); | |||
Map<String, String> params = new HashMap<>(2); | |||
params.put("type", type); | |||
params.put("data", data); | |||
return executeCommand(app, ip, port, SET_RULES_PATH, params, true) | |||
.thenCompose(r -> { | |||
if ("success".equalsIgnoreCase(r.trim())) { | |||
return CompletableFuture.completedFuture(null); | |||
} | |||
return AsyncUtils.newFailedFuture(new CommandFailedException(r)); | |||
}); | |||
} catch (Exception e) { | |||
logger.error("setRulesAsync API failed, type={}", type, e); | |||
return AsyncUtils.newFailedFuture(e); | |||
} | |||
} | |||
public List<NodeVo> fetchResourceOfMachine(String ip, int port, String type) { | |||
return fetchItems(ip, port, RESOURCE_URL_PATH, type, NodeVo.class); | |||
} | |||
@@ -487,6 +514,10 @@ public class SentinelApiClient { | |||
return setRules(app, ip, port, FLOW_RULE_TYPE, rules); | |||
} | |||
public CompletableFuture<Void> setFlowRuleOfMachineAsync(String app, String ip, int port, List<FlowRuleEntity> rules) { | |||
return setRulesAsync(app, ip, port, FLOW_RULE_TYPE, rules); | |||
} | |||
/** | |||
* set rules of the machine. rules == null will return immediately; | |||
* rules.isEmpty() means setting the rules to empty. | |||
@@ -15,6 +15,10 @@ | |||
*/ | |||
package com.alibaba.csp.sentinel.dashboard.config; | |||
import java.util.Arrays; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; | |||
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; | |||
import com.alibaba.csp.sentinel.dashboard.auth.AuthorizationInterceptor; | |||
@@ -75,6 +79,9 @@ public class WebConfig implements WebMvcConfigurer { | |||
registration.addUrlPatterns("/*"); | |||
registration.setName("sentinelFilter"); | |||
registration.setOrder(1); | |||
// If this is enabled, the entrance of all Web URL resources will be unified as a single context name. | |||
// In most scenarios that's enough, and it could reduce the memory footprint. | |||
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "true"); | |||
logger.info("Sentinel servlet CommonFilter registered"); | |||
@@ -83,12 +90,14 @@ public class WebConfig implements WebMvcConfigurer { | |||
@PostConstruct | |||
public void doInit() { | |||
Set<String> suffixSet = new HashSet<>(Arrays.asList(".js", ".css", ".html", ".ico", ".txt", | |||
".woff", ".woff2")); | |||
// Example: register a UrlCleaner to exclude URLs of common static resources. | |||
WebCallbackManager.setUrlCleaner(url -> { | |||
if (StringUtil.isEmpty(url)) { | |||
return url; | |||
} | |||
if (url.endsWith(".js") || url.endsWith(".css") || url.endsWith("html")) { | |||
if (suffixSet.stream().anyMatch(url::endsWith)) { | |||
return null; | |||
} | |||
return url; | |||
@@ -17,6 +17,9 @@ package com.alibaba.csp.sentinel.dashboard.controller; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.concurrent.CompletableFuture; | |||
import java.util.concurrent.ExecutionException; | |||
import java.util.concurrent.TimeUnit; | |||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction; | |||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType; | |||
@@ -145,19 +148,19 @@ public class FlowControllerV1 { | |||
entity.setResource(entity.getResource().trim()); | |||
try { | |||
entity = repository.save(entity); | |||
} catch (Throwable throwable) { | |||
logger.error("Failed to add flow rule", throwable); | |||
return Result.ofThrowable(-1, throwable); | |||
} | |||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { | |||
logger.error("Publish flow rules failed after rule add"); | |||
publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS); | |||
return Result.ofSuccess(entity); | |||
} catch (Throwable t) { | |||
Throwable e = t instanceof ExecutionException ? t.getCause() : t; | |||
logger.error("Failed to add new flow rule, app={}, ip={}", entity.getApp(), entity.getIp(), e); | |||
return Result.ofFail(-1, e.getMessage()); | |||
} | |||
return Result.ofSuccess(entity); | |||
} | |||
@PutMapping("/save.json") | |||
@AuthAction(PrivilegeType.WRITE_RULE) | |||
public Result<FlowRuleEntity> updateIfNotNull(Long id, String app, | |||
public Result<FlowRuleEntity> apiUpdateFlowRule(Long id, String app, | |||
String limitApp, String resource, Integer grade, | |||
Double count, Integer strategy, String refResource, | |||
Integer controlBehavior, Integer warmUpPeriodSec, | |||
@@ -222,21 +225,22 @@ public class FlowControllerV1 { | |||
try { | |||
entity = repository.save(entity); | |||
if (entity == null) { | |||
return Result.ofFail(-1, "save entity fail"); | |||
return Result.ofFail(-1, "save entity fail: null"); | |||
} | |||
} catch (Throwable throwable) { | |||
logger.error("save error:", throwable); | |||
return Result.ofThrowable(-1, throwable); | |||
} | |||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { | |||
logger.info("publish flow rules fail after rule update"); | |||
publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS); | |||
return Result.ofSuccess(entity); | |||
} catch (Throwable t) { | |||
Throwable e = t instanceof ExecutionException ? t.getCause() : t; | |||
logger.error("Error when updating flow rules, app={}, ip={}, ruleId={}", entity.getApp(), | |||
entity.getIp(), id, e); | |||
return Result.ofFail(-1, e.getMessage()); | |||
} | |||
return Result.ofSuccess(entity); | |||
} | |||
@DeleteMapping("/delete.json") | |||
@AuthAction(PrivilegeType.WRITE_RULE) | |||
public Result<Long> delete(Long id) { | |||
public Result<Long> apiDeleteFlowRule(Long id) { | |||
if (id == null) { | |||
return Result.ofFail(-1, "id can't be null"); | |||
@@ -251,14 +255,19 @@ public class FlowControllerV1 { | |||
} catch (Exception e) { | |||
return Result.ofFail(-1, e.getMessage()); | |||
} | |||
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { | |||
logger.info("publish flow rules fail after rule delete"); | |||
try { | |||
publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(5000, TimeUnit.MILLISECONDS); | |||
return Result.ofSuccess(id); | |||
} catch (Throwable t) { | |||
Throwable e = t instanceof ExecutionException ? t.getCause() : t; | |||
logger.error("Error when deleting flow rules, app={}, ip={}, id={}", oldEntity.getApp(), | |||
oldEntity.getIp(), id, e); | |||
return Result.ofFail(-1, e.getMessage()); | |||
} | |||
return Result.ofSuccess(id); | |||
} | |||
private boolean publishRules(String app, String ip, Integer port) { | |||
private CompletableFuture<Void> publishRules(String app, String ip, Integer port) { | |||
List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); | |||
return sentinelApiClient.setFlowRuleOfMachine(app, ip, port, rules); | |||
return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules); | |||
} | |||
} |
@@ -148,18 +148,18 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', ' | |||
getMachineRules(); | |||
confirmDialog.close(); | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}); | |||
}; | |||
function addNewRule(rule) { | |||
FlowService.newRule(rule).success(function (data) { | |||
if (data.code == 0) { | |||
if (data.code === 0) { | |||
getMachineRules(); | |||
flowRuleDialog.close(); | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}); | |||
}; | |||
@@ -173,7 +173,7 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', ' | |||
function saveRule(rule, edit) { | |||
FlowService.saveRule(rule).success(function (data) { | |||
if (data.code == 0) { | |||
if (data.code === 0) { | |||
getMachineRules(); | |||
if (edit) { | |||
flowRuleDialog.close(); | |||
@@ -181,7 +181,7 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', ' | |||
confirmDialog.close(); | |||
} | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}); | |||
} | |||
@@ -98,7 +98,7 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||
let url = '/dashboard/flow/' + $scope.app; | |||
$location.path(url); | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}).error((data, header, config, status) => { | |||
alert('未知错误'); | |||
@@ -110,10 +110,10 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||
return; | |||
} | |||
FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) { | |||
if (data.code == 0) { | |||
if (data.code === 0) { | |||
flowRuleDialog.close(); | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}); | |||
} | |||
@@ -159,12 +159,12 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||
return; | |||
} | |||
DegradeService.newRule(degradeRuleDialogScope.currentRule).success(function (data) { | |||
if (data.code == 0) { | |||
if (data.code === 0) { | |||
degradeRuleDialog.close(); | |||
var url = '/dashboard/degrade/' + $scope.app; | |||
$location.path(url); | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}); | |||
} | |||
@@ -174,10 +174,10 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||
return; | |||
} | |||
DegradeService.newRule(degradeRuleDialogScope.currentRule).success(function (data) { | |||
if (data.code == 0) { | |||
if (data.code === 0) { | |||
degradeRuleDialog.close(); | |||
} else { | |||
alert('失败!'); | |||
alert('失败:' + data.msg); | |||
} | |||
}); | |||
} | |||