init
This commit is contained in:
8
visual/sentinel-dashboard/README.md
Normal file
8
visual/sentinel-dashboard/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
feign 整合 sentinel
|
||||
```yaml
|
||||
feign:
|
||||
sentinel:
|
||||
# 为feign整合sentinel
|
||||
enable: true
|
||||
|
||||
```
|
||||
177
visual/sentinel-dashboard/pom.xml
Normal file
177
visual/sentinel-dashboard/pom.xml
Normal file
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>visual</artifactId>
|
||||
<groupId>cn.fateverse</groupId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>sentinel-dashboard</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.5.12</spring.boot.version>
|
||||
<curator.version>4.0.1</curator.version>
|
||||
<guava.version>30.1-jre</guava.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--注册中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-web-servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-parameter-flow-control</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<version>4.4.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpasyncclient</artifactId>
|
||||
<version>4.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore-nio</artifactId>
|
||||
<version>4.4.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>2.0.15</version>
|
||||
</dependency>
|
||||
|
||||
<!-- for Nacos rule publisher sample -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
<!-- <scope>test</scope>-->
|
||||
</dependency>
|
||||
<!-- for Apollo rule publisher sample -->
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-openapi</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--for Zookeeper rule publisher sample-->
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-recipes</artifactId>
|
||||
<version>${curator.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.stefanbirkner</groupId>
|
||||
<artifactId>system-rules</artifactId>
|
||||
<version>1.16.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/webapp/</directory>
|
||||
<excludes>
|
||||
<exclude>resources/node_modules/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.7.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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;
|
||||
|
||||
import com.alibaba.csp.sentinel.init.InitExecutor;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Sentinel dashboard application.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class DashboardApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
triggerSentinelInit();
|
||||
SpringApplication.run(DashboardApplication.class, args);
|
||||
}
|
||||
|
||||
private static void triggerSentinelInit() {
|
||||
new Thread(() -> InitExecutor.doInit()).start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author lkxiaolou
|
||||
* @since 1.7.1
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface AuthAction {
|
||||
|
||||
/**
|
||||
* @return the privilege type
|
||||
*/
|
||||
AuthService.PrivilegeType value();
|
||||
|
||||
/**
|
||||
* @return the target name to control
|
||||
*/
|
||||
String targetName() default "app";
|
||||
|
||||
/**
|
||||
* @return the message when permission is denied
|
||||
*/
|
||||
String message() default "Permission denied";
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
/**
|
||||
* Interface for authentication and authorization.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public interface AuthService<R> {
|
||||
|
||||
/**
|
||||
* Get the authentication user.
|
||||
*
|
||||
* @param request the request contains the user information
|
||||
* @return the auth user represent the current user, when the user is illegal, a null value will return.
|
||||
*/
|
||||
AuthUser getAuthUser(R request);
|
||||
|
||||
/**
|
||||
* Privilege type.
|
||||
*/
|
||||
enum PrivilegeType {
|
||||
/**
|
||||
* Read rule
|
||||
*/
|
||||
READ_RULE,
|
||||
/**
|
||||
* Create or modify rule
|
||||
*/
|
||||
WRITE_RULE,
|
||||
/**
|
||||
* Delete rule
|
||||
*/
|
||||
DELETE_RULE,
|
||||
/**
|
||||
* Read metrics
|
||||
*/
|
||||
READ_METRIC,
|
||||
/**
|
||||
* Add machine
|
||||
*/
|
||||
ADD_MACHINE,
|
||||
/**
|
||||
* All privileges above are granted.
|
||||
*/
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the current user.
|
||||
*/
|
||||
interface AuthUser {
|
||||
|
||||
/**
|
||||
* Query whether current user has the specific privilege to the target, the target
|
||||
* may be an app name or an ip address, or other destination.
|
||||
* <p>
|
||||
* This method will use return value to represent whether user has the specific
|
||||
* privileges to the target, but to throw a RuntimeException to represent no auth
|
||||
* is also a good way.
|
||||
* </p>
|
||||
*
|
||||
* @param target the target to check
|
||||
* @param privilegeType the privilege type to check
|
||||
* @return if current user has the specific privileges to the target, return true,
|
||||
* otherwise return false.
|
||||
*/
|
||||
boolean authTarget(String target, PrivilegeType privilegeType);
|
||||
|
||||
/**
|
||||
* Check whether current user is a super-user.
|
||||
*
|
||||
* @return if current user is super user return true, else return false.
|
||||
*/
|
||||
boolean isSuperUser();
|
||||
|
||||
/**
|
||||
* Get current user's nick name.
|
||||
*
|
||||
* @return current user's nick name.
|
||||
*/
|
||||
String getNickName();
|
||||
|
||||
/**
|
||||
* Get current user's login name.
|
||||
*
|
||||
* @return current user's login name.
|
||||
*/
|
||||
String getLoginName();
|
||||
|
||||
/**
|
||||
* Get current user's ID.
|
||||
*
|
||||
* @return ID of current user
|
||||
*/
|
||||
String getId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
/**
|
||||
* The web interceptor for privilege-based authorization.
|
||||
*
|
||||
* @author lkxiaolou
|
||||
* @author wxq
|
||||
* @since 1.7.1
|
||||
*/
|
||||
public interface AuthorizationInterceptor extends HandlerInterceptor {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* The web interceptor for privilege-based authorization.
|
||||
* <p>
|
||||
* move from old {@link AuthorizationInterceptor}.
|
||||
*
|
||||
* @author lkxiaolou
|
||||
* @author wxq
|
||||
* @since 1.7.1
|
||||
*/
|
||||
public class DefaultAuthorizationInterceptor implements AuthorizationInterceptor {
|
||||
|
||||
private final AuthService<HttpServletRequest> authService;
|
||||
|
||||
public DefaultAuthorizationInterceptor(AuthService<HttpServletRequest> authService) {
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
|
||||
Method method = ((HandlerMethod) handler).getMethod();
|
||||
|
||||
AuthAction authAction = method.getAnnotation(AuthAction.class);
|
||||
if (authAction != null) {
|
||||
AuthService.AuthUser authUser = authService.getAuthUser(request);
|
||||
if (authUser == null) {
|
||||
responseNoPrivilegeMsg(response, authAction.message());
|
||||
return false;
|
||||
}
|
||||
String target = request.getParameter(authAction.targetName());
|
||||
|
||||
if (!authUser.authTarget(target, authAction.value())) {
|
||||
responseNoPrivilegeMsg(response, authAction.message());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void responseNoPrivilegeMsg(HttpServletResponse response, String message) throws IOException {
|
||||
Result result = Result.ofFail(-1, message);
|
||||
response.addHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
response.getOutputStream().write(JSON.toJSONBytes(result));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>The Servlet filter for authentication.</p>
|
||||
*
|
||||
* <p>Note: some urls are excluded as they needn't auth, such as:</p>
|
||||
* <ul>
|
||||
* <li>index url: {@code /}</li>
|
||||
* <li>authentication request url: {@code /login}, {@code /logout}</li>
|
||||
* <li>machine registry: {@code /registry/machine}</li>
|
||||
* <li>static resources</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The excluded urls and urlSuffixes could be configured in {@code application.properties} file.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class DefaultLoginAuthenticationFilter implements LoginAuthenticationFilter {
|
||||
|
||||
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
|
||||
|
||||
private static final String URL_SUFFIX_DOT = ".";
|
||||
|
||||
/**
|
||||
* Some urls which needn't auth, such as /auth/login, /registry/machine and so on.
|
||||
*/
|
||||
@Value("#{'${auth.filter.exclude-urls}'.split(',')}")
|
||||
private List<String> authFilterExcludeUrls;
|
||||
|
||||
/**
|
||||
* Some urls with suffixes which needn't auth, such as htm, html, js and so on.
|
||||
*/
|
||||
@Value("#{'${auth.filter.exclude-url-suffixes}'.split(',')}")
|
||||
private List<String> authFilterExcludeUrlSuffixes;
|
||||
|
||||
/**
|
||||
* Authentication using AuthService interface.
|
||||
*/
|
||||
private final AuthService<HttpServletRequest> authService;
|
||||
|
||||
public DefaultLoginAuthenticationFilter(AuthService<HttpServletRequest> authService) {
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
|
||||
String servletPath = httpRequest.getServletPath();
|
||||
|
||||
// Exclude the urls which needn't auth
|
||||
boolean authFilterExcludeMatch = authFilterExcludeUrls.stream()
|
||||
.anyMatch(authFilterExcludeUrl -> PATH_MATCHER.match(authFilterExcludeUrl, servletPath));
|
||||
if (authFilterExcludeMatch) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// Exclude the urls with suffixes which needn't auth
|
||||
for (String authFilterExcludeUrlSuffix : authFilterExcludeUrlSuffixes) {
|
||||
if (StringUtils.isBlank(authFilterExcludeUrlSuffix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add . for url suffix so that we needn't add . in property file
|
||||
if (!authFilterExcludeUrlSuffix.startsWith(URL_SUFFIX_DOT)) {
|
||||
authFilterExcludeUrlSuffix = URL_SUFFIX_DOT + authFilterExcludeUrlSuffix;
|
||||
}
|
||||
|
||||
if (servletPath.endsWith(authFilterExcludeUrlSuffix)) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AuthService.AuthUser authUser = authService.getAuthUser(httpRequest);
|
||||
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
if (authUser == null) {
|
||||
// If auth fail, set response status code to 401
|
||||
httpResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* A fake AuthService implementation, which will pass all user auth checking.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class FakeAuthServiceImpl implements AuthService<HttpServletRequest> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public FakeAuthServiceImpl() {
|
||||
this.logger.warn("there is no auth, use {} by implementation {}", AuthService.class, this.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthUser getAuthUser(HttpServletRequest request) {
|
||||
return new AuthUserImpl();
|
||||
}
|
||||
|
||||
static final class AuthUserImpl implements AuthUser {
|
||||
|
||||
@Override
|
||||
public boolean authTarget(String target, PrivilegeType privilegeType) {
|
||||
// fake implementation, always return true
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuperUser() {
|
||||
// fake implementation, always return true
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName() {
|
||||
return "FAKE_NICK_NAME";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoginName() {
|
||||
return "FAKE_LOGIN_NAME";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "FAKE_EMP_ID";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.auth;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
/**
|
||||
* <p>The Servlet filter for authentication.</p>
|
||||
*
|
||||
* <p>Note: some urls are excluded as they needn't auth, such as:</p>
|
||||
* <ul>
|
||||
* <li>index url: {@code /}</li>
|
||||
* <li>authentication request url: {@code /login}, {@code /logout}</li>
|
||||
* <li>machine registry: {@code /registry/machine}</li>
|
||||
* <li>static resources</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The excluded urls and urlSuffixes could be configured in {@code application.properties} file.
|
||||
*
|
||||
* @author cdfive
|
||||
* @author wxq
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public interface LoginAuthenticationFilter extends Filter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.auth;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author cdfive
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public class SimpleWebAuthServiceImpl implements AuthService<HttpServletRequest> {
|
||||
|
||||
public static final String WEB_SESSION_KEY = "session_sentinel_admin";
|
||||
|
||||
@Override
|
||||
public AuthUser getAuthUser(HttpServletRequest request) {
|
||||
HttpSession session = request.getSession();
|
||||
Object sentinelUserObj = session.getAttribute(SimpleWebAuthServiceImpl.WEB_SESSION_KEY);
|
||||
if (sentinelUserObj != null && sentinelUserObj instanceof AuthUser) {
|
||||
return (AuthUser) sentinelUserObj;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final class SimpleWebAuthUserImpl implements AuthUser {
|
||||
|
||||
private String username;
|
||||
|
||||
public SimpleWebAuthUserImpl(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authTarget(String target, PrivilegeType privilegeType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuperUser() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickName() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoginName() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return username;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.client;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class CommandFailedException extends RuntimeException {
|
||||
|
||||
public CommandFailedException() {}
|
||||
|
||||
public CommandFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.client;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public class CommandNotFoundException extends Exception {
|
||||
|
||||
public CommandNotFoundException() { }
|
||||
|
||||
public CommandNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
* 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.client;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||
import com.alibaba.csp.sentinel.command.CommandConstants;
|
||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||
import com.alibaba.csp.sentinel.command.vo.NodeVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.util.AsyncUtils;
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
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.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
|
||||
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.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterClientInfoVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.ClusterServerStateVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.ClusterStateSimpleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ClusterClientConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerFlowConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerTransportConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.util.VersionUtils;
|
||||
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.concurrent.FutureCallback;
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.impl.client.DefaultRedirectStrategy;
|
||||
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClients;
|
||||
import org.apache.http.impl.nio.reactor.IOReactorConfig;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Communicate with Sentinel client.
|
||||
*
|
||||
* @author leyou
|
||||
*/
|
||||
@Component
|
||||
public class SentinelApiClient {
|
||||
private static Logger logger = LoggerFactory.getLogger(SentinelApiClient.class);
|
||||
|
||||
private static final Charset DEFAULT_CHARSET = Charset.forName(SentinelConfig.charset());
|
||||
private static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
|
||||
private static final String HTTP_HEADER_CONTENT_TYPE_URLENCODED = ContentType.create(URLEncodedUtils.CONTENT_TYPE).toString();
|
||||
|
||||
private static final String RESOURCE_URL_PATH = "jsonTree";
|
||||
private static final String CLUSTER_NODE_PATH = "clusterNode";
|
||||
private static final String GET_RULES_PATH = "getRules";
|
||||
private static final String SET_RULES_PATH = "setRules";
|
||||
private static final String GET_PARAM_RULE_PATH = "getParamFlowRules";
|
||||
private static final String SET_PARAM_RULE_PATH = "setParamFlowRules";
|
||||
|
||||
private static final String FETCH_CLUSTER_MODE_PATH = "getClusterMode";
|
||||
private static final String MODIFY_CLUSTER_MODE_PATH = "setClusterMode";
|
||||
private static final String FETCH_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/fetchConfig";
|
||||
private static final String MODIFY_CLUSTER_CLIENT_CONFIG_PATH = "cluster/client/modifyConfig";
|
||||
|
||||
private static final String FETCH_CLUSTER_SERVER_BASIC_INFO_PATH = "cluster/server/info";
|
||||
|
||||
private static final String MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH = "cluster/server/modifyTransportConfig";
|
||||
private static final String MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH = "cluster/server/modifyFlowConfig";
|
||||
private static final String MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH = "cluster/server/modifyNamespaceSet";
|
||||
|
||||
private static final String FETCH_GATEWAY_API_PATH = "gateway/getApiDefinitions";
|
||||
private static final String MODIFY_GATEWAY_API_PATH = "gateway/updateApiDefinitions";
|
||||
|
||||
private static final String FETCH_GATEWAY_FLOW_RULE_PATH = "gateway/getRules";
|
||||
private static final String MODIFY_GATEWAY_FLOW_RULE_PATH = "gateway/updateRules";
|
||||
|
||||
private static final String FLOW_RULE_TYPE = "flow";
|
||||
private static final String DEGRADE_RULE_TYPE = "degrade";
|
||||
private static final String SYSTEM_RULE_TYPE = "system";
|
||||
private static final String AUTHORITY_TYPE = "authority";
|
||||
|
||||
private CloseableHttpAsyncClient httpClient;
|
||||
|
||||
private static final SentinelVersion version160 = new SentinelVersion(1, 6, 0);
|
||||
private static final SentinelVersion version171 = new SentinelVersion(1, 7, 1);
|
||||
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
public SentinelApiClient() {
|
||||
IOReactorConfig ioConfig = IOReactorConfig.custom().setConnectTimeout(3000).setSoTimeout(10000)
|
||||
.setIoThreadCount(Runtime.getRuntime().availableProcessors() * 2).build();
|
||||
httpClient = HttpAsyncClients.custom().setRedirectStrategy(new DefaultRedirectStrategy() {
|
||||
@Override
|
||||
protected boolean isRedirectable(final String method) {
|
||||
return false;
|
||||
}
|
||||
}).setMaxConnTotal(4000).setMaxConnPerRoute(1000).setDefaultIOReactorConfig(ioConfig).build();
|
||||
httpClient.start();
|
||||
}
|
||||
|
||||
private boolean isSuccess(int statusCode) {
|
||||
return statusCode >= 200 && statusCode < 300;
|
||||
}
|
||||
|
||||
private boolean isCommandNotFound(int statusCode, String body) {
|
||||
return statusCode == 400 && StringUtil.isNotEmpty(body) && body.contains(CommandConstants.MSG_UNKNOWN_COMMAND_PREFIX);
|
||||
}
|
||||
|
||||
protected boolean isSupportPost(String app, String ip, int port) {
|
||||
return StringUtil.isNotEmpty(app) && Optional.ofNullable(appManagement.getDetailApp(app))
|
||||
.flatMap(e -> e.getMachine(ip, port))
|
||||
.flatMap(m -> VersionUtils.parseVersion(m.getVersion())
|
||||
.map(v -> v.greaterOrEqual(version160)))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether target instance (identified by tuple of app-ip:port)
|
||||
* supports the form of "xxxxx; xx=xx" in "Content-Type" header.
|
||||
*
|
||||
* @param app target app name
|
||||
* @param ip target node's address
|
||||
* @param port target node's port
|
||||
*/
|
||||
protected boolean isSupportEnhancedContentType(String app, String ip, int port) {
|
||||
return StringUtil.isNotEmpty(app) && Optional.ofNullable(appManagement.getDetailApp(app))
|
||||
.flatMap(e -> e.getMachine(ip, port))
|
||||
.flatMap(m -> VersionUtils.parseVersion(m.getVersion())
|
||||
.map(v -> v.greaterOrEqual(version171)))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
private StringBuilder queryString(Map<String, String> params) {
|
||||
StringBuilder queryStringBuilder = new StringBuilder();
|
||||
for (Entry<String, String> entry : params.entrySet()) {
|
||||
if (StringUtil.isEmpty(entry.getValue())) {
|
||||
continue;
|
||||
}
|
||||
String name = urlEncode(entry.getKey());
|
||||
String value = urlEncode(entry.getValue());
|
||||
if (name != null && value != null) {
|
||||
if (queryStringBuilder.length() > 0) {
|
||||
queryStringBuilder.append('&');
|
||||
}
|
||||
queryStringBuilder.append(name).append('=').append(value);
|
||||
}
|
||||
}
|
||||
return queryStringBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an `HttpUriRequest` in POST way.
|
||||
*
|
||||
* @param url
|
||||
* @param params
|
||||
* @param supportEnhancedContentType see {@link #isSupportEnhancedContentType(String, String, int)}
|
||||
* @return
|
||||
*/
|
||||
protected static HttpUriRequest postRequest(String url, Map<String, String> params, boolean supportEnhancedContentType) {
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (params != null && params.size() > 0) {
|
||||
List<NameValuePair> list = new ArrayList<>(params.size());
|
||||
for (Entry<String, String> entry : params.entrySet()) {
|
||||
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
httpPost.setEntity(new UrlEncodedFormEntity(list, Consts.UTF_8));
|
||||
if (!supportEnhancedContentType) {
|
||||
httpPost.setHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_HEADER_CONTENT_TYPE_URLENCODED);
|
||||
}
|
||||
}
|
||||
return httpPost;
|
||||
}
|
||||
|
||||
private String urlEncode(String str) {
|
||||
try {
|
||||
return URLEncoder.encode(str, DEFAULT_CHARSET.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.info("encode string error: {}", str, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getBody(HttpResponse response) throws Exception {
|
||||
Charset charset = null;
|
||||
try {
|
||||
String contentTypeStr = response.getFirstHeader(HTTP_HEADER_CONTENT_TYPE).getValue();
|
||||
if (StringUtil.isNotEmpty(contentTypeStr)) {
|
||||
ContentType contentType = ContentType.parse(contentTypeStr);
|
||||
charset = contentType.getCharset();
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return EntityUtils.toString(response.getEntity(), charset != null ? charset : DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* With no param
|
||||
*
|
||||
* @param ip
|
||||
* @param port
|
||||
* @param api
|
||||
* @return
|
||||
*/
|
||||
private CompletableFuture<String> executeCommand(String ip, int port, String api, boolean useHttpPost) {
|
||||
return executeCommand(ip, port, api, null, useHttpPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* No app specified, force to GET
|
||||
*
|
||||
* @param ip
|
||||
* @param port
|
||||
* @param api
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
private CompletableFuture<String> executeCommand(String ip, int port, String api, Map<String, String> params, boolean useHttpPost) {
|
||||
return executeCommand(null, ip, port, api, params, useHttpPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer to execute request using POST
|
||||
*
|
||||
* @param app
|
||||
* @param ip
|
||||
* @param port
|
||||
* @param api
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
private CompletableFuture<String> executeCommand(String app, String ip, int port, String api, Map<String, String> params, boolean useHttpPost) {
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
if (StringUtil.isBlank(ip) || StringUtil.isBlank(api)) {
|
||||
future.completeExceptionally(new IllegalArgumentException("Bad URL or command name"));
|
||||
return future;
|
||||
}
|
||||
if (!InetAddressUtils.isIPv4Address(ip) && !InetAddressUtils.isIPv6Address(ip)) {
|
||||
future.completeExceptionally(new IllegalArgumentException("Bad IP"));
|
||||
return future;
|
||||
}
|
||||
if (!StringUtil.isEmpty(app) && !appManagement.isValidMachineOfApp(app, ip)) {
|
||||
future.completeExceptionally(new IllegalArgumentException("Given ip does not belong to given app"));
|
||||
return future;
|
||||
}
|
||||
StringBuilder urlBuilder = new StringBuilder();
|
||||
urlBuilder.append("http://");
|
||||
urlBuilder.append(ip).append(':').append(port).append('/').append(api);
|
||||
if (params == null) {
|
||||
params = Collections.emptyMap();
|
||||
}
|
||||
if (!useHttpPost || !isSupportPost(app, ip, port)) {
|
||||
// Using GET in older versions, append parameters after url
|
||||
if (!params.isEmpty()) {
|
||||
if (urlBuilder.indexOf("?") == -1) {
|
||||
urlBuilder.append('?');
|
||||
} else {
|
||||
urlBuilder.append('&');
|
||||
}
|
||||
urlBuilder.append(queryString(params));
|
||||
}
|
||||
return executeCommand(new HttpGet(urlBuilder.toString()));
|
||||
} else {
|
||||
// Using POST
|
||||
return executeCommand(
|
||||
postRequest(urlBuilder.toString(), params, isSupportEnhancedContentType(app, ip, port)));
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<String> executeCommand(HttpUriRequest request) {
|
||||
CompletableFuture<String> future = new CompletableFuture<>();
|
||||
httpClient.execute(request, new FutureCallback<HttpResponse>() {
|
||||
@Override
|
||||
public void completed(final HttpResponse response) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
try {
|
||||
String value = getBody(response);
|
||||
if (isSuccess(statusCode)) {
|
||||
future.complete(value);
|
||||
} else {
|
||||
if (isCommandNotFound(statusCode, value)) {
|
||||
future.completeExceptionally(new CommandNotFoundException(request.getURI().getPath()));
|
||||
} else {
|
||||
future.completeExceptionally(new CommandFailedException(value));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
future.completeExceptionally(ex);
|
||||
logger.error("HTTP request failed: {}", request.getURI().toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Exception ex) {
|
||||
future.completeExceptionally(ex);
|
||||
logger.error("HTTP request failed: {}", request.getURI().toString(), ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
future.complete(null);
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
public void close() throws Exception {
|
||||
httpClient.close();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> CompletableFuture<List<T>> fetchItemsAsync(String ip, int port, String api, String type, Class<T> ruleType) {
|
||||
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||
Map<String, String> params = null;
|
||||
if (StringUtil.isNotEmpty(type)) {
|
||||
params = new HashMap<>(1);
|
||||
params.put("type", type);
|
||||
}
|
||||
return executeCommand(ip, port, api, params, false)
|
||||
.thenApply(json -> JSON.parseArray(json, ruleType));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> List<T> fetchItems(String ip, int port, String api, String type, Class<T> ruleType) {
|
||||
try {
|
||||
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||
Map<String, String> params = null;
|
||||
if (StringUtil.isNotEmpty(type)) {
|
||||
params = new HashMap<>(1);
|
||||
params.put("type", type);
|
||||
}
|
||||
return fetchItemsAsync(ip, port, api, type, ruleType).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
logger.error("Error when fetching items from api: {} -> {}", api, type, e);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
logger.error("Error when fetching items: {} -> {}", api, type, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Rule> List<T> fetchRules(String ip, int port, String type, Class<T> ruleType) {
|
||||
return fetchItems(ip, port, GET_RULES_PATH, type, ruleType);
|
||||
}
|
||||
|
||||
private boolean setRules(String app, String ip, int port, String type, List<? extends RuleEntity> entities) {
|
||||
if (entities == null) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
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);
|
||||
String result = executeCommand(app, ip, port, SET_RULES_PATH, params, true).get();
|
||||
logger.info("setRules result: {}, type={}", result, type);
|
||||
return true;
|
||||
} 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.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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch cluster node.
|
||||
*
|
||||
* @param ip ip to fetch
|
||||
* @param port port of the ip
|
||||
* @param includeZero whether zero value should in the result list.
|
||||
* @return
|
||||
*/
|
||||
public List<NodeVo> fetchClusterNodeOfMachine(String ip, int port, boolean includeZero) {
|
||||
String type = "notZero";
|
||||
if (includeZero) {
|
||||
type = "zero";
|
||||
}
|
||||
return fetchItems(ip, port, CLUSTER_NODE_PATH, type, NodeVo.class);
|
||||
}
|
||||
|
||||
public List<FlowRuleEntity> fetchFlowRuleOfMachine(String app, String ip, int port) {
|
||||
List<FlowRule> rules = fetchRules(ip, port, FLOW_RULE_TYPE, FlowRule.class);
|
||||
if (rules != null) {
|
||||
return rules.stream().map(rule -> FlowRuleEntity.fromFlowRule(app, ip, port, rule))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DegradeRuleEntity> fetchDegradeRuleOfMachine(String app, String ip, int port) {
|
||||
List<DegradeRule> rules = fetchRules(ip, port, DEGRADE_RULE_TYPE, DegradeRule.class);
|
||||
if (rules != null) {
|
||||
return rules.stream().map(rule -> DegradeRuleEntity.fromDegradeRule(app, ip, port, rule))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<SystemRuleEntity> fetchSystemRuleOfMachine(String app, String ip, int port) {
|
||||
List<SystemRule> rules = fetchRules(ip, port, SYSTEM_RULE_TYPE, SystemRule.class);
|
||||
if (rules != null) {
|
||||
return rules.stream().map(rule -> SystemRuleEntity.fromSystemRule(app, ip, port, rule))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all parameter flow rules from provided machine.
|
||||
*
|
||||
* @param app application name
|
||||
* @param ip machine client IP
|
||||
* @param port machine client port
|
||||
* @return all retrieved parameter flow rules
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public CompletableFuture<List<ParamFlowRuleEntity>> fetchParamFlowRulesOfMachine(String app, String ip, int port) {
|
||||
try {
|
||||
AssertUtil.notEmpty(app, "Bad app name");
|
||||
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||
return fetchItemsAsync(ip, port, GET_PARAM_RULE_PATH, null, ParamFlowRule.class)
|
||||
.thenApply(rules -> rules.stream()
|
||||
.map(e -> ParamFlowRuleEntity.fromParamFlowRule(app, ip, port, e))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error when fetching parameter flow rules", e);
|
||||
return AsyncUtils.newFailedFuture(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all authority rules from provided machine.
|
||||
*
|
||||
* @param app application name
|
||||
* @param ip machine client IP
|
||||
* @param port machine client port
|
||||
* @return all retrieved authority rules
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public List<AuthorityRuleEntity> fetchAuthorityRulesOfMachine(String app, String ip, int port) {
|
||||
AssertUtil.notEmpty(app, "Bad app name");
|
||||
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
params.put("type", AUTHORITY_TYPE);
|
||||
List<AuthorityRule> rules = fetchRules(ip, port, AUTHORITY_TYPE, AuthorityRule.class);
|
||||
return Optional.ofNullable(rules).map(r -> r.stream()
|
||||
.map(e -> AuthorityRuleEntity.fromAuthorityRule(app, ip, port, e))
|
||||
.collect(Collectors.toList())
|
||||
).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* set rules of the machine. rules == null will return immediately;
|
||||
* rules.isEmpty() means setting the rules to empty.
|
||||
*
|
||||
* @param app
|
||||
* @param ip
|
||||
* @param port
|
||||
* @param rules
|
||||
* @return whether successfully set the rules.
|
||||
*/
|
||||
public boolean setFlowRuleOfMachine(String app, String ip, int port, List<FlowRuleEntity> rules) {
|
||||
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.
|
||||
*
|
||||
* @param app
|
||||
* @param ip
|
||||
* @param port
|
||||
* @param rules
|
||||
* @return whether successfully set the rules.
|
||||
*/
|
||||
public boolean setDegradeRuleOfMachine(String app, String ip, int port, List<DegradeRuleEntity> rules) {
|
||||
return setRules(app, ip, port, DEGRADE_RULE_TYPE, rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* set rules of the machine. rules == null will return immediately;
|
||||
* rules.isEmpty() means setting the rules to empty.
|
||||
*
|
||||
* @param app
|
||||
* @param ip
|
||||
* @param port
|
||||
* @param rules
|
||||
* @return whether successfully set the rules.
|
||||
*/
|
||||
public boolean setSystemRuleOfMachine(String app, String ip, int port, List<SystemRuleEntity> rules) {
|
||||
return setRules(app, ip, port, SYSTEM_RULE_TYPE, rules);
|
||||
}
|
||||
|
||||
public boolean setAuthorityRuleOfMachine(String app, String ip, int port, List<AuthorityRuleEntity> rules) {
|
||||
return setRules(app, ip, port, AUTHORITY_TYPE, rules);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> setParamFlowRuleOfMachine(String app, String ip, int port, List<ParamFlowRuleEntity> rules) {
|
||||
if (rules == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
String data = JSON.toJSONString(
|
||||
rules.stream().map(ParamFlowRuleEntity::getRule).collect(Collectors.toList())
|
||||
);
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
params.put("data", data);
|
||||
return executeCommand(app, ip, port, SET_PARAM_RULE_PATH, params, true)
|
||||
.thenCompose(e -> {
|
||||
if (CommandConstants.MSG_SUCCESS.equals(e)) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
logger.warn("Push parameter flow rules to client failed: " + e);
|
||||
return AsyncUtils.newFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when setting parameter flow rule", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Cluster related
|
||||
|
||||
public CompletableFuture<ClusterStateSimpleEntity> fetchClusterMode(String ip, int port) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
return executeCommand(ip, port, FETCH_CLUSTER_MODE_PATH, false)
|
||||
.thenApply(r -> JSON.parseObject(r, ClusterStateSimpleEntity.class));
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when fetching cluster mode", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> modifyClusterMode(String ip, int port, int mode) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
params.put("mode", String.valueOf(mode));
|
||||
return executeCommand(ip, port, MODIFY_CLUSTER_MODE_PATH, params, false)
|
||||
.thenCompose(e -> {
|
||||
if (CommandConstants.MSG_SUCCESS.equals(e)) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
logger.warn("Error when modifying cluster mode: " + e);
|
||||
return AsyncUtils.newFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when modifying cluster mode", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<ClusterClientInfoVO> fetchClusterClientInfoAndConfig(String ip, int port) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
return executeCommand(ip, port, FETCH_CLUSTER_CLIENT_CONFIG_PATH, false)
|
||||
.thenApply(r -> JSON.parseObject(r, ClusterClientInfoVO.class));
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when fetching cluster client config", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> modifyClusterClientConfig(String app, String ip, int port, ClusterClientConfig config) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
params.put("data", JSON.toJSONString(config));
|
||||
return executeCommand(app, ip, port, MODIFY_CLUSTER_CLIENT_CONFIG_PATH, params, true)
|
||||
.thenCompose(e -> {
|
||||
if (CommandConstants.MSG_SUCCESS.equals(e)) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
logger.warn("Error when modifying cluster client config: " + e);
|
||||
return AsyncUtils.newFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when modifying cluster client config", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> modifyClusterServerFlowConfig(String app, String ip, int port, ServerFlowConfig config) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
params.put("data", JSON.toJSONString(config));
|
||||
return executeCommand(app, ip, port, MODIFY_CLUSTER_SERVER_FLOW_CONFIG_PATH, params, true)
|
||||
.thenCompose(e -> {
|
||||
if (CommandConstants.MSG_SUCCESS.equals(e)) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
logger.warn("Error when modifying cluster server flow config: " + e);
|
||||
return AsyncUtils.newFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when modifying cluster server flow config", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> modifyClusterServerTransportConfig(String app, String ip, int port, ServerTransportConfig config) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(2);
|
||||
params.put("port", config.getPort().toString());
|
||||
params.put("idleSeconds", config.getIdleSeconds().toString());
|
||||
return executeCommand(app, ip, port, MODIFY_CLUSTER_SERVER_TRANSPORT_CONFIG_PATH, params, false)
|
||||
.thenCompose(e -> {
|
||||
if (CommandConstants.MSG_SUCCESS.equals(e)) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
logger.warn("Error when modifying cluster server transport config: " + e);
|
||||
return AsyncUtils.newFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when modifying cluster server transport config", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> modifyClusterServerNamespaceSet(String app, String ip, int port, Set<String> set) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
params.put("data", JSON.toJSONString(set));
|
||||
return executeCommand(app, ip, port, MODIFY_CLUSTER_SERVER_NAMESPACE_SET_PATH, params, true)
|
||||
.thenCompose(e -> {
|
||||
if (CommandConstants.MSG_SUCCESS.equals(e)) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
logger.warn("Error when modifying cluster server NamespaceSet", e);
|
||||
return AsyncUtils.newFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when modifying cluster server NamespaceSet", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<ClusterServerStateVO> fetchClusterServerBasicInfo(String ip, int port) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
try {
|
||||
return executeCommand(ip, port, FETCH_CLUSTER_SERVER_BASIC_INFO_PATH, false)
|
||||
.thenApply(r -> JSON.parseObject(r, ClusterServerStateVO.class));
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when fetching cluster sever all config and basic info", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<List<ApiDefinitionEntity>> fetchApis(String app, String ip, int port) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
|
||||
try {
|
||||
return executeCommand(ip, port, FETCH_GATEWAY_API_PATH, false)
|
||||
.thenApply(r -> {
|
||||
List<ApiDefinitionEntity> entities = JSON.parseArray(r, ApiDefinitionEntity.class);
|
||||
if (entities != null) {
|
||||
for (ApiDefinitionEntity entity : entities) {
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
}
|
||||
}
|
||||
return entities;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when fetching gateway apis", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean modifyApis(String app, String ip, int port, List<ApiDefinitionEntity> apis) {
|
||||
if (apis == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
AssertUtil.notEmpty(app, "Bad app name");
|
||||
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||
String data = JSON.toJSONString(
|
||||
apis.stream().map(r -> r.toApiDefinition()).collect(Collectors.toList()));
|
||||
Map<String, String> params = new HashMap<>(2);
|
||||
params.put("data", data);
|
||||
String result = executeCommand(app, ip, port, MODIFY_GATEWAY_API_PATH, params, true).get();
|
||||
logger.info("Modify gateway apis: {}", result);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error when modifying gateway apis", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<List<GatewayFlowRuleEntity>> fetchGatewayFlowRules(String app, String ip, int port) {
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));
|
||||
}
|
||||
|
||||
try {
|
||||
return executeCommand(ip, port, FETCH_GATEWAY_FLOW_RULE_PATH, false)
|
||||
.thenApply(r -> {
|
||||
List<GatewayFlowRule> gatewayFlowRules = JSON.parseArray(r, GatewayFlowRule.class);
|
||||
List<GatewayFlowRuleEntity> entities = gatewayFlowRules.stream().map(rule -> GatewayFlowRuleEntity.fromGatewayFlowRule(app, ip, port, rule)).collect(Collectors.toList());
|
||||
return entities;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Error when fetching gateway flow rules", ex);
|
||||
return AsyncUtils.newFailedFuture(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean modifyGatewayFlowRules(String app, String ip, int port, List<GatewayFlowRuleEntity> rules) {
|
||||
if (rules == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
AssertUtil.notEmpty(app, "Bad app name");
|
||||
AssertUtil.notEmpty(ip, "Bad machine IP");
|
||||
AssertUtil.isTrue(port > 0, "Bad machine port");
|
||||
String data = JSON.toJSONString(
|
||||
rules.stream().map(r -> r.toGatewayFlowRule()).collect(Collectors.toList()));
|
||||
Map<String, String> params = new HashMap<>(2);
|
||||
params.put("data", data);
|
||||
String result = executeCommand(app, ip, port, MODIFY_GATEWAY_FLOW_RULE_PATH, params, true).get();
|
||||
logger.info("Modify gateway flow rules: {}", result);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error when modifying gateway apis", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.*;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(AuthProperties.class)
|
||||
public class AuthConfiguration {
|
||||
|
||||
private final AuthProperties authProperties;
|
||||
|
||||
public AuthConfiguration(AuthProperties authProperties) {
|
||||
this.authProperties = authProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AuthService<HttpServletRequest> httpServletRequestAuthService() {
|
||||
if (this.authProperties.isEnabled()) {
|
||||
return new SimpleWebAuthServiceImpl();
|
||||
}
|
||||
return new FakeAuthServiceImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LoginAuthenticationFilter loginAuthenticationFilter(AuthService<HttpServletRequest> httpServletRequestAuthService) {
|
||||
return new DefaultLoginAuthenticationFilter(httpServletRequestAuthService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AuthorizationInterceptor authorizationInterceptor(AuthService<HttpServletRequest> httpServletRequestAuthService) {
|
||||
return new DefaultAuthorizationInterceptor(httpServletRequestAuthService);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "auth")
|
||||
public class AuthProperties {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* <p>Dashboard local config support.</p>
|
||||
* <p>
|
||||
* Dashboard supports configuration loading by several ways by order:<br>
|
||||
* 1. System.properties<br>
|
||||
* 2. Env
|
||||
* </p>
|
||||
*
|
||||
* @author jason
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class DashboardConfig {
|
||||
|
||||
public static final int DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS = 60_000;
|
||||
|
||||
/**
|
||||
* Login username
|
||||
*/
|
||||
public static final String CONFIG_AUTH_USERNAME = "sentinel.dashboard.auth.username";
|
||||
|
||||
/**
|
||||
* Login password
|
||||
*/
|
||||
public static final String CONFIG_AUTH_PASSWORD = "sentinel.dashboard.auth.password";
|
||||
|
||||
/**
|
||||
* Hide application name in sidebar when it has no healthy machines after specific period in millisecond.
|
||||
*/
|
||||
public static final String CONFIG_HIDE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.app.hideAppNoMachineMillis";
|
||||
/**
|
||||
* Remove application when it has no healthy machines after specific period in millisecond.
|
||||
*/
|
||||
public static final String CONFIG_REMOVE_APP_NO_MACHINE_MILLIS = "sentinel.dashboard.removeAppNoMachineMillis";
|
||||
/**
|
||||
* Timeout
|
||||
*/
|
||||
public static final String CONFIG_UNHEALTHY_MACHINE_MILLIS = "sentinel.dashboard.unhealthyMachineMillis";
|
||||
/**
|
||||
* Auto remove unhealthy machine after specific period in millisecond.
|
||||
*/
|
||||
public static final String CONFIG_AUTO_REMOVE_MACHINE_MILLIS = "sentinel.dashboard.autoRemoveMachineMillis";
|
||||
|
||||
private static final ConcurrentMap<String, Object> cacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
@NonNull
|
||||
private static String getConfig(String name) {
|
||||
// env
|
||||
String val = System.getenv(name);
|
||||
if (StringUtils.isNotEmpty(val)) {
|
||||
return val;
|
||||
}
|
||||
// properties
|
||||
val = System.getProperty(name);
|
||||
if (StringUtils.isNotEmpty(val)) {
|
||||
return val;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected static String getConfigStr(String name) {
|
||||
if (cacheMap.containsKey(name)) {
|
||||
return (String) cacheMap.get(name);
|
||||
}
|
||||
|
||||
String val = getConfig(name);
|
||||
|
||||
if (StringUtils.isBlank(val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
cacheMap.put(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
protected static int getConfigInt(String name, int defaultVal, int minVal) {
|
||||
if (cacheMap.containsKey(name)) {
|
||||
return (int)cacheMap.get(name);
|
||||
}
|
||||
int val = NumberUtils.toInt(getConfig(name));
|
||||
if (val == 0) {
|
||||
val = defaultVal;
|
||||
} else if (val < minVal) {
|
||||
val = minVal;
|
||||
}
|
||||
cacheMap.put(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
public static String getAuthUsername() {
|
||||
return getConfigStr(CONFIG_AUTH_USERNAME);
|
||||
}
|
||||
|
||||
public static String getAuthPassword() {
|
||||
return getConfigStr(CONFIG_AUTH_PASSWORD);
|
||||
}
|
||||
|
||||
public static int getHideAppNoMachineMillis() {
|
||||
return getConfigInt(CONFIG_HIDE_APP_NO_MACHINE_MILLIS, 0, 60000);
|
||||
}
|
||||
|
||||
public static int getRemoveAppNoMachineMillis() {
|
||||
return getConfigInt(CONFIG_REMOVE_APP_NO_MACHINE_MILLIS, 0, 120000);
|
||||
}
|
||||
|
||||
public static int getAutoRemoveMachineMillis() {
|
||||
return getConfigInt(CONFIG_AUTO_REMOVE_MACHINE_MILLIS, 0, 300000);
|
||||
}
|
||||
|
||||
public static int getUnhealthyMachineMillis() {
|
||||
return getConfigInt(CONFIG_UNHEALTHY_MACHINE_MILLIS, DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS, 30000);
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
cacheMap.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.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;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.LoginAuthenticationFilter;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.Filter;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(WebConfig.class);
|
||||
|
||||
@Autowired
|
||||
private LoginAuthenticationFilter loginAuthenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private AuthorizationInterceptor authorizationInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/**").addResourceLocations("classpath:/resources/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("forward:/index.htm");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link CommonFilter} to the server, this is the simplest way to use Sentinel
|
||||
* for Web application.
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean sentinelFilterRegistration() {
|
||||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new CommonFilter());
|
||||
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");
|
||||
|
||||
return registration;
|
||||
}
|
||||
|
||||
@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 (suffixSet.stream().anyMatch(url::endsWith)) {
|
||||
return null;
|
||||
}
|
||||
return url;
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean authenticationFilterRegistration() {
|
||||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(loginAuthenticationFilter);
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("authenticationFilter");
|
||||
registration.setOrder(0);
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.MachineInfoVo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Carpenter Lee
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/app")
|
||||
public class AppController {
|
||||
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
@GetMapping("/names.json")
|
||||
public Result<List<String>> queryApps(HttpServletRequest request) {
|
||||
return Result.ofSuccess(appManagement.getAppNames());
|
||||
}
|
||||
|
||||
@GetMapping("/briefinfos.json")
|
||||
public Result<List<AppInfo>> queryAppInfos(HttpServletRequest request) {
|
||||
List<AppInfo> list = new ArrayList<>(appManagement.getBriefApps());
|
||||
Collections.sort(list, Comparator.comparing(AppInfo::getApp));
|
||||
return Result.ofSuccess(list);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{app}/machines.json")
|
||||
public Result<List<MachineInfoVo>> getMachinesByApp(@PathVariable("app") String app) {
|
||||
AppInfo appInfo = appManagement.getDetailApp(app);
|
||||
if (appInfo == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
List<MachineInfo> list = new ArrayList<>(appInfo.getMachines());
|
||||
Collections.sort(list, Comparator.comparing(MachineInfo::getApp).thenComparing(MachineInfo::getIp).thenComparingInt(MachineInfo::getPort));
|
||||
return Result.ofSuccess(MachineInfoVo.fromMachineInfoList(list));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{app}/machine/remove.json")
|
||||
public Result<String> removeMachineById(
|
||||
@PathVariable("app") String app,
|
||||
@RequestParam(name = "ip") String ip,
|
||||
@RequestParam(name = "port") int port) {
|
||||
AppInfo appInfo = appManagement.getDetailApp(app);
|
||||
if (appInfo == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
if (appManagement.removeMachine(app, ip, port)) {
|
||||
return Result.ofSuccessMsg("success");
|
||||
} else {
|
||||
return Result.ofFail(1, "remove failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.SimpleWebAuthServiceImpl;
|
||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author cdfive
|
||||
* @since 1.6.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class);
|
||||
|
||||
@Value("${auth.username:sentinel}")
|
||||
private String authUsername;
|
||||
|
||||
@Value("${auth.password:sentinel}")
|
||||
private String authPassword;
|
||||
|
||||
@Autowired
|
||||
private AuthService<HttpServletRequest> authService;
|
||||
|
||||
@PostMapping("/login")
|
||||
public Result<AuthService.AuthUser> login(HttpServletRequest request, String username, String password) {
|
||||
if (StringUtils.isNotBlank(DashboardConfig.getAuthUsername())) {
|
||||
authUsername = DashboardConfig.getAuthUsername();
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(DashboardConfig.getAuthPassword())) {
|
||||
authPassword = DashboardConfig.getAuthPassword();
|
||||
}
|
||||
|
||||
/*
|
||||
* If auth.username or auth.password is blank(set in application.properties or VM arguments),
|
||||
* auth will pass, as the front side validate the input which can't be blank,
|
||||
* so user can input any username or password(both are not blank) to login in that case.
|
||||
*/
|
||||
if (StringUtils.isNotBlank(authUsername) && !authUsername.equals(username)
|
||||
|| StringUtils.isNotBlank(authPassword) && !authPassword.equals(password)) {
|
||||
LOGGER.error("Login failed: Invalid username or password, username=" + username);
|
||||
return Result.ofFail(-1, "Invalid username or password");
|
||||
}
|
||||
|
||||
AuthService.AuthUser authUser = new SimpleWebAuthServiceImpl.SimpleWebAuthUserImpl(username);
|
||||
request.getSession().setAttribute(SimpleWebAuthServiceImpl.WEB_SESSION_KEY, authUser);
|
||||
return Result.ofSuccess(authUser);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/logout")
|
||||
public Result<?> logout(HttpServletRequest request) {
|
||||
request.getSession().invalidate();
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/check")
|
||||
public Result<?> check(HttpServletRequest request) {
|
||||
AuthService.AuthUser authUser = authService.getAuthUser(request);
|
||||
if (authUser == null) {
|
||||
return Result.ofFail(-1, "Not logged in");
|
||||
}
|
||||
return Result.ofSuccess(authUser);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.Date;
|
||||
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.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/authority")
|
||||
public class AuthorityRuleController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AuthorityRuleController.class);
|
||||
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
@Autowired
|
||||
private RuleRepository<AuthorityRuleEntity, Long> repository;
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
@GetMapping("/rules")
|
||||
@AuthAction(PrivilegeType.READ_RULE)
|
||||
public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
|
||||
@RequestParam String ip,
|
||||
@RequestParam Integer port) {
|
||||
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");
|
||||
}
|
||||
try {
|
||||
List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
|
||||
rules = repository.saveAll(rules);
|
||||
return Result.ofSuccess(rules);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when querying authority rules", throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <R> Result<R> checkEntityInternal(AuthorityRuleEntity entity) {
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "bad rule body");
|
||||
}
|
||||
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");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getResource())) {
|
||||
return Result.ofFail(-1, "resource name cannot be null or empty");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getLimitApp())) {
|
||||
return Result.ofFail(-1, "limitApp should be valid");
|
||||
}
|
||||
if (entity.getStrategy() != RuleConstant.AUTHORITY_WHITE
|
||||
&& entity.getStrategy() != RuleConstant.AUTHORITY_BLACK) {
|
||||
return Result.ofFail(-1, "Unknown strategy (must be blacklist or whitelist)");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/rule")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<AuthorityRuleEntity> apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) {
|
||||
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
entity.setId(null);
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Failed to add authority rule", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
|
||||
logger.info("Publish authority rules failed after rule add");
|
||||
}
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@PutMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
|
||||
@RequestBody AuthorityRuleEntity entity) {
|
||||
if (id == null || id <= 0) {
|
||||
return Result.ofFail(-1, "Invalid id");
|
||||
}
|
||||
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
entity.setId(id);
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(null);
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "Failed to save authority rule");
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Failed to save authority rule", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
|
||||
logger.info("Publish authority rules failed after rule update");
|
||||
}
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@DeleteMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.DELETE_RULE)
|
||||
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id cannot be null");
|
||||
}
|
||||
AuthorityRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
try {
|
||||
repository.delete(id);
|
||||
} catch (Exception e) {
|
||||
return Result.ofFail(-1, e.getMessage());
|
||||
}
|
||||
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
|
||||
logger.error("Publish authority rules failed after rule delete");
|
||||
}
|
||||
return Result.ofSuccess(id);
|
||||
}
|
||||
|
||||
private boolean publishRules(String app, String ip, Integer port) {
|
||||
List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.Date;
|
||||
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.repository.rule.RuleRepository;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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.RestController;
|
||||
|
||||
/**
|
||||
* Controller regarding APIs of degrade rules. Refactored since 1.8.0.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/degrade")
|
||||
public class DegradeController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DegradeController.class);
|
||||
|
||||
@Autowired
|
||||
private RuleRepository<DegradeRuleEntity, Long> repository;
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
@GetMapping("/rules.json")
|
||||
@AuthAction(PrivilegeType.READ_RULE)
|
||||
public Result<List<DegradeRuleEntity>> apiQueryMachineRules(String app, String ip, Integer port) {
|
||||
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<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);
|
||||
rules = repository.saveAll(rules);
|
||||
return Result.ofSuccess(rules);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("queryApps error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/rule")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<DegradeRuleEntity> apiAddRule(@RequestBody DegradeRuleEntity entity) {
|
||||
Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} 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);
|
||||
}
|
||||
|
||||
@PutMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<DegradeRuleEntity> apiUpdateRule(@PathVariable("id") Long id,
|
||||
@RequestBody DegradeRuleEntity entity) {
|
||||
if (id == null || id <= 0) {
|
||||
return Result.ofFail(-1, "id can't be null or negative");
|
||||
}
|
||||
DegradeRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofFail(-1, "Degrade rule does not exist, id=" + id);
|
||||
}
|
||||
entity.setApp(oldEntity.getApp());
|
||||
entity.setIp(oldEntity.getIp());
|
||||
entity.setPort(oldEntity.getPort());
|
||||
entity.setId(oldEntity.getId());
|
||||
Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
entity.setGmtCreate(oldEntity.getGmtCreate());
|
||||
entity.setGmtModified(new Date());
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} 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);
|
||||
}
|
||||
|
||||
@DeleteMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.DELETE_RULE)
|
||||
public Result<Long> delete(@PathVariable("id") Long id) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
|
||||
DegradeRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
try {
|
||||
repository.delete(id);
|
||||
} 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<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
|
||||
}
|
||||
|
||||
private <R> Result<R> checkEntityInternal(DegradeRuleEntity entity) {
|
||||
if (StringUtil.isBlank(entity.getApp())) {
|
||||
return Result.ofFail(-1, "app can't be blank");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getIp())) {
|
||||
return Result.ofFail(-1, "ip can't be null or empty");
|
||||
}
|
||||
if (!appManagement.isValidMachineOfApp(entity.getApp(), entity.getIp())) {
|
||||
return Result.ofFail(-1, "given ip does not belong to given app");
|
||||
}
|
||||
if (entity.getPort() == null || entity.getPort() <= 0) {
|
||||
return Result.ofFail(-1, "invalid port: " + entity.getPort());
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getLimitApp())) {
|
||||
return Result.ofFail(-1, "limitApp can't be null or empty");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getResource())) {
|
||||
return Result.ofFail(-1, "resource can't be null or empty");
|
||||
}
|
||||
Double threshold = entity.getCount();
|
||||
if (threshold == null || threshold < 0) {
|
||||
return Result.ofFail(-1, "invalid threshold: " + threshold);
|
||||
}
|
||||
Integer recoveryTimeoutSec = entity.getTimeWindow();
|
||||
if (recoveryTimeoutSec == null || recoveryTimeoutSec <= 0) {
|
||||
return Result.ofFail(-1, "recoveryTimeout should be positive");
|
||||
}
|
||||
Integer strategy = entity.getGrade();
|
||||
if (strategy == null) {
|
||||
return Result.ofFail(-1, "circuit breaker strategy cannot be null");
|
||||
}
|
||||
if (strategy < CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()
|
||||
|| strategy > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
|
||||
return Result.ofFail(-1, "Invalid circuit breaker strategy: " + strategy);
|
||||
}
|
||||
if (entity.getMinRequestAmount() == null || entity.getMinRequestAmount() <= 0) {
|
||||
return Result.ofFail(-1, "Invalid minRequestAmount");
|
||||
}
|
||||
if (entity.getStatIntervalMs() == null || entity.getStatIntervalMs() <= 0) {
|
||||
return Result.ofFail(-1, "Invalid statInterval");
|
||||
}
|
||||
if (strategy == RuleConstant.DEGRADE_GRADE_RT) {
|
||||
Double slowRatio = entity.getSlowRatioThreshold();
|
||||
if (slowRatio == null) {
|
||||
return Result.ofFail(-1, "SlowRatioThreshold is required for slow request ratio strategy");
|
||||
} else if (slowRatio < 0 || slowRatio > 1) {
|
||||
return Result.ofFail(-1, "SlowRatioThreshold should be in range: [0.0, 1.0]");
|
||||
}
|
||||
} else if (strategy == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
|
||||
if (threshold > 1) {
|
||||
return Result.ofFail(-1, "Ratio threshold should be in range: [0.0, 1.0]");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.EntryType;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/demo", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class DemoController {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(MachineRegistryController.class);
|
||||
|
||||
@RequestMapping("/greeting")
|
||||
public String greeting() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@RequestMapping("/link")
|
||||
@ResponseBody
|
||||
public String link() throws BlockException {
|
||||
|
||||
Entry entry = SphU.entry("head1", EntryType.IN);
|
||||
|
||||
Entry entry1 = SphU.entry("head2", EntryType.IN);
|
||||
Entry entry2 = SphU.entry("head3", EntryType.IN);
|
||||
Entry entry3 = SphU.entry("head4", EntryType.IN);
|
||||
|
||||
entry3.exit();
|
||||
entry2.exit();
|
||||
entry1.exit();
|
||||
entry.exit();
|
||||
return "successfully create a call link";
|
||||
}
|
||||
|
||||
@RequestMapping("/loop")
|
||||
@ResponseBody
|
||||
public String loop(String name, int time) throws BlockException {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread timer = new Thread(new RunTask(name, time, false));
|
||||
timer.setName("false");
|
||||
timer.start();
|
||||
}
|
||||
return "successfully create a loop thread";
|
||||
}
|
||||
|
||||
@RequestMapping("/slow")
|
||||
@ResponseBody
|
||||
public String slow(String name, int time) throws BlockException {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread timer = new Thread(new RunTask(name, time, true));
|
||||
timer.setName("false");
|
||||
timer.start();
|
||||
}
|
||||
return "successfully create a loop thread";
|
||||
}
|
||||
|
||||
static class RunTask implements Runnable {
|
||||
int time;
|
||||
boolean stop = false;
|
||||
String name;
|
||||
boolean slow = false;
|
||||
|
||||
public RunTask(String name, int time, boolean slow) {
|
||||
super();
|
||||
this.time = time;
|
||||
this.name = name;
|
||||
this.slow = slow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
ContextUtil.enter(String.valueOf(startTime));
|
||||
while (!stop) {
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - startTime > time * 1000) {
|
||||
stop = true;
|
||||
}
|
||||
Entry e1 = null;
|
||||
try {
|
||||
e1 = SphU.entry(name);
|
||||
|
||||
if (slow) {
|
||||
TimeUnit.MILLISECONDS.sleep(3000);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
if (e1 != null) {
|
||||
e1.exit();
|
||||
}
|
||||
}
|
||||
Random random2 = new Random();
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(random2.nextInt(200));
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
ContextUtil.exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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.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;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Flow rule controller.
|
||||
*
|
||||
* @author leyou
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/v1/flow")
|
||||
public class FlowControllerV1 {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FlowControllerV1.class);
|
||||
|
||||
@Autowired
|
||||
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
|
||||
@GetMapping("/rules")
|
||||
@AuthAction(PrivilegeType.READ_RULE)
|
||||
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app,
|
||||
@RequestParam String ip,
|
||||
@RequestParam Integer port) {
|
||||
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<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);
|
||||
rules = repository.saveAll(rules);
|
||||
return Result.ofSuccess(rules);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when querying flow rules", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private <R> Result<R> checkEntityInternal(FlowRuleEntity 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) {
|
||||
return Result.ofFail(-1, "port can't be null");
|
||||
}
|
||||
if (!appManagement.isValidMachineOfApp(entity.getApp(), entity.getIp())) {
|
||||
return Result.ofFail(-1, "given ip does not belong to given app");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getLimitApp())) {
|
||||
return Result.ofFail(-1, "limitApp can't be null or empty");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getResource())) {
|
||||
return Result.ofFail(-1, "resource can't be null or empty");
|
||||
}
|
||||
if (entity.getGrade() == null) {
|
||||
return Result.ofFail(-1, "grade can't be null");
|
||||
}
|
||||
if (entity.getGrade() != 0 && entity.getGrade() != 1) {
|
||||
return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
|
||||
}
|
||||
if (entity.getCount() == null || entity.getCount() < 0) {
|
||||
return Result.ofFail(-1, "count should be at lease zero");
|
||||
}
|
||||
if (entity.getStrategy() == null) {
|
||||
return Result.ofFail(-1, "strategy can't be null");
|
||||
}
|
||||
if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
|
||||
return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
|
||||
}
|
||||
if (entity.getControlBehavior() == null) {
|
||||
return Result.ofFail(-1, "controlBehavior can't be null");
|
||||
}
|
||||
int controlBehavior = entity.getControlBehavior();
|
||||
if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {
|
||||
return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
|
||||
}
|
||||
if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {
|
||||
return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
|
||||
}
|
||||
if (entity.isClusterMode() && entity.getClusterConfig() == null) {
|
||||
return Result.ofFail(-1, "cluster config should be valid");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/rule")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) {
|
||||
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
entity.setId(null);
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
entity.setLimitApp(entity.getLimitApp().trim());
|
||||
entity.setResource(entity.getResource().trim());
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/save.json")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<FlowRuleEntity> apiUpdateFlowRule(Long id, String app,
|
||||
String limitApp, String resource, Integer grade,
|
||||
Double count, Integer strategy, String refResource,
|
||||
Integer controlBehavior, Integer warmUpPeriodSec,
|
||||
Integer maxQueueingTimeMs) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
FlowRuleEntity entity = repository.findById(id);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "id " + id + " dose not exist");
|
||||
}
|
||||
if (StringUtil.isNotBlank(app)) {
|
||||
entity.setApp(app.trim());
|
||||
}
|
||||
if (StringUtil.isNotBlank(limitApp)) {
|
||||
entity.setLimitApp(limitApp.trim());
|
||||
}
|
||||
if (StringUtil.isNotBlank(resource)) {
|
||||
entity.setResource(resource.trim());
|
||||
}
|
||||
if (grade != null) {
|
||||
if (grade != 0 && grade != 1) {
|
||||
return Result.ofFail(-1, "grade must be 0 or 1, but " + grade + " got");
|
||||
}
|
||||
entity.setGrade(grade);
|
||||
}
|
||||
if (count != null) {
|
||||
entity.setCount(count);
|
||||
}
|
||||
if (strategy != null) {
|
||||
if (strategy != 0 && strategy != 1 && strategy != 2) {
|
||||
return Result.ofFail(-1, "strategy must be in [0, 1, 2], but " + strategy + " got");
|
||||
}
|
||||
entity.setStrategy(strategy);
|
||||
if (strategy != 0) {
|
||||
if (StringUtil.isBlank(refResource)) {
|
||||
return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
|
||||
}
|
||||
entity.setRefResource(refResource.trim());
|
||||
}
|
||||
}
|
||||
if (controlBehavior != null) {
|
||||
if (controlBehavior != 0 && controlBehavior != 1 && controlBehavior != 2) {
|
||||
return Result.ofFail(-1, "controlBehavior must be in [0, 1, 2], but " + controlBehavior + " got");
|
||||
}
|
||||
if (controlBehavior == 1 && warmUpPeriodSec == null) {
|
||||
return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
|
||||
}
|
||||
if (controlBehavior == 2 && maxQueueingTimeMs == null) {
|
||||
return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
|
||||
}
|
||||
entity.setControlBehavior(controlBehavior);
|
||||
if (warmUpPeriodSec != null) {
|
||||
entity.setWarmUpPeriodSec(warmUpPeriodSec);
|
||||
}
|
||||
if (maxQueueingTimeMs != null) {
|
||||
entity.setMaxQueueingTimeMs(maxQueueingTimeMs);
|
||||
}
|
||||
}
|
||||
Date date = new Date();
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "save entity fail: null");
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete.json")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<Long> apiDeleteFlowRule(Long id) {
|
||||
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
FlowRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
try {
|
||||
repository.delete(id);
|
||||
} catch (Exception e) {
|
||||
return Result.ofFail(-1, e.getMessage());
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
|
||||
List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/registry", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class MachineRegistryController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(MachineRegistryController.class);
|
||||
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/machine")
|
||||
public Result<?> receiveHeartBeat(String app,
|
||||
@RequestParam(value = "app_type", required = false, defaultValue = "0")
|
||||
Integer appType, Long version, String v, String hostname, String ip,
|
||||
Integer port) {
|
||||
if (StringUtil.isBlank(app) || app.length() > 256) {
|
||||
return Result.ofFail(-1, "invalid appName");
|
||||
}
|
||||
if (StringUtil.isBlank(ip) || ip.length() > 128) {
|
||||
return Result.ofFail(-1, "invalid ip: " + ip);
|
||||
}
|
||||
if (!InetAddressUtils.isIPv4Address(ip) && !InetAddressUtils.isIPv6Address(ip)) {
|
||||
return Result.ofFail(-1, "invalid ip: " + ip);
|
||||
}
|
||||
if (port == null || port < -1) {
|
||||
return Result.ofFail(-1, "invalid port");
|
||||
}
|
||||
if (hostname != null && hostname.length() > 256) {
|
||||
return Result.ofFail(-1, "hostname too long");
|
||||
}
|
||||
if (port == -1) {
|
||||
logger.warn("Receive heartbeat from " + ip + " but port not set yet");
|
||||
return Result.ofFail(-1, "your port not set yet");
|
||||
}
|
||||
String sentinelVersion = StringUtil.isBlank(v) ? "unknown" : v;
|
||||
|
||||
version = version == null ? System.currentTimeMillis() : version;
|
||||
try {
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
machineInfo.setApp(app);
|
||||
machineInfo.setAppType(appType);
|
||||
machineInfo.setHostname(hostname);
|
||||
machineInfo.setIp(ip);
|
||||
machineInfo.setPort(port);
|
||||
machineInfo.setHeartbeatVersion(version);
|
||||
machineInfo.setLastHeartbeat(System.currentTimeMillis());
|
||||
machineInfo.setVersion(sentinelVersion);
|
||||
appManagement.addMachine(machineInfo);
|
||||
return Result.ofSuccessMsg("success");
|
||||
} catch (Exception e) {
|
||||
logger.error("Receive heartbeat error", e);
|
||||
return Result.ofFail(-1, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.metric.MetricsRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.MetricVo;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping(value = "/metric", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class MetricController {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(MetricController.class);
|
||||
|
||||
private static final long maxQueryIntervalMs = 1000 * 60 * 60;
|
||||
|
||||
@Autowired
|
||||
private MetricsRepository<MetricEntity> metricStore;
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/queryTopResourceMetric.json")
|
||||
public Result<?> queryTopResourceMetric(final String app,
|
||||
Integer pageIndex,
|
||||
Integer pageSize,
|
||||
Boolean desc,
|
||||
Long startTime, Long endTime, String searchKey) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
if (pageIndex == null || pageIndex <= 0) {
|
||||
pageIndex = 1;
|
||||
}
|
||||
if (pageSize == null) {
|
||||
pageSize = 6;
|
||||
}
|
||||
if (pageSize >= 20) {
|
||||
pageSize = 20;
|
||||
}
|
||||
if (desc == null) {
|
||||
desc = true;
|
||||
}
|
||||
if (endTime == null) {
|
||||
endTime = System.currentTimeMillis();
|
||||
}
|
||||
if (startTime == null) {
|
||||
startTime = endTime - 1000 * 60 * 5;
|
||||
}
|
||||
if (endTime - startTime > maxQueryIntervalMs) {
|
||||
return Result.ofFail(-1, "time intervalMs is too big, must <= 1h");
|
||||
}
|
||||
List<String> resources = metricStore.listResourcesOfApp(app);
|
||||
logger.debug("queryTopResourceMetric(), resources.size()={}", resources.size());
|
||||
|
||||
if (resources == null || resources.isEmpty()) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
if (!desc) {
|
||||
Collections.reverse(resources);
|
||||
}
|
||||
if (StringUtil.isNotEmpty(searchKey)) {
|
||||
List<String> searched = new ArrayList<>();
|
||||
for (String resource : resources) {
|
||||
if (resource.contains(searchKey)) {
|
||||
searched.add(resource);
|
||||
}
|
||||
}
|
||||
resources = searched;
|
||||
}
|
||||
int totalPage = (resources.size() + pageSize - 1) / pageSize;
|
||||
List<String> topResource = new ArrayList<>();
|
||||
if (pageIndex <= totalPage) {
|
||||
topResource = resources.subList((pageIndex - 1) * pageSize,
|
||||
Math.min(pageIndex * pageSize, resources.size()));
|
||||
}
|
||||
final Map<String, Iterable<MetricVo>> map = new ConcurrentHashMap<>();
|
||||
logger.debug("topResource={}", topResource);
|
||||
long time = System.currentTimeMillis();
|
||||
for (final String resource : topResource) {
|
||||
List<MetricEntity> entities = metricStore.queryByAppAndResourceBetween(
|
||||
app, resource, startTime, endTime);
|
||||
logger.debug("resource={}, entities.size()={}", resource, entities == null ? "null" : entities.size());
|
||||
List<MetricVo> vos = MetricVo.fromMetricEntities(entities, resource);
|
||||
Iterable<MetricVo> vosSorted = sortMetricVoAndDistinct(vos);
|
||||
map.put(resource, vosSorted);
|
||||
}
|
||||
logger.debug("queryTopResourceMetric() total query time={} ms", System.currentTimeMillis() - time);
|
||||
Map<String, Object> resultMap = new HashMap<>(16);
|
||||
resultMap.put("totalCount", resources.size());
|
||||
resultMap.put("totalPage", totalPage);
|
||||
resultMap.put("pageIndex", pageIndex);
|
||||
resultMap.put("pageSize", pageSize);
|
||||
|
||||
Map<String, Iterable<MetricVo>> map2 = new LinkedHashMap<>();
|
||||
// order matters.
|
||||
for (String identity : topResource) {
|
||||
map2.put(identity, map.get(identity));
|
||||
}
|
||||
resultMap.put("metric", map2);
|
||||
return Result.ofSuccess(resultMap);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/queryByAppAndResource.json")
|
||||
public Result<?> queryByAppAndResource(String app, String identity, Long startTime, Long endTime) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
if (StringUtil.isEmpty(identity)) {
|
||||
return Result.ofFail(-1, "identity can't be null or empty");
|
||||
}
|
||||
if (endTime == null) {
|
||||
endTime = System.currentTimeMillis();
|
||||
}
|
||||
if (startTime == null) {
|
||||
startTime = endTime - 1000 * 60;
|
||||
}
|
||||
if (endTime - startTime > maxQueryIntervalMs) {
|
||||
return Result.ofFail(-1, "time intervalMs is too big, must <= 1h");
|
||||
}
|
||||
List<MetricEntity> entities = metricStore.queryByAppAndResourceBetween(
|
||||
app, identity, startTime, endTime);
|
||||
List<MetricVo> vos = MetricVo.fromMetricEntities(entities, identity);
|
||||
return Result.ofSuccess(sortMetricVoAndDistinct(vos));
|
||||
}
|
||||
|
||||
private Iterable<MetricVo> sortMetricVoAndDistinct(List<MetricVo> vos) {
|
||||
if (vos == null) {
|
||||
return null;
|
||||
}
|
||||
Map<Long, MetricVo> map = new TreeMap<>();
|
||||
for (MetricVo vo : vos) {
|
||||
MetricVo oldVo = map.get(vo.getTimestamp());
|
||||
if (oldVo == null || vo.getGmtCreate() > oldVo.getGmtCreate()) {
|
||||
map.put(vo.getTimestamp(), vo);
|
||||
}
|
||||
}
|
||||
return map.values();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/paramFlow")
|
||||
public class ParamFlowRuleController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ParamFlowRuleController.class);
|
||||
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
@Autowired
|
||||
private RuleRepository<ParamFlowRuleEntity, Long> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/rules")
|
||||
@AuthAction(PrivilegeType.READ_RULE)
|
||||
public Result<List<ParamFlowRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
|
||||
@RequestParam String ip,
|
||||
@RequestParam Integer port) {
|
||||
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());
|
||||
}
|
||||
} 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(PrivilegeType.WRITE_RULE)
|
||||
public Result<ParamFlowRuleEntity> apiAddParamFlowRule(@RequestBody ParamFlowRuleEntity entity) {
|
||||
Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
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();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
private <R> Result<R> checkEntityInternal(ParamFlowRuleEntity entity) {
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "bad rule body");
|
||||
}
|
||||
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");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getResource())) {
|
||||
return Result.ofFail(-1, "resource name cannot be null or empty");
|
||||
}
|
||||
if (entity.getCount() < 0) {
|
||||
return Result.ofFail(-1, "count should be valid");
|
||||
}
|
||||
if (entity.getGrade() != RuleConstant.FLOW_GRADE_QPS) {
|
||||
return Result.ofFail(-1, "Unknown mode (blockGrade) for parameter flow control");
|
||||
}
|
||||
if (entity.getParamIdx() == null || entity.getParamIdx() < 0) {
|
||||
return Result.ofFail(-1, "paramIdx should be valid");
|
||||
}
|
||||
if (entity.getDurationInSec() <= 0) {
|
||||
return Result.ofFail(-1, "durationInSec should be valid");
|
||||
}
|
||||
if (entity.getControlBehavior() < 0) {
|
||||
return Result.ofFail(-1, "controlBehavior should be valid");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@PutMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<ParamFlowRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
|
||||
@RequestBody ParamFlowRuleEntity entity) {
|
||||
if (id == null || id <= 0) {
|
||||
return Result.ofFail(-1, "Invalid id");
|
||||
}
|
||||
ParamFlowRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofFail(-1, "id " + id + " does not exist");
|
||||
}
|
||||
|
||||
Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
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();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.DELETE_RULE)
|
||||
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id cannot be null");
|
||||
}
|
||||
ParamFlowRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
try {
|
||||
repository.delete(id);
|
||||
publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get();
|
||||
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<Void> publishRules(String app, String ip, Integer port) {
|
||||
List<ParamFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules);
|
||||
}
|
||||
|
||||
private <R> Result<R> 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);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.csp.sentinel.command.vo.NodeVo;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.ResourceTreeNode;
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.ResourceVo;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Carpenter Lee
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/resource")
|
||||
public class ResourceController {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ResourceController.class);
|
||||
|
||||
@Autowired
|
||||
private SentinelApiClient httpFetcher;
|
||||
|
||||
/**
|
||||
* Fetch real time statistics info of the machine.
|
||||
*
|
||||
* @param ip ip to fetch
|
||||
* @param port port of the ip
|
||||
* @param type one of [root, default, cluster], 'root' means fetching from tree root node, 'default' means
|
||||
* fetching from tree default node, 'cluster' means fetching from cluster node.
|
||||
* @param searchKey key to search
|
||||
* @return node statistics info.
|
||||
*/
|
||||
@GetMapping("/machineResource.json")
|
||||
public Result<List<ResourceVo>> fetchResourceChainListOfMachine(String ip, Integer port, String type,
|
||||
String searchKey) {
|
||||
if (StringUtil.isEmpty(ip) || port == null) {
|
||||
return Result.ofFail(-1, "invalid param, give ip, port");
|
||||
}
|
||||
final String ROOT = "root";
|
||||
final String DEFAULT = "default";
|
||||
if (StringUtil.isEmpty(type)) {
|
||||
type = ROOT;
|
||||
}
|
||||
if (ROOT.equalsIgnoreCase(type) || DEFAULT.equalsIgnoreCase(type)) {
|
||||
List<NodeVo> nodeVos = httpFetcher.fetchResourceOfMachine(ip, port, type);
|
||||
if (nodeVos == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
ResourceTreeNode treeNode = ResourceTreeNode.fromNodeVoList(nodeVos);
|
||||
treeNode.searchIgnoreCase(searchKey);
|
||||
return Result.ofSuccess(ResourceVo.fromResourceTreeNode(treeNode));
|
||||
} else {
|
||||
// Normal (cluster node).
|
||||
List<NodeVo> nodeVos = httpFetcher.fetchClusterNodeOfMachine(ip, port, true);
|
||||
if (nodeVos == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
if (StringUtil.isNotEmpty(searchKey)) {
|
||||
nodeVos = nodeVos.stream().filter(node -> node.getResource()
|
||||
.toLowerCase().contains(searchKey.toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return Result.ofSuccess(ResourceVo.fromNodeVoList(nodeVos));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
||||
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.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author leyou(lihao)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/system")
|
||||
public class SystemController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SystemController.class);
|
||||
|
||||
@Autowired
|
||||
private RuleRepository<SystemRuleEntity, Long> repository;
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
private <R> Result<R> checkBasicParams(String app, String ip, Integer port) {
|
||||
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");
|
||||
}
|
||||
if (port <= 0 || port > 65535) {
|
||||
return Result.ofFail(-1, "port should be in (0, 65535)");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@GetMapping("/rules.json")
|
||||
@AuthAction(PrivilegeType.READ_RULE)
|
||||
public Result<List<SystemRuleEntity>> apiQueryMachineRules(String app, String ip,
|
||||
Integer port) {
|
||||
Result<List<SystemRuleEntity>> checkResult = checkBasicParams(app, ip, port);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
try {
|
||||
List<SystemRuleEntity> rules = sentinelApiClient.fetchSystemRuleOfMachine(app, ip, port);
|
||||
rules = repository.saveAll(rules);
|
||||
return Result.ofSuccess(rules);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Query machine system rules error", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private int countNotNullAndNotNegative(Number... values) {
|
||||
int notNullCount = 0;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i] != null && values[i].doubleValue() >= 0) {
|
||||
notNullCount++;
|
||||
}
|
||||
}
|
||||
return notNullCount;
|
||||
}
|
||||
|
||||
@RequestMapping("/new.json")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<SystemRuleEntity> apiAdd(String app, String ip, Integer port,
|
||||
Double highestSystemLoad, Double highestCpuUsage, Long avgRt,
|
||||
Long maxThread, Double qps) {
|
||||
|
||||
Result<SystemRuleEntity> checkResult = checkBasicParams(app, ip, port);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
int notNullCount = countNotNullAndNotNegative(highestSystemLoad, avgRt, maxThread, qps, highestCpuUsage);
|
||||
if (notNullCount != 1) {
|
||||
return Result.ofFail(-1, "only one of [highestSystemLoad, avgRt, maxThread, qps,highestCpuUsage] "
|
||||
+ "value must be set > 0, but " + notNullCount + " values get");
|
||||
}
|
||||
if (null != highestCpuUsage && highestCpuUsage > 1) {
|
||||
return Result.ofFail(-1, "highestCpuUsage must between [0.0, 1.0]");
|
||||
}
|
||||
SystemRuleEntity entity = new SystemRuleEntity();
|
||||
entity.setApp(app.trim());
|
||||
entity.setIp(ip.trim());
|
||||
entity.setPort(port);
|
||||
// -1 is a fake value
|
||||
if (null != highestSystemLoad) {
|
||||
entity.setHighestSystemLoad(highestSystemLoad);
|
||||
} else {
|
||||
entity.setHighestSystemLoad(-1D);
|
||||
}
|
||||
|
||||
if (null != highestCpuUsage) {
|
||||
entity.setHighestCpuUsage(highestCpuUsage);
|
||||
} else {
|
||||
entity.setHighestCpuUsage(-1D);
|
||||
}
|
||||
|
||||
if (avgRt != null) {
|
||||
entity.setAvgRt(avgRt);
|
||||
} else {
|
||||
entity.setAvgRt(-1L);
|
||||
}
|
||||
if (maxThread != null) {
|
||||
entity.setMaxThread(maxThread);
|
||||
} else {
|
||||
entity.setMaxThread(-1L);
|
||||
}
|
||||
if (qps != null) {
|
||||
entity.setQps(qps);
|
||||
} else {
|
||||
entity.setQps(-1D);
|
||||
}
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Add SystemRule error", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
if (!publishRules(app, ip, port)) {
|
||||
logger.warn("Publish system rules fail after rule add");
|
||||
}
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@GetMapping("/save.json")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
public Result<SystemRuleEntity> apiUpdateIfNotNull(Long id, String app, Double highestSystemLoad,
|
||||
Double highestCpuUsage, Long avgRt, Long maxThread, Double qps) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
SystemRuleEntity entity = repository.findById(id);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "id " + id + " dose not exist");
|
||||
}
|
||||
|
||||
if (StringUtil.isNotBlank(app)) {
|
||||
entity.setApp(app.trim());
|
||||
}
|
||||
if (highestSystemLoad != null) {
|
||||
if (highestSystemLoad < 0) {
|
||||
return Result.ofFail(-1, "highestSystemLoad must >= 0");
|
||||
}
|
||||
entity.setHighestSystemLoad(highestSystemLoad);
|
||||
}
|
||||
if (highestCpuUsage != null) {
|
||||
if (highestCpuUsage < 0) {
|
||||
return Result.ofFail(-1, "highestCpuUsage must >= 0");
|
||||
}
|
||||
if (highestCpuUsage > 1) {
|
||||
return Result.ofFail(-1, "highestCpuUsage must <= 1");
|
||||
}
|
||||
entity.setHighestCpuUsage(highestCpuUsage);
|
||||
}
|
||||
if (avgRt != null) {
|
||||
if (avgRt < 0) {
|
||||
return Result.ofFail(-1, "avgRt must >= 0");
|
||||
}
|
||||
entity.setAvgRt(avgRt);
|
||||
}
|
||||
if (maxThread != null) {
|
||||
if (maxThread < 0) {
|
||||
return Result.ofFail(-1, "maxThread must >= 0");
|
||||
}
|
||||
entity.setMaxThread(maxThread);
|
||||
}
|
||||
if (qps != null) {
|
||||
if (qps < 0) {
|
||||
return Result.ofFail(-1, "qps must >= 0");
|
||||
}
|
||||
entity.setQps(qps);
|
||||
}
|
||||
Date date = new Date();
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("save error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
|
||||
logger.info("publish system rules fail after rule update");
|
||||
}
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@RequestMapping("/delete.json")
|
||||
@AuthAction(PrivilegeType.DELETE_RULE)
|
||||
public Result<?> delete(Long id) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
SystemRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
try {
|
||||
repository.delete(id);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("delete error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
|
||||
logger.info("publish system rules fail after rule delete");
|
||||
}
|
||||
return Result.ofSuccess(id);
|
||||
}
|
||||
|
||||
private boolean publishRules(String app, String ip, Integer port) {
|
||||
List<SystemRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.setSystemRuleOfMachine(app, ip, port, rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author hisenyuan
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@RestController
|
||||
public class VersionController {
|
||||
|
||||
private static final String VERSION_PATTERN = "-";
|
||||
|
||||
@Value("${sentinel.dashboard.version:}")
|
||||
private String sentinelDashboardVersion;
|
||||
|
||||
@GetMapping("/version")
|
||||
public Result<String> apiGetVersion() {
|
||||
if (StringUtil.isNotBlank(sentinelDashboardVersion)) {
|
||||
String res = sentinelDashboardVersion;
|
||||
if (sentinelDashboardVersion.contains(VERSION_PATTERN)) {
|
||||
res = sentinelDashboardVersion.substring(0, sentinelDashboardVersion.indexOf(VERSION_PATTERN));
|
||||
}
|
||||
return Result.ofSuccess(res);
|
||||
} else {
|
||||
return Result.ofFail(1, "getVersion failed: empty version");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.controller.cluster;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterAppFullAssignRequest;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterAppAssignResultVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterAppSingleServerAssignRequest;
|
||||
import com.alibaba.csp.sentinel.dashboard.service.ClusterAssignService;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/cluster/assign")
|
||||
public class ClusterAssignController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ClusterAssignController.class);
|
||||
|
||||
@Autowired
|
||||
private ClusterAssignService clusterAssignService;
|
||||
|
||||
@PostMapping("/all_server/{app}")
|
||||
public Result<ClusterAppAssignResultVO> apiAssignAllClusterServersOfApp(@PathVariable String app,
|
||||
@RequestBody
|
||||
ClusterAppFullAssignRequest assignRequest) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app cannot be null or empty");
|
||||
}
|
||||
if (assignRequest == null || assignRequest.getClusterMap() == null
|
||||
|| assignRequest.getRemainingList() == null) {
|
||||
return Result.ofFail(-1, "bad request body");
|
||||
}
|
||||
try {
|
||||
return Result.ofSuccess(clusterAssignService.applyAssignToApp(app, assignRequest.getClusterMap(),
|
||||
assignRequest.getRemainingList()));
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when assigning full cluster servers for app: " + app, throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/single_server/{app}")
|
||||
public Result<ClusterAppAssignResultVO> apiAssignSingleClusterServersOfApp(@PathVariable String app,
|
||||
@RequestBody ClusterAppSingleServerAssignRequest assignRequest) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app cannot be null or empty");
|
||||
}
|
||||
if (assignRequest == null || assignRequest.getClusterMap() == null) {
|
||||
return Result.ofFail(-1, "bad request body");
|
||||
}
|
||||
try {
|
||||
return Result.ofSuccess(clusterAssignService.applyAssignToApp(app, Collections.singletonList(assignRequest.getClusterMap()),
|
||||
assignRequest.getRemainingList()));
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when assigning single cluster servers for app: " + app, throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/unbind_server/{app}")
|
||||
public Result<ClusterAppAssignResultVO> apiUnbindClusterServersOfApp(@PathVariable String app,
|
||||
@RequestBody Set<String> machineIds) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app cannot be null or empty");
|
||||
}
|
||||
if (machineIds == null || machineIds.isEmpty()) {
|
||||
return Result.ofFail(-1, "bad request body");
|
||||
}
|
||||
try {
|
||||
return Result.ofSuccess(clusterAssignService.unbindClusterServers(app, machineIds));
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when unbinding cluster server {} for app <{}>", machineIds, app, throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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.controller.cluster;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
|
||||
import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.request.ClusterClientModifyRequest;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.request.ClusterModifyRequest;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.request.ClusterServerModifyRequest;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.AppClusterClientStateWrapVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.AppClusterServerStateWrapVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.ClusterUniversalStatePairVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.state.ClusterUniversalStateVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.service.ClusterConfigService;
|
||||
import com.alibaba.csp.sentinel.dashboard.util.ClusterEntityUtils;
|
||||
import com.alibaba.csp.sentinel.dashboard.util.VersionUtils;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/cluster")
|
||||
public class ClusterConfigController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ClusterConfigController.class);
|
||||
|
||||
private final SentinelVersion version140 = new SentinelVersion().setMajorVersion(1).setMinorVersion(4);
|
||||
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
@Autowired
|
||||
private ClusterConfigService clusterConfigService;
|
||||
|
||||
@PostMapping("/config/modify_single")
|
||||
public Result<Boolean> apiModifyClusterConfig(@RequestBody String payload) {
|
||||
if (StringUtil.isBlank(payload)) {
|
||||
return Result.ofFail(-1, "empty request body");
|
||||
}
|
||||
try {
|
||||
JSONObject body = JSON.parseObject(payload);
|
||||
if (body.containsKey(KEY_MODE)) {
|
||||
int mode = body.getInteger(KEY_MODE);
|
||||
switch (mode) {
|
||||
case ClusterStateManager.CLUSTER_CLIENT:
|
||||
ClusterClientModifyRequest data = JSON.parseObject(payload, ClusterClientModifyRequest.class);
|
||||
Result<Boolean> res = checkValidRequest(data);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
clusterConfigService.modifyClusterClientConfig(data).get();
|
||||
return Result.ofSuccess(true);
|
||||
case ClusterStateManager.CLUSTER_SERVER:
|
||||
ClusterServerModifyRequest d = JSON.parseObject(payload, ClusterServerModifyRequest.class);
|
||||
Result<Boolean> r = checkValidRequest(d);
|
||||
if (r != null) {
|
||||
return r;
|
||||
}
|
||||
// TODO: bad design here, should refactor!
|
||||
clusterConfigService.modifyClusterServerConfig(d).get();
|
||||
return Result.ofSuccess(true);
|
||||
default:
|
||||
return Result.ofFail(-1, "invalid mode");
|
||||
}
|
||||
}
|
||||
return Result.ofFail(-1, "invalid parameter");
|
||||
} catch (ExecutionException ex) {
|
||||
logger.error("Error when modifying cluster config", ex.getCause());
|
||||
return errorResponse(ex);
|
||||
} catch (Throwable ex) {
|
||||
logger.error("Error when modifying cluster config", ex);
|
||||
return Result.ofFail(-1, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Result<T> errorResponse(ExecutionException ex) {
|
||||
if (isNotSupported(ex.getCause())) {
|
||||
return unsupportedVersion();
|
||||
} else {
|
||||
return Result.ofThrowable(-1, ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/state_single")
|
||||
public Result<ClusterUniversalStateVO> apiGetClusterState(@RequestParam String app,
|
||||
@RequestParam String ip,
|
||||
@RequestParam Integer port) {
|
||||
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 (!checkIfSupported(app, ip, port)) {
|
||||
return unsupportedVersion();
|
||||
}
|
||||
try {
|
||||
return clusterConfigService.getClusterUniversalState(app, ip, port)
|
||||
.thenApply(Result::ofSuccess)
|
||||
.get();
|
||||
} catch (ExecutionException ex) {
|
||||
logger.error("Error when fetching cluster state", ex.getCause());
|
||||
return errorResponse(ex);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when fetching cluster state", throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/server_state/{app}")
|
||||
public Result<List<AppClusterServerStateWrapVO>> apiGetClusterServerStateOfApp(@PathVariable String app) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app cannot be null or empty");
|
||||
}
|
||||
try {
|
||||
return clusterConfigService.getClusterUniversalState(app)
|
||||
.thenApply(ClusterEntityUtils::wrapToAppClusterServerState)
|
||||
.thenApply(Result::ofSuccess)
|
||||
.get();
|
||||
} catch (ExecutionException ex) {
|
||||
logger.error("Error when fetching cluster server state of app: " + app, ex.getCause());
|
||||
return errorResponse(ex);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when fetching cluster server state of app: " + app, throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/client_state/{app}")
|
||||
public Result<List<AppClusterClientStateWrapVO>> apiGetClusterClientStateOfApp(@PathVariable String app) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app cannot be null or empty");
|
||||
}
|
||||
try {
|
||||
return clusterConfigService.getClusterUniversalState(app)
|
||||
.thenApply(ClusterEntityUtils::wrapToAppClusterClientState)
|
||||
.thenApply(Result::ofSuccess)
|
||||
.get();
|
||||
} catch (ExecutionException ex) {
|
||||
logger.error("Error when fetching cluster token client state of app: " + app, ex.getCause());
|
||||
return errorResponse(ex);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when fetching cluster token client state of app: " + app, throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/state/{app}")
|
||||
public Result<List<ClusterUniversalStatePairVO>> apiGetClusterStateOfApp(@PathVariable String app) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app cannot be null or empty");
|
||||
}
|
||||
try {
|
||||
return clusterConfigService.getClusterUniversalState(app)
|
||||
.thenApply(Result::ofSuccess)
|
||||
.get();
|
||||
} catch (ExecutionException ex) {
|
||||
logger.error("Error when fetching cluster state of app: " + app, ex.getCause());
|
||||
return errorResponse(ex);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when fetching cluster state of app: " + app, throwable);
|
||||
return Result.ofFail(-1, throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNotSupported(Throwable ex) {
|
||||
return ex instanceof CommandNotFoundException;
|
||||
}
|
||||
|
||||
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(version140)))
|
||||
.orElse(true);
|
||||
// If error occurred or cannot retrieve machine info, return true.
|
||||
} catch (Exception ex) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private Result<Boolean> checkValidRequest(ClusterModifyRequest request) {
|
||||
if (StringUtil.isEmpty(request.getApp())) {
|
||||
return Result.ofFail(-1, "app cannot be empty");
|
||||
}
|
||||
if (StringUtil.isEmpty(request.getIp())) {
|
||||
return Result.ofFail(-1, "ip cannot be empty");
|
||||
}
|
||||
if (request.getPort() == null || request.getPort() < 0) {
|
||||
return Result.ofFail(-1, "invalid port");
|
||||
}
|
||||
if (request.getMode() == null || request.getMode() < 0) {
|
||||
return Result.ofFail(-1, "invalid mode");
|
||||
}
|
||||
if (!checkIfSupported(request.getApp(), request.getIp(), request.getPort())) {
|
||||
return unsupportedVersion();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private <R> Result<R> unsupportedVersion() {
|
||||
return Result.ofFail(4041, "Sentinel client not supported for cluster flow control (unsupported version or dependency absent)");
|
||||
}
|
||||
|
||||
private static final String KEY_MODE = "mode";
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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.controller.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiPredicateItemEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.AddApiReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.ApiPredicateItemVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.api.UpdateApiReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemApiDefinitionStore;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.*;
|
||||
|
||||
/**
|
||||
* Gateway api Controller for manage gateway api definitions.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/gateway/api")
|
||||
public class GatewayApiController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GatewayApiController.class);
|
||||
|
||||
@Autowired
|
||||
private InMemApiDefinitionStore repository;
|
||||
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
|
||||
@GetMapping("/list.json")
|
||||
@AuthAction(AuthService.PrivilegeType.READ_RULE)
|
||||
public Result<List<ApiDefinitionEntity>> queryApis(String app, String ip, Integer port) {
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
try {
|
||||
List<ApiDefinitionEntity> apis = sentinelApiClient.fetchApis(app, ip, port).get();
|
||||
repository.saveAll(apis);
|
||||
return Result.ofSuccess(apis);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("queryApis error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/new.json")
|
||||
@AuthAction(AuthService.PrivilegeType.WRITE_RULE)
|
||||
public Result<ApiDefinitionEntity> addApi(HttpServletRequest request, @RequestBody AddApiReqVo reqVo) {
|
||||
|
||||
String app = reqVo.getApp();
|
||||
if (StringUtil.isBlank(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
|
||||
ApiDefinitionEntity entity = new ApiDefinitionEntity();
|
||||
entity.setApp(app.trim());
|
||||
|
||||
String ip = reqVo.getIp();
|
||||
if (StringUtil.isBlank(ip)) {
|
||||
return Result.ofFail(-1, "ip can't be null or empty");
|
||||
}
|
||||
entity.setIp(ip.trim());
|
||||
|
||||
Integer port = reqVo.getPort();
|
||||
if (port == null) {
|
||||
return Result.ofFail(-1, "port can't be null");
|
||||
}
|
||||
entity.setPort(port);
|
||||
|
||||
// API名称
|
||||
String apiName = reqVo.getApiName();
|
||||
if (StringUtil.isBlank(apiName)) {
|
||||
return Result.ofFail(-1, "apiName can't be null or empty");
|
||||
}
|
||||
entity.setApiName(apiName.trim());
|
||||
|
||||
// 匹配规则列表
|
||||
List<ApiPredicateItemVo> predicateItems = reqVo.getPredicateItems();
|
||||
if (CollectionUtils.isEmpty(predicateItems)) {
|
||||
return Result.ofFail(-1, "predicateItems can't empty");
|
||||
}
|
||||
|
||||
List<ApiPredicateItemEntity> predicateItemEntities = new ArrayList<>();
|
||||
for (ApiPredicateItemVo predicateItem : predicateItems) {
|
||||
ApiPredicateItemEntity predicateItemEntity = new ApiPredicateItemEntity();
|
||||
|
||||
// 匹配模式
|
||||
Integer matchStrategy = predicateItem.getMatchStrategy();
|
||||
if (!Arrays.asList(URL_MATCH_STRATEGY_EXACT, URL_MATCH_STRATEGY_PREFIX, URL_MATCH_STRATEGY_REGEX).contains(matchStrategy)) {
|
||||
return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy);
|
||||
}
|
||||
predicateItemEntity.setMatchStrategy(matchStrategy);
|
||||
|
||||
// 匹配串
|
||||
String pattern = predicateItem.getPattern();
|
||||
if (StringUtil.isBlank(pattern)) {
|
||||
return Result.ofFail(-1, "pattern can't be null or empty");
|
||||
}
|
||||
predicateItemEntity.setPattern(pattern);
|
||||
|
||||
predicateItemEntities.add(predicateItemEntity);
|
||||
}
|
||||
entity.setPredicateItems(new LinkedHashSet<>(predicateItemEntities));
|
||||
|
||||
// 检查API名称不能重复
|
||||
List<ApiDefinitionEntity> allApis = repository.findAllByMachine(MachineInfo.of(app.trim(), ip.trim(), port));
|
||||
if (allApis.stream().map(o -> o.getApiName()).anyMatch(o -> o.equals(apiName.trim()))) {
|
||||
return Result.ofFail(-1, "apiName exists: " + apiName);
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("add gateway api error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
|
||||
if (!publishApis(app, ip, port)) {
|
||||
logger.warn("publish gateway apis fail after add");
|
||||
}
|
||||
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@PostMapping("/save.json")
|
||||
@AuthAction(AuthService.PrivilegeType.WRITE_RULE)
|
||||
public Result<ApiDefinitionEntity> updateApi(@RequestBody UpdateApiReqVo reqVo) {
|
||||
String app = reqVo.getApp();
|
||||
if (StringUtil.isBlank(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
|
||||
Long id = reqVo.getId();
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
|
||||
ApiDefinitionEntity entity = repository.findById(id);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "api does not exist, id=" + id);
|
||||
}
|
||||
|
||||
// 匹配规则列表
|
||||
List<ApiPredicateItemVo> predicateItems = reqVo.getPredicateItems();
|
||||
if (CollectionUtils.isEmpty(predicateItems)) {
|
||||
return Result.ofFail(-1, "predicateItems can't empty");
|
||||
}
|
||||
|
||||
List<ApiPredicateItemEntity> predicateItemEntities = new ArrayList<>();
|
||||
for (ApiPredicateItemVo predicateItem : predicateItems) {
|
||||
ApiPredicateItemEntity predicateItemEntity = new ApiPredicateItemEntity();
|
||||
|
||||
// 匹配模式
|
||||
int matchStrategy = predicateItem.getMatchStrategy();
|
||||
if (!Arrays.asList(URL_MATCH_STRATEGY_EXACT, URL_MATCH_STRATEGY_PREFIX, URL_MATCH_STRATEGY_REGEX).contains(matchStrategy)) {
|
||||
return Result.ofFail(-1, "Invalid matchStrategy: " + matchStrategy);
|
||||
}
|
||||
predicateItemEntity.setMatchStrategy(matchStrategy);
|
||||
|
||||
// 匹配串
|
||||
String pattern = predicateItem.getPattern();
|
||||
if (StringUtil.isBlank(pattern)) {
|
||||
return Result.ofFail(-1, "pattern can't be null or empty");
|
||||
}
|
||||
predicateItemEntity.setPattern(pattern);
|
||||
|
||||
predicateItemEntities.add(predicateItemEntity);
|
||||
}
|
||||
entity.setPredicateItems(new LinkedHashSet<>(predicateItemEntities));
|
||||
|
||||
Date date = new Date();
|
||||
entity.setGmtModified(date);
|
||||
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("update gateway api error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
|
||||
if (!publishApis(app, entity.getIp(), entity.getPort())) {
|
||||
logger.warn("publish gateway apis fail after update");
|
||||
}
|
||||
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@PostMapping("/delete.json")
|
||||
@AuthAction(AuthService.PrivilegeType.DELETE_RULE)
|
||||
|
||||
public Result<Long> deleteApi(Long id) {
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
|
||||
ApiDefinitionEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
try {
|
||||
repository.delete(id);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("delete gateway api error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
|
||||
if (!publishApis(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
|
||||
logger.warn("publish gateway apis fail after delete");
|
||||
}
|
||||
|
||||
return Result.ofSuccess(id);
|
||||
}
|
||||
|
||||
private boolean publishApis(String app, String ip, Integer port) {
|
||||
List<ApiDefinitionEntity> apis = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.modifyApis(app, ip, port, apis);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* 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.controller.gateway;
|
||||
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
|
||||
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayParamFlowItemEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.AddFlowRuleReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.GatewayParamFlowItemVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.vo.gateway.rule.UpdateFlowRuleReqVo;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.gateway.InMemGatewayFlowRuleStore;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.*;
|
||||
import static com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants.*;
|
||||
import static com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity.*;
|
||||
|
||||
/**
|
||||
* Gateway flow rule Controller for manage gateway flow rules.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/gateway/flow")
|
||||
public class GatewayFlowRuleController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(GatewayFlowRuleController.class);
|
||||
|
||||
@Autowired
|
||||
private InMemGatewayFlowRuleStore repository;
|
||||
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
|
||||
@GetMapping("/list.json")
|
||||
@AuthAction(AuthService.PrivilegeType.READ_RULE)
|
||||
public Result<List<GatewayFlowRuleEntity>> queryFlowRules(String app, String ip, Integer port) {
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
try {
|
||||
List<GatewayFlowRuleEntity> rules = sentinelApiClient.fetchGatewayFlowRules(app, ip, port).get();
|
||||
repository.saveAll(rules);
|
||||
return Result.ofSuccess(rules);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("query gateway flow rules error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/new.json")
|
||||
@AuthAction(AuthService.PrivilegeType.WRITE_RULE)
|
||||
public Result<GatewayFlowRuleEntity> addFlowRule(@RequestBody AddFlowRuleReqVo reqVo) {
|
||||
|
||||
String app = reqVo.getApp();
|
||||
if (StringUtil.isBlank(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
|
||||
GatewayFlowRuleEntity entity = new GatewayFlowRuleEntity();
|
||||
entity.setApp(app.trim());
|
||||
|
||||
String ip = reqVo.getIp();
|
||||
if (StringUtil.isBlank(ip)) {
|
||||
return Result.ofFail(-1, "ip can't be null or empty");
|
||||
}
|
||||
entity.setIp(ip.trim());
|
||||
|
||||
Integer port = reqVo.getPort();
|
||||
if (port == null) {
|
||||
return Result.ofFail(-1, "port can't be null");
|
||||
}
|
||||
entity.setPort(port);
|
||||
|
||||
// API类型, Route ID或API分组
|
||||
Integer resourceMode = reqVo.getResourceMode();
|
||||
if (resourceMode == null) {
|
||||
return Result.ofFail(-1, "resourceMode can't be null");
|
||||
}
|
||||
if (!Arrays.asList(RESOURCE_MODE_ROUTE_ID, RESOURCE_MODE_CUSTOM_API_NAME).contains(resourceMode)) {
|
||||
return Result.ofFail(-1, "invalid resourceMode: " + resourceMode);
|
||||
}
|
||||
entity.setResourceMode(resourceMode);
|
||||
|
||||
// API名称
|
||||
String resource = reqVo.getResource();
|
||||
if (StringUtil.isBlank(resource)) {
|
||||
return Result.ofFail(-1, "resource can't be null or empty");
|
||||
}
|
||||
entity.setResource(resource.trim());
|
||||
|
||||
// 针对请求属性
|
||||
GatewayParamFlowItemVo paramItem = reqVo.getParamItem();
|
||||
if (paramItem != null) {
|
||||
GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();
|
||||
entity.setParamItem(itemEntity);
|
||||
|
||||
// 参数属性 0-ClientIP 1-Remote Host 2-Header 3-URL参数 4-Cookie
|
||||
Integer parseStrategy = paramItem.getParseStrategy();
|
||||
if (!Arrays.asList(PARAM_PARSE_STRATEGY_CLIENT_IP, PARAM_PARSE_STRATEGY_HOST, PARAM_PARSE_STRATEGY_HEADER
|
||||
, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
|
||||
return Result.ofFail(-1, "invalid parseStrategy: " + parseStrategy);
|
||||
}
|
||||
itemEntity.setParseStrategy(paramItem.getParseStrategy());
|
||||
|
||||
// 当参数属性为2-Header 3-URL参数 4-Cookie时,参数名称必填
|
||||
if (Arrays.asList(PARAM_PARSE_STRATEGY_HEADER, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
|
||||
// 参数名称
|
||||
String fieldName = paramItem.getFieldName();
|
||||
if (StringUtil.isBlank(fieldName)) {
|
||||
return Result.ofFail(-1, "fieldName can't be null or empty");
|
||||
}
|
||||
itemEntity.setFieldName(paramItem.getFieldName());
|
||||
}
|
||||
|
||||
String pattern = paramItem.getPattern();
|
||||
// 如果匹配串不为空,验证匹配模式
|
||||
if (StringUtil.isNotEmpty(pattern)) {
|
||||
itemEntity.setPattern(pattern);
|
||||
Integer matchStrategy = paramItem.getMatchStrategy();
|
||||
if (!Arrays.asList(PARAM_MATCH_STRATEGY_EXACT, PARAM_MATCH_STRATEGY_CONTAINS, PARAM_MATCH_STRATEGY_REGEX).contains(matchStrategy)) {
|
||||
return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy);
|
||||
}
|
||||
itemEntity.setMatchStrategy(matchStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
// 阈值类型 0-线程数 1-QPS
|
||||
Integer grade = reqVo.getGrade();
|
||||
if (grade == null) {
|
||||
return Result.ofFail(-1, "grade can't be null");
|
||||
}
|
||||
if (!Arrays.asList(FLOW_GRADE_THREAD, FLOW_GRADE_QPS).contains(grade)) {
|
||||
return Result.ofFail(-1, "invalid grade: " + grade);
|
||||
}
|
||||
entity.setGrade(grade);
|
||||
|
||||
// QPS阈值
|
||||
Double count = reqVo.getCount();
|
||||
if (count == null) {
|
||||
return Result.ofFail(-1, "count can't be null");
|
||||
}
|
||||
if (count < 0) {
|
||||
return Result.ofFail(-1, "count should be at lease zero");
|
||||
}
|
||||
entity.setCount(count);
|
||||
|
||||
// 间隔
|
||||
Long interval = reqVo.getInterval();
|
||||
if (interval == null) {
|
||||
return Result.ofFail(-1, "interval can't be null");
|
||||
}
|
||||
if (interval <= 0) {
|
||||
return Result.ofFail(-1, "interval should be greater than zero");
|
||||
}
|
||||
entity.setInterval(interval);
|
||||
|
||||
// 间隔单位
|
||||
Integer intervalUnit = reqVo.getIntervalUnit();
|
||||
if (intervalUnit == null) {
|
||||
return Result.ofFail(-1, "intervalUnit can't be null");
|
||||
}
|
||||
if (!Arrays.asList(INTERVAL_UNIT_SECOND, INTERVAL_UNIT_MINUTE, INTERVAL_UNIT_HOUR, INTERVAL_UNIT_DAY).contains(intervalUnit)) {
|
||||
return Result.ofFail(-1, "Invalid intervalUnit: " + intervalUnit);
|
||||
}
|
||||
entity.setIntervalUnit(intervalUnit);
|
||||
|
||||
// 流控方式 0-快速失败 2-匀速排队
|
||||
Integer controlBehavior = reqVo.getControlBehavior();
|
||||
if (controlBehavior == null) {
|
||||
return Result.ofFail(-1, "controlBehavior can't be null");
|
||||
}
|
||||
if (!Arrays.asList(CONTROL_BEHAVIOR_DEFAULT, CONTROL_BEHAVIOR_RATE_LIMITER).contains(controlBehavior)) {
|
||||
return Result.ofFail(-1, "invalid controlBehavior: " + controlBehavior);
|
||||
}
|
||||
entity.setControlBehavior(controlBehavior);
|
||||
|
||||
if (CONTROL_BEHAVIOR_DEFAULT == controlBehavior) {
|
||||
// 0-快速失败, 则Burst size必填
|
||||
Integer burst = reqVo.getBurst();
|
||||
if (burst == null) {
|
||||
return Result.ofFail(-1, "burst can't be null");
|
||||
}
|
||||
if (burst < 0) {
|
||||
return Result.ofFail(-1, "invalid burst: " + burst);
|
||||
}
|
||||
entity.setBurst(burst);
|
||||
} else if (CONTROL_BEHAVIOR_RATE_LIMITER == controlBehavior) {
|
||||
// 1-匀速排队, 则超时时间必填
|
||||
Integer maxQueueingTimeoutMs = reqVo.getMaxQueueingTimeoutMs();
|
||||
if (maxQueueingTimeoutMs == null) {
|
||||
return Result.ofFail(-1, "maxQueueingTimeoutMs can't be null");
|
||||
}
|
||||
if (maxQueueingTimeoutMs < 0) {
|
||||
return Result.ofFail(-1, "invalid maxQueueingTimeoutMs: " + maxQueueingTimeoutMs);
|
||||
}
|
||||
entity.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs);
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("add gateway flow rule error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
|
||||
if (!publishRules(app, ip, port)) {
|
||||
logger.warn("publish gateway flow rules fail after add");
|
||||
}
|
||||
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@PostMapping("/save.json")
|
||||
@AuthAction(AuthService.PrivilegeType.WRITE_RULE)
|
||||
public Result<GatewayFlowRuleEntity> updateFlowRule(@RequestBody UpdateFlowRuleReqVo reqVo) {
|
||||
|
||||
String app = reqVo.getApp();
|
||||
if (StringUtil.isBlank(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
|
||||
Long id = reqVo.getId();
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
|
||||
GatewayFlowRuleEntity entity = repository.findById(id);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "gateway flow rule does not exist, id=" + id);
|
||||
}
|
||||
|
||||
// 针对请求属性
|
||||
GatewayParamFlowItemVo paramItem = reqVo.getParamItem();
|
||||
if (paramItem != null) {
|
||||
GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();
|
||||
entity.setParamItem(itemEntity);
|
||||
|
||||
// 参数属性 0-ClientIP 1-Remote Host 2-Header 3-URL参数 4-Cookie
|
||||
Integer parseStrategy = paramItem.getParseStrategy();
|
||||
if (!Arrays.asList(PARAM_PARSE_STRATEGY_CLIENT_IP, PARAM_PARSE_STRATEGY_HOST, PARAM_PARSE_STRATEGY_HEADER
|
||||
, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
|
||||
return Result.ofFail(-1, "invalid parseStrategy: " + parseStrategy);
|
||||
}
|
||||
itemEntity.setParseStrategy(paramItem.getParseStrategy());
|
||||
|
||||
// 当参数属性为2-Header 3-URL参数 4-Cookie时,参数名称必填
|
||||
if (Arrays.asList(PARAM_PARSE_STRATEGY_HEADER, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
|
||||
// 参数名称
|
||||
String fieldName = paramItem.getFieldName();
|
||||
if (StringUtil.isBlank(fieldName)) {
|
||||
return Result.ofFail(-1, "fieldName can't be null or empty");
|
||||
}
|
||||
itemEntity.setFieldName(paramItem.getFieldName());
|
||||
}
|
||||
|
||||
String pattern = paramItem.getPattern();
|
||||
// 如果匹配串不为空,验证匹配模式
|
||||
if (StringUtil.isNotEmpty(pattern)) {
|
||||
itemEntity.setPattern(pattern);
|
||||
Integer matchStrategy = paramItem.getMatchStrategy();
|
||||
if (!Arrays.asList(PARAM_MATCH_STRATEGY_EXACT, PARAM_MATCH_STRATEGY_CONTAINS, PARAM_MATCH_STRATEGY_REGEX).contains(matchStrategy)) {
|
||||
return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy);
|
||||
}
|
||||
itemEntity.setMatchStrategy(matchStrategy);
|
||||
}
|
||||
} else {
|
||||
entity.setParamItem(null);
|
||||
}
|
||||
|
||||
// 阈值类型 0-线程数 1-QPS
|
||||
Integer grade = reqVo.getGrade();
|
||||
if (grade == null) {
|
||||
return Result.ofFail(-1, "grade can't be null");
|
||||
}
|
||||
if (!Arrays.asList(FLOW_GRADE_THREAD, FLOW_GRADE_QPS).contains(grade)) {
|
||||
return Result.ofFail(-1, "invalid grade: " + grade);
|
||||
}
|
||||
entity.setGrade(grade);
|
||||
|
||||
// QPS阈值
|
||||
Double count = reqVo.getCount();
|
||||
if (count == null) {
|
||||
return Result.ofFail(-1, "count can't be null");
|
||||
}
|
||||
if (count < 0) {
|
||||
return Result.ofFail(-1, "count should be at lease zero");
|
||||
}
|
||||
entity.setCount(count);
|
||||
|
||||
// 间隔
|
||||
Long interval = reqVo.getInterval();
|
||||
if (interval == null) {
|
||||
return Result.ofFail(-1, "interval can't be null");
|
||||
}
|
||||
if (interval <= 0) {
|
||||
return Result.ofFail(-1, "interval should be greater than zero");
|
||||
}
|
||||
entity.setInterval(interval);
|
||||
|
||||
// 间隔单位
|
||||
Integer intervalUnit = reqVo.getIntervalUnit();
|
||||
if (intervalUnit == null) {
|
||||
return Result.ofFail(-1, "intervalUnit can't be null");
|
||||
}
|
||||
if (!Arrays.asList(INTERVAL_UNIT_SECOND, INTERVAL_UNIT_MINUTE, INTERVAL_UNIT_HOUR, INTERVAL_UNIT_DAY).contains(intervalUnit)) {
|
||||
return Result.ofFail(-1, "Invalid intervalUnit: " + intervalUnit);
|
||||
}
|
||||
entity.setIntervalUnit(intervalUnit);
|
||||
|
||||
// 流控方式 0-快速失败 2-匀速排队
|
||||
Integer controlBehavior = reqVo.getControlBehavior();
|
||||
if (controlBehavior == null) {
|
||||
return Result.ofFail(-1, "controlBehavior can't be null");
|
||||
}
|
||||
if (!Arrays.asList(CONTROL_BEHAVIOR_DEFAULT, CONTROL_BEHAVIOR_RATE_LIMITER).contains(controlBehavior)) {
|
||||
return Result.ofFail(-1, "invalid controlBehavior: " + controlBehavior);
|
||||
}
|
||||
entity.setControlBehavior(controlBehavior);
|
||||
|
||||
if (CONTROL_BEHAVIOR_DEFAULT == controlBehavior) {
|
||||
// 0-快速失败, 则Burst size必填
|
||||
Integer burst = reqVo.getBurst();
|
||||
if (burst == null) {
|
||||
return Result.ofFail(-1, "burst can't be null");
|
||||
}
|
||||
if (burst < 0) {
|
||||
return Result.ofFail(-1, "invalid burst: " + burst);
|
||||
}
|
||||
entity.setBurst(burst);
|
||||
} else if (CONTROL_BEHAVIOR_RATE_LIMITER == controlBehavior) {
|
||||
// 2-匀速排队, 则超时时间必填
|
||||
Integer maxQueueingTimeoutMs = reqVo.getMaxQueueingTimeoutMs();
|
||||
if (maxQueueingTimeoutMs == null) {
|
||||
return Result.ofFail(-1, "maxQueueingTimeoutMs can't be null");
|
||||
}
|
||||
if (maxQueueingTimeoutMs < 0) {
|
||||
return Result.ofFail(-1, "invalid maxQueueingTimeoutMs: " + maxQueueingTimeoutMs);
|
||||
}
|
||||
entity.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs);
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
entity.setGmtModified(date);
|
||||
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("update gateway flow rule error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
|
||||
if (!publishRules(app, entity.getIp(), entity.getPort())) {
|
||||
logger.warn("publish gateway flow rules fail after update");
|
||||
}
|
||||
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/delete.json")
|
||||
@AuthAction(AuthService.PrivilegeType.DELETE_RULE)
|
||||
public Result<Long> deleteFlowRule(Long id) {
|
||||
|
||||
if (id == null) {
|
||||
return Result.ofFail(-1, "id can't be null");
|
||||
}
|
||||
|
||||
GatewayFlowRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
try {
|
||||
repository.delete(id);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("delete gateway flow rule error:", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
|
||||
if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
|
||||
logger.warn("publish gateway flow rules fail after delete");
|
||||
}
|
||||
|
||||
return Result.ofSuccess(id);
|
||||
}
|
||||
|
||||
private boolean publishRules(String app, String ip, Integer port) {
|
||||
List<GatewayFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.modifyGatewayFlowRules(app, ip, port, rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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.controller.v2;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
|
||||
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
|
||||
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.Result;
|
||||
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Flow rule controller (v2).
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/v2/flow")
|
||||
public class FlowControllerV2 {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);
|
||||
|
||||
@Autowired
|
||||
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("flowRuleNacosProvider")
|
||||
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
|
||||
@Autowired
|
||||
@Qualifier("flowRuleNacosPublisher")
|
||||
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
|
||||
|
||||
@GetMapping("/rules")
|
||||
@AuthAction(PrivilegeType.READ_RULE)
|
||||
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app) {
|
||||
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
try {
|
||||
List<FlowRuleEntity> rules = ruleProvider.getRules(app);
|
||||
if (rules != null && !rules.isEmpty()) {
|
||||
for (FlowRuleEntity entity : rules) {
|
||||
entity.setApp(app);
|
||||
if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
|
||||
entity.setId(entity.getClusterConfig().getFlowId());
|
||||
}
|
||||
}
|
||||
}
|
||||
rules = repository.saveAll(rules);
|
||||
return Result.ofSuccess(rules);
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Error when querying flow rules", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "invalid body");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getApp())) {
|
||||
return Result.ofFail(-1, "app can't be null or empty");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getLimitApp())) {
|
||||
return Result.ofFail(-1, "limitApp can't be null or empty");
|
||||
}
|
||||
if (StringUtil.isBlank(entity.getResource())) {
|
||||
return Result.ofFail(-1, "resource can't be null or empty");
|
||||
}
|
||||
if (entity.getGrade() == null) {
|
||||
return Result.ofFail(-1, "grade can't be null");
|
||||
}
|
||||
if (entity.getGrade() != 0 && entity.getGrade() != 1) {
|
||||
return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");
|
||||
}
|
||||
if (entity.getCount() == null || entity.getCount() < 0) {
|
||||
return Result.ofFail(-1, "count should be at lease zero");
|
||||
}
|
||||
if (entity.getStrategy() == null) {
|
||||
return Result.ofFail(-1, "strategy can't be null");
|
||||
}
|
||||
if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {
|
||||
return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");
|
||||
}
|
||||
if (entity.getControlBehavior() == null) {
|
||||
return Result.ofFail(-1, "controlBehavior can't be null");
|
||||
}
|
||||
int controlBehavior = entity.getControlBehavior();
|
||||
if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {
|
||||
return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");
|
||||
}
|
||||
if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {
|
||||
return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");
|
||||
}
|
||||
if (entity.isClusterMode() && entity.getClusterConfig() == null) {
|
||||
return Result.ofFail(-1, "cluster config should be valid");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/rule")
|
||||
@AuthAction(value = PrivilegeType.WRITE_RULE)
|
||||
public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) {
|
||||
|
||||
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
entity.setId(null);
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
entity.setLimitApp(entity.getLimitApp().trim());
|
||||
entity.setResource(entity.getResource().trim());
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
publishRules(entity.getApp());
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Failed to add flow rule", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@PutMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.WRITE_RULE)
|
||||
|
||||
public Result<FlowRuleEntity> apiUpdateFlowRule(@PathVariable("id") Long id,
|
||||
@RequestBody FlowRuleEntity entity) {
|
||||
if (id == null || id <= 0) {
|
||||
return Result.ofFail(-1, "Invalid id");
|
||||
}
|
||||
FlowRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofFail(-1, "id " + id + " does not exist");
|
||||
}
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "invalid body");
|
||||
}
|
||||
|
||||
entity.setApp(oldEntity.getApp());
|
||||
entity.setIp(oldEntity.getIp());
|
||||
entity.setPort(oldEntity.getPort());
|
||||
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
|
||||
if (checkResult != null) {
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
entity.setId(id);
|
||||
Date date = new Date();
|
||||
entity.setGmtCreate(oldEntity.getGmtCreate());
|
||||
entity.setGmtModified(date);
|
||||
try {
|
||||
entity = repository.save(entity);
|
||||
if (entity == null) {
|
||||
return Result.ofFail(-1, "save entity fail");
|
||||
}
|
||||
publishRules(oldEntity.getApp());
|
||||
} catch (Throwable throwable) {
|
||||
logger.error("Failed to update flow rule", throwable);
|
||||
return Result.ofThrowable(-1, throwable);
|
||||
}
|
||||
return Result.ofSuccess(entity);
|
||||
}
|
||||
|
||||
@DeleteMapping("/rule/{id}")
|
||||
@AuthAction(PrivilegeType.DELETE_RULE)
|
||||
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
|
||||
if (id == null || id <= 0) {
|
||||
return Result.ofFail(-1, "Invalid id");
|
||||
}
|
||||
FlowRuleEntity oldEntity = repository.findById(id);
|
||||
if (oldEntity == null) {
|
||||
return Result.ofSuccess(null);
|
||||
}
|
||||
|
||||
try {
|
||||
repository.delete(id);
|
||||
publishRules(oldEntity.getApp());
|
||||
} catch (Exception e) {
|
||||
return Result.ofFail(-1, e.getMessage());
|
||||
}
|
||||
return Result.ofSuccess(id);
|
||||
}
|
||||
|
||||
private void publishRules(/*@NonNull*/ String app) throws Exception {
|
||||
List<FlowRuleEntity> rules = repository.findAllByApp(app);
|
||||
rulePublisher.publish(app, rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.datasource.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppInfo;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class ApplicationEntity {
|
||||
|
||||
private Long id;
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
private String app;
|
||||
private Integer appType;
|
||||
private String activeConsole;
|
||||
private Date lastFetch;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Integer getAppType() {
|
||||
return appType;
|
||||
}
|
||||
|
||||
public void setAppType(Integer appType) {
|
||||
this.appType = appType;
|
||||
}
|
||||
|
||||
public String getActiveConsole() {
|
||||
return activeConsole;
|
||||
}
|
||||
|
||||
public Date getLastFetch() {
|
||||
return lastFetch;
|
||||
}
|
||||
|
||||
public void setLastFetch(Date lastFetch) {
|
||||
this.lastFetch = lastFetch;
|
||||
}
|
||||
|
||||
public void setActiveConsole(String activeConsole) {
|
||||
this.activeConsole = activeConsole;
|
||||
}
|
||||
|
||||
public AppInfo toAppInfo() {
|
||||
return new AppInfo(app, appType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApplicationEntity{" +
|
||||
"id=" + id +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModified=" + gmtModified +
|
||||
", app='" + app + '\'' +
|
||||
", activeConsole='" + activeConsole + '\'' +
|
||||
", lastFetch=" + lastFetch +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.datasource.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class MachineEntity {
|
||||
private Long id;
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
private String app;
|
||||
private String ip;
|
||||
private String hostname;
|
||||
private Date timestamp;
|
||||
private Integer port;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Date timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public MachineInfo toMachineInfo() {
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
|
||||
machineInfo.setApp(app);
|
||||
machineInfo.setHostname(hostname);
|
||||
machineInfo.setIp(ip);
|
||||
machineInfo.setPort(port);
|
||||
machineInfo.setLastHeartbeat(timestamp.getTime());
|
||||
machineInfo.setHeartbeatVersion(timestamp.getTime());
|
||||
|
||||
return machineInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MachineEntity{" +
|
||||
"id=" + id +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModified=" + gmtModified +
|
||||
", app='" + app + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", hostname='" + hostname + '\'' +
|
||||
", timestamp=" + timestamp +
|
||||
", port=" + port +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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.datasource.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class MetricEntity {
|
||||
private Long id;
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
private String app;
|
||||
/**
|
||||
* 监控信息的时间戳
|
||||
*/
|
||||
private Date timestamp;
|
||||
private String resource;
|
||||
private Long passQps;
|
||||
private Long successQps;
|
||||
private Long blockQps;
|
||||
private Long exceptionQps;
|
||||
|
||||
/**
|
||||
* summary rt of all success exit qps.
|
||||
*/
|
||||
private double rt;
|
||||
|
||||
/**
|
||||
* 本次聚合的总条数
|
||||
*/
|
||||
private int count;
|
||||
|
||||
private int resourceCode;
|
||||
|
||||
public static MetricEntity copyOf(MetricEntity oldEntity) {
|
||||
MetricEntity entity = new MetricEntity();
|
||||
entity.setId(oldEntity.getId());
|
||||
entity.setGmtCreate(oldEntity.getGmtCreate());
|
||||
entity.setGmtModified(oldEntity.getGmtModified());
|
||||
entity.setApp(oldEntity.getApp());
|
||||
entity.setTimestamp(oldEntity.getTimestamp());
|
||||
entity.setResource(oldEntity.getResource());
|
||||
entity.setPassQps(oldEntity.getPassQps());
|
||||
entity.setBlockQps(oldEntity.getBlockQps());
|
||||
entity.setSuccessQps(oldEntity.getSuccessQps());
|
||||
entity.setExceptionQps(oldEntity.getExceptionQps());
|
||||
entity.setRt(oldEntity.getRt());
|
||||
entity.setCount(oldEntity.getCount());
|
||||
return entity;
|
||||
}
|
||||
|
||||
public synchronized void addPassQps(Long passQps) {
|
||||
this.passQps += passQps;
|
||||
}
|
||||
|
||||
public synchronized void addBlockQps(Long blockQps) {
|
||||
this.blockQps += blockQps;
|
||||
}
|
||||
|
||||
public synchronized void addExceptionQps(Long exceptionQps) {
|
||||
this.exceptionQps += exceptionQps;
|
||||
}
|
||||
|
||||
public synchronized void addCount(int count) {
|
||||
this.count += count;
|
||||
}
|
||||
|
||||
public synchronized void addRtAndSuccessQps(double avgRt, Long successQps) {
|
||||
this.rt += avgRt * successQps;
|
||||
this.successQps += successQps;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #rt} = {@code avgRt * successQps}
|
||||
*
|
||||
* @param avgRt average rt of {@code successQps}
|
||||
* @param successQps
|
||||
*/
|
||||
public synchronized void setRtAndSuccessQps(double avgRt, Long successQps) {
|
||||
this.rt = avgRt * successQps;
|
||||
this.successQps = successQps;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Date timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
this.resourceCode = resource.hashCode();
|
||||
}
|
||||
|
||||
public Long getPassQps() {
|
||||
return passQps;
|
||||
}
|
||||
|
||||
public void setPassQps(Long passQps) {
|
||||
this.passQps = passQps;
|
||||
}
|
||||
|
||||
public Long getBlockQps() {
|
||||
return blockQps;
|
||||
}
|
||||
|
||||
public void setBlockQps(Long blockQps) {
|
||||
this.blockQps = blockQps;
|
||||
}
|
||||
|
||||
public Long getExceptionQps() {
|
||||
return exceptionQps;
|
||||
}
|
||||
|
||||
public void setExceptionQps(Long exceptionQps) {
|
||||
this.exceptionQps = exceptionQps;
|
||||
}
|
||||
|
||||
public double getRt() {
|
||||
return rt;
|
||||
}
|
||||
|
||||
public void setRt(double rt) {
|
||||
this.rt = rt;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int getResourceCode() {
|
||||
return resourceCode;
|
||||
}
|
||||
|
||||
public Long getSuccessQps() {
|
||||
return successQps;
|
||||
}
|
||||
|
||||
public void setSuccessQps(Long successQps) {
|
||||
this.successQps = successQps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MetricEntity{" +
|
||||
"id=" + id +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModified=" + gmtModified +
|
||||
", app='" + app + '\'' +
|
||||
", timestamp=" + timestamp +
|
||||
", resource='" + resource + '\'' +
|
||||
", passQps=" + passQps +
|
||||
", blockQps=" + blockQps +
|
||||
", successQps=" + successQps +
|
||||
", exceptionQps=" + exceptionQps +
|
||||
", rt=" + rt +
|
||||
", count=" + count +
|
||||
", resourceCode=" + resourceCode +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.datasource.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class MetricPositionEntity {
|
||||
private long id;
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
private String app;
|
||||
private String ip;
|
||||
/**
|
||||
* Sentinel在该应用上使用的端口
|
||||
*/
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* 机器名,冗余字段
|
||||
*/
|
||||
private String hostname;
|
||||
|
||||
/**
|
||||
* 上一次拉取的最晚时间戳
|
||||
*/
|
||||
private Date lastFetch;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
public Date getLastFetch() {
|
||||
return lastFetch;
|
||||
}
|
||||
|
||||
public void setLastFetch(Date lastFetch) {
|
||||
this.lastFetch = lastFetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MetricPositionEntity{" +
|
||||
"id=" + id +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModified=" + gmtModified +
|
||||
", app='" + app + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", hostname='" + hostname + '\'' +
|
||||
", lastFetch=" + lastFetch +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.datasource.entity;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public class SentinelVersion {
|
||||
private int majorVersion;
|
||||
private int minorVersion;
|
||||
private int fixVersion;
|
||||
private String postfix;
|
||||
|
||||
public SentinelVersion() {
|
||||
this(0, 0, 0);
|
||||
}
|
||||
|
||||
public SentinelVersion(int major, int minor, int fix) {
|
||||
this(major, minor, fix, null);
|
||||
}
|
||||
|
||||
public SentinelVersion(int major, int minor, int fix, String postfix) {
|
||||
this.majorVersion = major;
|
||||
this.minorVersion = minor;
|
||||
this.fixVersion = fix;
|
||||
this.postfix = postfix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 000, 000, 000
|
||||
*/
|
||||
public int getFullVersion() {
|
||||
return majorVersion * 1000000 + minorVersion * 1000 + fixVersion;
|
||||
}
|
||||
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
public SentinelVersion setMajorVersion(int majorVersion) {
|
||||
this.majorVersion = majorVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMinorVersion() {
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
public SentinelVersion setMinorVersion(int minorVersion) {
|
||||
this.minorVersion = minorVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFixVersion() {
|
||||
return fixVersion;
|
||||
}
|
||||
|
||||
public SentinelVersion setFixVersion(int fixVersion) {
|
||||
this.fixVersion = fixVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPostfix() {
|
||||
return postfix;
|
||||
}
|
||||
|
||||
public SentinelVersion setPostfix(String postfix) {
|
||||
this.postfix = postfix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean greaterThan(SentinelVersion version) {
|
||||
if (version == null) {
|
||||
return true;
|
||||
}
|
||||
return getFullVersion() > version.getFullVersion();
|
||||
}
|
||||
|
||||
public boolean greaterOrEqual(SentinelVersion version) {
|
||||
if (version == null) {
|
||||
return true;
|
||||
}
|
||||
return getFullVersion() >= version.getFullVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (o == null || getClass() != o.getClass()) { return false; }
|
||||
|
||||
SentinelVersion that = (SentinelVersion)o;
|
||||
|
||||
if (getFullVersion() != that.getFullVersion()) { return false; }
|
||||
return postfix != null ? postfix.equals(that.postfix) : that.postfix == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = majorVersion;
|
||||
result = 31 * result + minorVersion;
|
||||
result = 31 * result + fixVersion;
|
||||
result = 31 * result + (postfix != null ? postfix.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SentinelVersion{" +
|
||||
"majorVersion=" + majorVersion +
|
||||
", minorVersion=" + minorVersion +
|
||||
", fixVersion=" + fixVersion +
|
||||
", postfix='" + postfix + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.datasource.entity.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity;
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Entity for {@link ApiDefinition}.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class ApiDefinitionEntity implements RuleEntity {
|
||||
|
||||
private Long id;
|
||||
private String app;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
|
||||
private String apiName;
|
||||
private Set<ApiPredicateItemEntity> predicateItems;
|
||||
|
||||
public static ApiDefinitionEntity fromApiDefinition(String app, String ip, Integer port, ApiDefinition apiDefinition) {
|
||||
ApiDefinitionEntity entity = new ApiDefinitionEntity();
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
entity.setApiName(apiDefinition.getApiName());
|
||||
|
||||
Set<ApiPredicateItemEntity> predicateItems = new LinkedHashSet<>();
|
||||
entity.setPredicateItems(predicateItems);
|
||||
|
||||
Set<ApiPredicateItem> apiPredicateItems = apiDefinition.getPredicateItems();
|
||||
if (apiPredicateItems != null) {
|
||||
for (ApiPredicateItem apiPredicateItem : apiPredicateItems) {
|
||||
ApiPredicateItemEntity itemEntity = new ApiPredicateItemEntity();
|
||||
predicateItems.add(itemEntity);
|
||||
ApiPathPredicateItem pathPredicateItem = (ApiPathPredicateItem) apiPredicateItem;
|
||||
itemEntity.setPattern(pathPredicateItem.getPattern());
|
||||
itemEntity.setMatchStrategy(pathPredicateItem.getMatchStrategy());
|
||||
}
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public ApiDefinition toApiDefinition() {
|
||||
ApiDefinition apiDefinition = new ApiDefinition();
|
||||
apiDefinition.setApiName(apiName);
|
||||
|
||||
Set<ApiPredicateItem> apiPredicateItems = new LinkedHashSet<>();
|
||||
apiDefinition.setPredicateItems(apiPredicateItems);
|
||||
|
||||
if (predicateItems != null) {
|
||||
for (ApiPredicateItemEntity predicateItem : predicateItems) {
|
||||
ApiPathPredicateItem apiPredicateItem = new ApiPathPredicateItem();
|
||||
apiPredicateItems.add(apiPredicateItem);
|
||||
apiPredicateItem.setMatchStrategy(predicateItem.getMatchStrategy());
|
||||
apiPredicateItem.setPattern(predicateItem.getPattern());
|
||||
}
|
||||
}
|
||||
|
||||
return apiDefinition;
|
||||
}
|
||||
|
||||
public ApiDefinitionEntity() {
|
||||
|
||||
}
|
||||
|
||||
public ApiDefinitionEntity(String apiName, Set<ApiPredicateItemEntity> predicateItems) {
|
||||
this.apiName = apiName;
|
||||
this.predicateItems = predicateItems;
|
||||
}
|
||||
|
||||
public String getApiName() {
|
||||
return apiName;
|
||||
}
|
||||
|
||||
public void setApiName(String apiName) {
|
||||
this.apiName = apiName;
|
||||
}
|
||||
|
||||
public Set<ApiPredicateItemEntity> getPredicateItems() {
|
||||
return predicateItems;
|
||||
}
|
||||
|
||||
public void setPredicateItems(Set<ApiPredicateItemEntity> predicateItems) {
|
||||
this.predicateItems = predicateItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rule toRule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (o == null || getClass() != o.getClass()) { return false; }
|
||||
ApiDefinitionEntity entity = (ApiDefinitionEntity) o;
|
||||
return Objects.equals(id, entity.id) &&
|
||||
Objects.equals(app, entity.app) &&
|
||||
Objects.equals(ip, entity.ip) &&
|
||||
Objects.equals(port, entity.port) &&
|
||||
Objects.equals(gmtCreate, entity.gmtCreate) &&
|
||||
Objects.equals(gmtModified, entity.gmtModified) &&
|
||||
Objects.equals(apiName, entity.apiName) &&
|
||||
Objects.equals(predicateItems, entity.predicateItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, app, ip, port, gmtCreate, gmtModified, apiName, predicateItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApiDefinitionEntity{" +
|
||||
"id=" + id +
|
||||
", app='" + app + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModified=" + gmtModified +
|
||||
", apiName='" + apiName + '\'' +
|
||||
", predicateItems=" + predicateItems +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.datasource.entity.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Entity for {@link ApiPredicateItem}.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class ApiPredicateItemEntity {
|
||||
|
||||
private String pattern;
|
||||
|
||||
private Integer matchStrategy;
|
||||
|
||||
public ApiPredicateItemEntity() {
|
||||
}
|
||||
|
||||
public ApiPredicateItemEntity(String pattern, int matchStrategy) {
|
||||
this.pattern = pattern;
|
||||
this.matchStrategy = matchStrategy;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public Integer getMatchStrategy() {
|
||||
return matchStrategy;
|
||||
}
|
||||
|
||||
public void setMatchStrategy(Integer matchStrategy) {
|
||||
this.matchStrategy = matchStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (o == null || getClass() != o.getClass()) { return false; }
|
||||
ApiPredicateItemEntity that = (ApiPredicateItemEntity) o;
|
||||
return Objects.equals(pattern, that.pattern) &&
|
||||
Objects.equals(matchStrategy, that.matchStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pattern, matchStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApiPredicateItemEntity{" +
|
||||
"pattern='" + pattern + '\'' +
|
||||
", matchStrategy=" + matchStrategy +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* 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.datasource.entity.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayParamFlowItem;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity;
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Entity for {@link GatewayFlowRule}.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class GatewayFlowRuleEntity implements RuleEntity {
|
||||
|
||||
/**间隔单位*/
|
||||
/**0-秒*/
|
||||
public static final int INTERVAL_UNIT_SECOND = 0;
|
||||
/**1-分*/
|
||||
public static final int INTERVAL_UNIT_MINUTE = 1;
|
||||
/**2-时*/
|
||||
public static final int INTERVAL_UNIT_HOUR = 2;
|
||||
/**3-天*/
|
||||
public static final int INTERVAL_UNIT_DAY = 3;
|
||||
|
||||
private Long id;
|
||||
private String app;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
|
||||
private String resource;
|
||||
private Integer resourceMode;
|
||||
|
||||
private Integer grade;
|
||||
private Double count;
|
||||
private Long interval;
|
||||
private Integer intervalUnit;
|
||||
|
||||
private Integer controlBehavior;
|
||||
private Integer burst;
|
||||
|
||||
private Integer maxQueueingTimeoutMs;
|
||||
|
||||
private GatewayParamFlowItemEntity paramItem;
|
||||
|
||||
public static Long calIntervalSec(Long interval, Integer intervalUnit) {
|
||||
switch (intervalUnit) {
|
||||
case INTERVAL_UNIT_SECOND:
|
||||
return interval;
|
||||
case INTERVAL_UNIT_MINUTE:
|
||||
return interval * 60;
|
||||
case INTERVAL_UNIT_HOUR:
|
||||
return interval * 60 * 60;
|
||||
case INTERVAL_UNIT_DAY:
|
||||
return interval * 60 * 60 * 24;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid intervalUnit: " + intervalUnit);
|
||||
}
|
||||
|
||||
public static Object[] parseIntervalSec(Long intervalSec) {
|
||||
if (intervalSec % (60 * 60 * 24) == 0) {
|
||||
return new Object[] {intervalSec / (60 * 60 * 24), INTERVAL_UNIT_DAY};
|
||||
}
|
||||
|
||||
if (intervalSec % (60 * 60 ) == 0) {
|
||||
return new Object[] {intervalSec / (60 * 60), INTERVAL_UNIT_HOUR};
|
||||
}
|
||||
|
||||
if (intervalSec % 60 == 0) {
|
||||
return new Object[] {intervalSec / 60, INTERVAL_UNIT_MINUTE};
|
||||
}
|
||||
|
||||
return new Object[] {intervalSec, INTERVAL_UNIT_SECOND};
|
||||
}
|
||||
|
||||
public GatewayFlowRule toGatewayFlowRule() {
|
||||
GatewayFlowRule rule = new GatewayFlowRule();
|
||||
rule.setResource(resource);
|
||||
rule.setResourceMode(resourceMode);
|
||||
|
||||
rule.setGrade(grade);
|
||||
rule.setCount(count);
|
||||
rule.setIntervalSec(calIntervalSec(interval, intervalUnit));
|
||||
|
||||
rule.setControlBehavior(controlBehavior);
|
||||
|
||||
if (burst != null) {
|
||||
rule.setBurst(burst);
|
||||
}
|
||||
|
||||
if (maxQueueingTimeoutMs != null) {
|
||||
rule.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs);
|
||||
}
|
||||
|
||||
if (paramItem != null) {
|
||||
GatewayParamFlowItem ruleItem = new GatewayParamFlowItem();
|
||||
rule.setParamItem(ruleItem);
|
||||
ruleItem.setParseStrategy(paramItem.getParseStrategy());
|
||||
ruleItem.setFieldName(paramItem.getFieldName());
|
||||
ruleItem.setPattern(paramItem.getPattern());
|
||||
|
||||
if (paramItem.getMatchStrategy() != null) {
|
||||
ruleItem.setMatchStrategy(paramItem.getMatchStrategy());
|
||||
}
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
public static GatewayFlowRuleEntity fromGatewayFlowRule(String app, String ip, Integer port, GatewayFlowRule rule) {
|
||||
GatewayFlowRuleEntity entity = new GatewayFlowRuleEntity();
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
|
||||
entity.setResource(rule.getResource());
|
||||
entity.setResourceMode(rule.getResourceMode());
|
||||
|
||||
entity.setGrade(rule.getGrade());
|
||||
entity.setCount(rule.getCount());
|
||||
Object[] intervalSecResult = parseIntervalSec(rule.getIntervalSec());
|
||||
entity.setInterval((Long) intervalSecResult[0]);
|
||||
entity.setIntervalUnit((Integer) intervalSecResult[1]);
|
||||
|
||||
entity.setControlBehavior(rule.getControlBehavior());
|
||||
entity.setBurst(rule.getBurst());
|
||||
entity.setMaxQueueingTimeoutMs(rule.getMaxQueueingTimeoutMs());
|
||||
|
||||
GatewayParamFlowItem paramItem = rule.getParamItem();
|
||||
if (paramItem != null) {
|
||||
GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();
|
||||
entity.setParamItem(itemEntity);
|
||||
itemEntity.setParseStrategy(paramItem.getParseStrategy());
|
||||
itemEntity.setFieldName(paramItem.getFieldName());
|
||||
itemEntity.setPattern(paramItem.getPattern());
|
||||
itemEntity.setMatchStrategy(paramItem.getMatchStrategy());
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rule toRule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
public GatewayParamFlowItemEntity getParamItem() {
|
||||
return paramItem;
|
||||
}
|
||||
|
||||
public void setParamItem(GatewayParamFlowItemEntity paramItem) {
|
||||
this.paramItem = paramItem;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Integer getResourceMode() {
|
||||
return resourceMode;
|
||||
}
|
||||
|
||||
public void setResourceMode(Integer resourceMode) {
|
||||
this.resourceMode = resourceMode;
|
||||
}
|
||||
|
||||
public Integer getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void setGrade(Integer grade) {
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
public Double getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Double count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Long getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public void setInterval(Long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public Integer getIntervalUnit() {
|
||||
return intervalUnit;
|
||||
}
|
||||
|
||||
public void setIntervalUnit(Integer intervalUnit) {
|
||||
this.intervalUnit = intervalUnit;
|
||||
}
|
||||
|
||||
public Integer getControlBehavior() {
|
||||
return controlBehavior;
|
||||
}
|
||||
|
||||
public void setControlBehavior(Integer controlBehavior) {
|
||||
this.controlBehavior = controlBehavior;
|
||||
}
|
||||
|
||||
public Integer getBurst() {
|
||||
return burst;
|
||||
}
|
||||
|
||||
public void setBurst(Integer burst) {
|
||||
this.burst = burst;
|
||||
}
|
||||
|
||||
public Integer getMaxQueueingTimeoutMs() {
|
||||
return maxQueueingTimeoutMs;
|
||||
}
|
||||
|
||||
public void setMaxQueueingTimeoutMs(Integer maxQueueingTimeoutMs) {
|
||||
this.maxQueueingTimeoutMs = maxQueueingTimeoutMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (o == null || getClass() != o.getClass()) { return false; }
|
||||
GatewayFlowRuleEntity that = (GatewayFlowRuleEntity) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(app, that.app) &&
|
||||
Objects.equals(ip, that.ip) &&
|
||||
Objects.equals(port, that.port) &&
|
||||
Objects.equals(gmtCreate, that.gmtCreate) &&
|
||||
Objects.equals(gmtModified, that.gmtModified) &&
|
||||
Objects.equals(resource, that.resource) &&
|
||||
Objects.equals(resourceMode, that.resourceMode) &&
|
||||
Objects.equals(grade, that.grade) &&
|
||||
Objects.equals(count, that.count) &&
|
||||
Objects.equals(interval, that.interval) &&
|
||||
Objects.equals(intervalUnit, that.intervalUnit) &&
|
||||
Objects.equals(controlBehavior, that.controlBehavior) &&
|
||||
Objects.equals(burst, that.burst) &&
|
||||
Objects.equals(maxQueueingTimeoutMs, that.maxQueueingTimeoutMs) &&
|
||||
Objects.equals(paramItem, that.paramItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, app, ip, port, gmtCreate, gmtModified, resource, resourceMode, grade, count, interval, intervalUnit, controlBehavior, burst, maxQueueingTimeoutMs, paramItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GatewayFlowRuleEntity{" +
|
||||
"id=" + id +
|
||||
", app='" + app + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModified=" + gmtModified +
|
||||
", resource='" + resource + '\'' +
|
||||
", resourceMode=" + resourceMode +
|
||||
", grade=" + grade +
|
||||
", count=" + count +
|
||||
", interval=" + interval +
|
||||
", intervalUnit=" + intervalUnit +
|
||||
", controlBehavior=" + controlBehavior +
|
||||
", burst=" + burst +
|
||||
", maxQueueingTimeoutMs=" + maxQueueingTimeoutMs +
|
||||
", paramItem=" + paramItem +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.datasource.entity.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayParamFlowItem;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Entity for {@link GatewayParamFlowItem}.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class GatewayParamFlowItemEntity {
|
||||
|
||||
private Integer parseStrategy;
|
||||
|
||||
private String fieldName;
|
||||
|
||||
private String pattern;
|
||||
|
||||
private Integer matchStrategy;
|
||||
|
||||
public Integer getParseStrategy() {
|
||||
return parseStrategy;
|
||||
}
|
||||
|
||||
public void setParseStrategy(Integer parseStrategy) {
|
||||
this.parseStrategy = parseStrategy;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
public void setFieldName(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public Integer getMatchStrategy() {
|
||||
return matchStrategy;
|
||||
}
|
||||
|
||||
public void setMatchStrategy(Integer matchStrategy) {
|
||||
this.matchStrategy = matchStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (o == null || getClass() != o.getClass()) { return false; }
|
||||
GatewayParamFlowItemEntity that = (GatewayParamFlowItemEntity) o;
|
||||
return Objects.equals(parseStrategy, that.parseStrategy) &&
|
||||
Objects.equals(fieldName, that.fieldName) &&
|
||||
Objects.equals(pattern, that.pattern) &&
|
||||
Objects.equals(matchStrategy, that.matchStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(parseStrategy, fieldName, pattern, matchStrategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GatewayParamFlowItemEntity{" +
|
||||
"parseStrategy=" + parseStrategy +
|
||||
", fieldName='" + fieldName + '\'' +
|
||||
", pattern='" + pattern + '\'' +
|
||||
", matchStrategy=" + matchStrategy +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public abstract class AbstractRuleEntity<T extends AbstractRule> implements RuleEntity {
|
||||
|
||||
protected Long id;
|
||||
|
||||
protected String app;
|
||||
protected String ip;
|
||||
protected Integer port;
|
||||
|
||||
protected T rule;
|
||||
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public AbstractRuleEntity<T> setApp(String app) {
|
||||
this.app = app;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public AbstractRuleEntity<T> setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public AbstractRuleEntity<T> setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public T getRule() {
|
||||
return rule;
|
||||
}
|
||||
|
||||
public AbstractRuleEntity<T> setRule(T rule) {
|
||||
this.rule = rule;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public AbstractRuleEntity<T> setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public AbstractRuleEntity<T> setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T toRule() {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public class AuthorityRuleEntity extends AbstractRuleEntity<AuthorityRule> {
|
||||
|
||||
public AuthorityRuleEntity() {
|
||||
}
|
||||
|
||||
public AuthorityRuleEntity(AuthorityRule authorityRule) {
|
||||
AssertUtil.notNull(authorityRule, "Authority rule should not be null");
|
||||
this.rule = authorityRule;
|
||||
}
|
||||
|
||||
public static AuthorityRuleEntity fromAuthorityRule(String app, String ip, Integer port, AuthorityRule rule) {
|
||||
AuthorityRuleEntity entity = new AuthorityRuleEntity(rule);
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public String getLimitApp() {
|
||||
return rule.getLimitApp();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public String getResource() {
|
||||
return rule.getResource();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public int getStrategy() {
|
||||
return rule.getStrategy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class DegradeRuleEntity implements RuleEntity {
|
||||
|
||||
private Long id;
|
||||
private String app;
|
||||
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private String resource;
|
||||
private String limitApp;
|
||||
private Double count;
|
||||
private Integer timeWindow;
|
||||
private Integer grade;
|
||||
private Integer minRequestAmount;
|
||||
private Double slowRatioThreshold;
|
||||
private Integer statIntervalMs;
|
||||
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
|
||||
public static DegradeRuleEntity fromDegradeRule(String app, String ip, Integer port, DegradeRule rule) {
|
||||
DegradeRuleEntity entity = new DegradeRuleEntity();
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
entity.setResource(rule.getResource());
|
||||
entity.setLimitApp(rule.getLimitApp());
|
||||
entity.setCount(rule.getCount());
|
||||
entity.setTimeWindow(rule.getTimeWindow());
|
||||
entity.setGrade(rule.getGrade());
|
||||
entity.setMinRequestAmount(rule.getMinRequestAmount());
|
||||
entity.setSlowRatioThreshold(rule.getSlowRatioThreshold());
|
||||
entity.setStatIntervalMs(rule.getStatIntervalMs());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String getLimitApp() {
|
||||
return limitApp;
|
||||
}
|
||||
|
||||
public void setLimitApp(String limitApp) {
|
||||
this.limitApp = limitApp;
|
||||
}
|
||||
|
||||
public Double getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Double count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Integer getTimeWindow() {
|
||||
return timeWindow;
|
||||
}
|
||||
|
||||
public void setTimeWindow(Integer timeWindow) {
|
||||
this.timeWindow = timeWindow;
|
||||
}
|
||||
|
||||
public Integer getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void setGrade(Integer grade) {
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
public Integer getMinRequestAmount() {
|
||||
return minRequestAmount;
|
||||
}
|
||||
|
||||
public DegradeRuleEntity setMinRequestAmount(Integer minRequestAmount) {
|
||||
this.minRequestAmount = minRequestAmount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Double getSlowRatioThreshold() {
|
||||
return slowRatioThreshold;
|
||||
}
|
||||
|
||||
public DegradeRuleEntity setSlowRatioThreshold(Double slowRatioThreshold) {
|
||||
this.slowRatioThreshold = slowRatioThreshold;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getStatIntervalMs() {
|
||||
return statIntervalMs;
|
||||
}
|
||||
|
||||
public DegradeRuleEntity setStatIntervalMs(Integer statIntervalMs) {
|
||||
this.statIntervalMs = statIntervalMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DegradeRule toRule() {
|
||||
DegradeRule rule = new DegradeRule();
|
||||
rule.setResource(resource);
|
||||
rule.setLimitApp(limitApp);
|
||||
rule.setCount(count);
|
||||
rule.setTimeWindow(timeWindow);
|
||||
rule.setGrade(grade);
|
||||
if (minRequestAmount != null) {
|
||||
rule.setMinRequestAmount(minRequestAmount);
|
||||
}
|
||||
if (slowRatioThreshold != null) {
|
||||
rule.setSlowRatioThreshold(slowRatioThreshold);
|
||||
}
|
||||
if (statIntervalMs != null) {
|
||||
rule.setStatIntervalMs(statIntervalMs);
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.ClusterFlowConfig;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class FlowRuleEntity implements RuleEntity {
|
||||
|
||||
private Long id;
|
||||
private String app;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
private String limitApp;
|
||||
private String resource;
|
||||
/**
|
||||
* 0为线程数;1为qps
|
||||
*/
|
||||
private Integer grade;
|
||||
private Double count;
|
||||
/**
|
||||
* 0为直接限流;1为关联限流;2为链路限流
|
||||
***/
|
||||
private Integer strategy;
|
||||
private String refResource;
|
||||
/**
|
||||
* 0. default, 1. warm up, 2. rate limiter
|
||||
*/
|
||||
private Integer controlBehavior;
|
||||
private Integer warmUpPeriodSec;
|
||||
/**
|
||||
* max queueing time in rate limiter behavior
|
||||
*/
|
||||
private Integer maxQueueingTimeMs;
|
||||
|
||||
private boolean clusterMode;
|
||||
/**
|
||||
* Flow rule config for cluster mode.
|
||||
*/
|
||||
private ClusterFlowConfig clusterConfig;
|
||||
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
|
||||
public static FlowRuleEntity fromFlowRule(String app, String ip, Integer port, FlowRule rule) {
|
||||
FlowRuleEntity entity = new FlowRuleEntity();
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
entity.setLimitApp(rule.getLimitApp());
|
||||
entity.setResource(rule.getResource());
|
||||
entity.setGrade(rule.getGrade());
|
||||
entity.setCount(rule.getCount());
|
||||
entity.setStrategy(rule.getStrategy());
|
||||
entity.setRefResource(rule.getRefResource());
|
||||
entity.setControlBehavior(rule.getControlBehavior());
|
||||
entity.setWarmUpPeriodSec(rule.getWarmUpPeriodSec());
|
||||
entity.setMaxQueueingTimeMs(rule.getMaxQueueingTimeMs());
|
||||
entity.setClusterMode(rule.isClusterMode());
|
||||
entity.setClusterConfig(rule.getClusterConfig());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLimitApp() {
|
||||
return limitApp;
|
||||
}
|
||||
|
||||
public void setLimitApp(String limitApp) {
|
||||
this.limitApp = limitApp;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Integer getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void setGrade(Integer grade) {
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
public Double getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Double count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Integer getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
public void setStrategy(Integer strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public String getRefResource() {
|
||||
return refResource;
|
||||
}
|
||||
|
||||
public void setRefResource(String refResource) {
|
||||
this.refResource = refResource;
|
||||
}
|
||||
|
||||
public Integer getControlBehavior() {
|
||||
return controlBehavior;
|
||||
}
|
||||
|
||||
public void setControlBehavior(Integer controlBehavior) {
|
||||
this.controlBehavior = controlBehavior;
|
||||
}
|
||||
|
||||
public Integer getWarmUpPeriodSec() {
|
||||
return warmUpPeriodSec;
|
||||
}
|
||||
|
||||
public void setWarmUpPeriodSec(Integer warmUpPeriodSec) {
|
||||
this.warmUpPeriodSec = warmUpPeriodSec;
|
||||
}
|
||||
|
||||
public Integer getMaxQueueingTimeMs() {
|
||||
return maxQueueingTimeMs;
|
||||
}
|
||||
|
||||
public void setMaxQueueingTimeMs(Integer maxQueueingTimeMs) {
|
||||
this.maxQueueingTimeMs = maxQueueingTimeMs;
|
||||
}
|
||||
|
||||
public boolean isClusterMode() {
|
||||
return clusterMode;
|
||||
}
|
||||
|
||||
public FlowRuleEntity setClusterMode(boolean clusterMode) {
|
||||
this.clusterMode = clusterMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterFlowConfig getClusterConfig() {
|
||||
return clusterConfig;
|
||||
}
|
||||
|
||||
public FlowRuleEntity setClusterConfig(ClusterFlowConfig clusterConfig) {
|
||||
this.clusterConfig = clusterConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowRule toRule() {
|
||||
FlowRule flowRule = new FlowRule();
|
||||
flowRule.setCount(this.count);
|
||||
flowRule.setGrade(this.grade);
|
||||
flowRule.setResource(this.resource);
|
||||
flowRule.setLimitApp(this.limitApp);
|
||||
flowRule.setRefResource(this.refResource);
|
||||
flowRule.setStrategy(this.strategy);
|
||||
if (this.controlBehavior != null) {
|
||||
flowRule.setControlBehavior(controlBehavior);
|
||||
}
|
||||
if (this.warmUpPeriodSec != null) {
|
||||
flowRule.setWarmUpPeriodSec(warmUpPeriodSec);
|
||||
}
|
||||
if (this.maxQueueingTimeMs != null) {
|
||||
flowRule.setMaxQueueingTimeMs(maxQueueingTimeMs);
|
||||
}
|
||||
flowRule.setClusterMode(clusterMode);
|
||||
flowRule.setClusterConfig(clusterConfig);
|
||||
return flowRule;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowClusterConfig;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public class ParamFlowRuleEntity extends AbstractRuleEntity<ParamFlowRule> {
|
||||
|
||||
public ParamFlowRuleEntity() {
|
||||
}
|
||||
|
||||
public ParamFlowRuleEntity(ParamFlowRule rule) {
|
||||
AssertUtil.notNull(rule, "Authority rule should not be null");
|
||||
this.rule = rule;
|
||||
}
|
||||
|
||||
public static ParamFlowRuleEntity fromParamFlowRule(String app, String ip, Integer port, ParamFlowRule rule) {
|
||||
ParamFlowRuleEntity entity = new ParamFlowRuleEntity(rule);
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public String getLimitApp() {
|
||||
return rule.getLimitApp();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public String getResource() {
|
||||
return rule.getResource();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public int getGrade() {
|
||||
return rule.getGrade();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public Integer getParamIdx() {
|
||||
return rule.getParamIdx();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public double getCount() {
|
||||
return rule.getCount();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public List<ParamFlowItem> getParamFlowItemList() {
|
||||
return rule.getParamFlowItemList();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public int getControlBehavior() {
|
||||
return rule.getControlBehavior();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public int getMaxQueueingTimeMs() {
|
||||
return rule.getMaxQueueingTimeMs();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public int getBurstCount() {
|
||||
return rule.getBurstCount();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public long getDurationInSec() {
|
||||
return rule.getDurationInSec();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public boolean isClusterMode() {
|
||||
return rule.isClusterMode();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public ParamFlowClusterConfig getClusterConfig() {
|
||||
return rule.getClusterConfig();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.Rule;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public interface RuleEntity {
|
||||
|
||||
Long getId();
|
||||
|
||||
void setId(Long id);
|
||||
|
||||
String getApp();
|
||||
|
||||
String getIp();
|
||||
|
||||
Integer getPort();
|
||||
|
||||
Date getGmtCreate();
|
||||
|
||||
Rule toRule();
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.datasource.entity.rule;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemRule;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class SystemRuleEntity implements RuleEntity {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String app;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
private Double highestSystemLoad;
|
||||
private Long avgRt;
|
||||
private Long maxThread;
|
||||
private Double qps;
|
||||
private Double highestCpuUsage;
|
||||
|
||||
private Date gmtCreate;
|
||||
private Date gmtModified;
|
||||
|
||||
public static SystemRuleEntity fromSystemRule(String app, String ip, Integer port, SystemRule rule) {
|
||||
SystemRuleEntity entity = new SystemRuleEntity();
|
||||
entity.setApp(app);
|
||||
entity.setIp(ip);
|
||||
entity.setPort(port);
|
||||
entity.setHighestSystemLoad(rule.getHighestSystemLoad());
|
||||
entity.setHighestCpuUsage(rule.getHighestCpuUsage());
|
||||
entity.setAvgRt(rule.getAvgRt());
|
||||
entity.setMaxThread(rule.getMaxThread());
|
||||
entity.setQps(rule.getQps());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Double getHighestSystemLoad() {
|
||||
return highestSystemLoad;
|
||||
}
|
||||
|
||||
public void setHighestSystemLoad(Double highestSystemLoad) {
|
||||
this.highestSystemLoad = highestSystemLoad;
|
||||
}
|
||||
|
||||
public Long getAvgRt() {
|
||||
return avgRt;
|
||||
}
|
||||
|
||||
public void setAvgRt(Long avgRt) {
|
||||
this.avgRt = avgRt;
|
||||
}
|
||||
|
||||
public Long getMaxThread() {
|
||||
return maxThread;
|
||||
}
|
||||
|
||||
public void setMaxThread(Long maxThread) {
|
||||
this.maxThread = maxThread;
|
||||
}
|
||||
|
||||
public Double getQps() {
|
||||
return qps;
|
||||
}
|
||||
|
||||
public void setQps(Double qps) {
|
||||
this.qps = qps;
|
||||
}
|
||||
|
||||
public Double getHighestCpuUsage() {
|
||||
return highestCpuUsage;
|
||||
}
|
||||
|
||||
public void setHighestCpuUsage(Double highestCpuUsage) {
|
||||
this.highestCpuUsage = highestCpuUsage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModified() {
|
||||
return gmtModified;
|
||||
}
|
||||
|
||||
public void setGmtModified(Date gmtModified) {
|
||||
this.gmtModified = gmtModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemRule toRule() {
|
||||
SystemRule rule = new SystemRule();
|
||||
rule.setHighestSystemLoad(highestSystemLoad);
|
||||
rule.setAvgRt(avgRt);
|
||||
rule.setMaxThread(maxThread);
|
||||
rule.setQps(qps);
|
||||
rule.setHighestCpuUsage(highestCpuUsage);
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.discovery;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
|
||||
|
||||
public class AppInfo {
|
||||
|
||||
private String app = "";
|
||||
|
||||
private Integer appType = 0;
|
||||
|
||||
private Set<MachineInfo> machines = ConcurrentHashMap.newKeySet();
|
||||
|
||||
public AppInfo() {}
|
||||
|
||||
public AppInfo(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public AppInfo(String app, Integer appType) {
|
||||
this.app = app;
|
||||
this.appType = appType;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Integer getAppType() {
|
||||
return appType;
|
||||
}
|
||||
|
||||
public void setAppType(Integer appType) {
|
||||
this.appType = appType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current machines.
|
||||
*
|
||||
* @return a new copy of the current machines.
|
||||
*/
|
||||
public Set<MachineInfo> getMachines() {
|
||||
return new HashSet<>(machines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AppInfo{" + "app='" + app + ", machines=" + machines + '}';
|
||||
}
|
||||
|
||||
public boolean addMachine(MachineInfo machineInfo) {
|
||||
machines.remove(machineInfo);
|
||||
return machines.add(machineInfo);
|
||||
}
|
||||
|
||||
public synchronized boolean removeMachine(String ip, int port) {
|
||||
Iterator<MachineInfo> it = machines.iterator();
|
||||
while (it.hasNext()) {
|
||||
MachineInfo machine = it.next();
|
||||
if (machine.getIp().equals(ip) && machine.getPort() == port) {
|
||||
it.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Optional<MachineInfo> getMachine(String ip, int port) {
|
||||
return machines.stream()
|
||||
.filter(e -> e.getIp().equals(ip) && e.getPort().equals(port))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Optional<MachineInfo> getMachine(String ip) {
|
||||
return machines.stream()
|
||||
.filter(e -> e.getIp().equals(ip))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private boolean heartbeatJudge(final int threshold) {
|
||||
if (machines.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (threshold > 0) {
|
||||
long healthyCount = machines.stream()
|
||||
.filter(MachineInfo::isHealthy)
|
||||
.count();
|
||||
if (healthyCount == 0) {
|
||||
// No healthy machines.
|
||||
return machines.stream()
|
||||
.max(Comparator.comparingLong(MachineInfo::getLastHeartbeat))
|
||||
.map(e -> System.currentTimeMillis() - e.getLastHeartbeat() < threshold)
|
||||
.orElse(false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether current application has no healthy machines and should not be displayed.
|
||||
*
|
||||
* @return true if the application should be displayed in the sidebar, otherwise false
|
||||
*/
|
||||
public boolean isShown() {
|
||||
return heartbeatJudge(DashboardConfig.getHideAppNoMachineMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether current application has no healthy machines and should be removed.
|
||||
*
|
||||
* @return true if the application is dead and should be removed, otherwise false
|
||||
*/
|
||||
public boolean isDead() {
|
||||
return !heartbeatJudge(DashboardConfig.getRemoveAppNoMachineMillis());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.discovery;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AppManagement implements MachineDiscovery {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
private MachineDiscovery machineDiscovery;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
machineDiscovery = context.getBean(SimpleMachineDiscovery.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AppInfo> getBriefApps() {
|
||||
return machineDiscovery.getBriefApps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long addMachine(MachineInfo machineInfo) {
|
||||
return machineDiscovery.addMachine(machineInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeMachine(String app, String ip, int port) {
|
||||
return machineDiscovery.removeMachine(app, ip, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAppNames() {
|
||||
return machineDiscovery.getAppNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppInfo getDetailApp(String app) {
|
||||
return machineDiscovery.getDetailApp(app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApp(String app) {
|
||||
machineDiscovery.removeApp(app);
|
||||
}
|
||||
|
||||
public boolean isValidMachineOfApp(String app, String ip) {
|
||||
if (StringUtil.isEmpty(app)) {
|
||||
return false;
|
||||
}
|
||||
return Optional.ofNullable(getDetailApp(app))
|
||||
.flatMap(a -> a.getMachine(ip))
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.discovery;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface MachineDiscovery {
|
||||
|
||||
String UNKNOWN_APP_NAME = "CLUSTER_NOT_STARTED";
|
||||
|
||||
List<String> getAppNames();
|
||||
|
||||
Set<AppInfo> getBriefApps();
|
||||
|
||||
AppInfo getDetailApp(String app);
|
||||
|
||||
/**
|
||||
* Remove the given app from the application registry.
|
||||
*
|
||||
* @param app application name
|
||||
* @since 1.5.0
|
||||
*/
|
||||
void removeApp(String app);
|
||||
|
||||
long addMachine(MachineInfo machineInfo);
|
||||
|
||||
/**
|
||||
* Remove the given machine instance from the application registry.
|
||||
*
|
||||
* @param app the application name of the machine
|
||||
* @param ip machine IP
|
||||
* @param port machine port
|
||||
* @return true if removed, otherwise false
|
||||
* @since 1.5.0
|
||||
*/
|
||||
boolean removeMachine(String app, String ip, int port);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.discovery;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
public class MachineInfo implements Comparable<MachineInfo> {
|
||||
|
||||
private String app = "";
|
||||
private Integer appType = 0;
|
||||
private String hostname = "";
|
||||
private String ip = "";
|
||||
private Integer port = -1;
|
||||
private long lastHeartbeat;
|
||||
private long heartbeatVersion;
|
||||
|
||||
/**
|
||||
* Indicates the version of Sentinel client (since 0.2.0).
|
||||
*/
|
||||
private String version;
|
||||
|
||||
public static MachineInfo of(String app, String ip, Integer port) {
|
||||
MachineInfo machineInfo = new MachineInfo();
|
||||
machineInfo.setApp(app);
|
||||
machineInfo.setIp(ip);
|
||||
machineInfo.setPort(port);
|
||||
return machineInfo;
|
||||
}
|
||||
|
||||
public String toHostPort() {
|
||||
return ip + ":" + port;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Integer getAppType() {
|
||||
return appType;
|
||||
}
|
||||
|
||||
public void setAppType(Integer appType) {
|
||||
this.appType = appType;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public long getHeartbeatVersion() {
|
||||
return heartbeatVersion;
|
||||
}
|
||||
|
||||
public void setHeartbeatVersion(long heartbeatVersion) {
|
||||
this.heartbeatVersion = heartbeatVersion;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public MachineInfo setVersion(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isHealthy() {
|
||||
long delta = System.currentTimeMillis() - lastHeartbeat;
|
||||
return delta < DashboardConfig.getUnhealthyMachineMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* whether dead should be removed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isDead() {
|
||||
if (DashboardConfig.getAutoRemoveMachineMillis() > 0) {
|
||||
long delta = System.currentTimeMillis() - lastHeartbeat;
|
||||
return delta > DashboardConfig.getAutoRemoveMachineMillis();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long getLastHeartbeat() {
|
||||
return lastHeartbeat;
|
||||
}
|
||||
|
||||
public void setLastHeartbeat(long lastHeartbeat) {
|
||||
this.lastHeartbeat = lastHeartbeat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MachineInfo o) {
|
||||
if (this == o) {
|
||||
return 0;
|
||||
}
|
||||
if (!port.equals(o.getPort())) {
|
||||
return port.compareTo(o.getPort());
|
||||
}
|
||||
if (!StringUtil.equals(app, o.getApp())) {
|
||||
return app.compareToIgnoreCase(o.getApp());
|
||||
}
|
||||
return ip.compareToIgnoreCase(o.getIp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("MachineInfo {")
|
||||
.append("app='").append(app).append('\'')
|
||||
.append(",appType='").append(appType).append('\'')
|
||||
.append(", hostname='").append(hostname).append('\'')
|
||||
.append(", ip='").append(ip).append('\'')
|
||||
.append(", port=").append(port)
|
||||
.append(", heartbeatVersion=").append(heartbeatVersion)
|
||||
.append(", lastHeartbeat=").append(lastHeartbeat)
|
||||
.append(", version='").append(version).append('\'')
|
||||
.append(", healthy=").append(isHealthy())
|
||||
.append('}').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (!(o instanceof MachineInfo)) { return false; }
|
||||
MachineInfo that = (MachineInfo)o;
|
||||
return Objects.equals(app, that.app) &&
|
||||
Objects.equals(ip, that.ip) &&
|
||||
Objects.equals(port, that.port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(app, ip, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Information for log
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toLogString() {
|
||||
return app + "|" + ip + "|" + port + "|" + version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.discovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
@Component
|
||||
public class SimpleMachineDiscovery implements MachineDiscovery {
|
||||
|
||||
private final ConcurrentMap<String, AppInfo> apps = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public long addMachine(MachineInfo machineInfo) {
|
||||
AssertUtil.notNull(machineInfo, "machineInfo cannot be null");
|
||||
AppInfo appInfo = apps.computeIfAbsent(machineInfo.getApp(), o -> new AppInfo(machineInfo.getApp(), machineInfo.getAppType()));
|
||||
appInfo.addMachine(machineInfo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeMachine(String app, String ip, int port) {
|
||||
AssertUtil.assertNotBlank(app, "app name cannot be blank");
|
||||
AppInfo appInfo = apps.get(app);
|
||||
if (appInfo != null) {
|
||||
return appInfo.removeMachine(ip, port);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAppNames() {
|
||||
return new ArrayList<>(apps.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppInfo getDetailApp(String app) {
|
||||
AssertUtil.assertNotBlank(app, "app name cannot be blank");
|
||||
return apps.get(app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AppInfo> getBriefApps() {
|
||||
return new HashSet<>(apps.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeApp(String app) {
|
||||
AssertUtil.assertNotBlank(app, "app name cannot be blank");
|
||||
apps.remove(app);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.csp.sentinel.command.vo.NodeVo;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class ResourceTreeNode {
|
||||
private String id;
|
||||
private String parentId;
|
||||
private String resource;
|
||||
|
||||
private Integer threadNum;
|
||||
private Long passQps;
|
||||
private Long blockQps;
|
||||
private Long totalQps;
|
||||
private Long averageRt;
|
||||
private Long successQps;
|
||||
private Long exceptionQps;
|
||||
private Long oneMinutePass;
|
||||
private Long oneMinuteBlock;
|
||||
private Long oneMinuteException;
|
||||
private Long oneMinuteTotal;
|
||||
|
||||
private boolean visible = true;
|
||||
|
||||
private List<ResourceTreeNode> children = new ArrayList<>();
|
||||
|
||||
public static ResourceTreeNode fromNodeVoList(List<NodeVo> nodeVos) {
|
||||
if (nodeVos == null || nodeVos.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
ResourceTreeNode root = null;
|
||||
Map<String, ResourceTreeNode> map = new HashMap<>();
|
||||
for (NodeVo vo : nodeVos) {
|
||||
ResourceTreeNode node = fromNodeVo(vo);
|
||||
map.put(node.id, node);
|
||||
// real root
|
||||
if (node.parentId == null || node.parentId.isEmpty()) {
|
||||
root = node;
|
||||
} else if (map.containsKey(node.parentId)) {
|
||||
map.get(node.parentId).children.add(node);
|
||||
} else {
|
||||
// impossible
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
public static ResourceTreeNode fromNodeVo(NodeVo vo) {
|
||||
ResourceTreeNode node = new ResourceTreeNode();
|
||||
node.id = vo.getId();
|
||||
node.parentId = vo.getParentId();
|
||||
node.resource = vo.getResource();
|
||||
node.threadNum = vo.getThreadNum();
|
||||
node.passQps = vo.getPassQps();
|
||||
node.blockQps = vo.getBlockQps();
|
||||
node.totalQps = vo.getTotalQps();
|
||||
node.averageRt = vo.getAverageRt();
|
||||
node.successQps = vo.getSuccessQps();
|
||||
node.exceptionQps = vo.getExceptionQps();
|
||||
node.oneMinutePass = vo.getOneMinutePass();
|
||||
node.oneMinuteBlock = vo.getOneMinuteBlock();
|
||||
node.oneMinuteException = vo.getOneMinuteException();
|
||||
node.oneMinuteTotal = vo.getOneMinuteTotal();
|
||||
return node;
|
||||
}
|
||||
|
||||
public void searchIgnoreCase(String searchKey) {
|
||||
search(this, searchKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* This node is visible only when searchKey matches this.resource or at least
|
||||
* one of this's children is visible
|
||||
*/
|
||||
private boolean search(ResourceTreeNode node, String searchKey) {
|
||||
// empty matches all
|
||||
if (searchKey == null || searchKey.isEmpty() ||
|
||||
node.resource.toLowerCase().contains(searchKey.toLowerCase())) {
|
||||
node.visible = true;
|
||||
} else {
|
||||
node.visible = false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
for (ResourceTreeNode c : node.children) {
|
||||
found |= search(c, searchKey);
|
||||
}
|
||||
node.visible |= found;
|
||||
return node.visible;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Integer getThreadNum() {
|
||||
return threadNum;
|
||||
}
|
||||
|
||||
public void setThreadNum(Integer threadNum) {
|
||||
this.threadNum = threadNum;
|
||||
}
|
||||
|
||||
public Long getPassQps() {
|
||||
return passQps;
|
||||
}
|
||||
|
||||
public void setPassQps(Long passQps) {
|
||||
this.passQps = passQps;
|
||||
}
|
||||
|
||||
public Long getBlockQps() {
|
||||
return blockQps;
|
||||
}
|
||||
|
||||
public void setBlockQps(Long blockQps) {
|
||||
this.blockQps = blockQps;
|
||||
}
|
||||
|
||||
public Long getTotalQps() {
|
||||
return totalQps;
|
||||
}
|
||||
|
||||
public void setTotalQps(Long totalQps) {
|
||||
this.totalQps = totalQps;
|
||||
}
|
||||
|
||||
public Long getAverageRt() {
|
||||
return averageRt;
|
||||
}
|
||||
|
||||
public void setAverageRt(Long averageRt) {
|
||||
this.averageRt = averageRt;
|
||||
}
|
||||
|
||||
public Long getSuccessQps() {
|
||||
return successQps;
|
||||
}
|
||||
|
||||
public void setSuccessQps(Long successQps) {
|
||||
this.successQps = successQps;
|
||||
}
|
||||
|
||||
public Long getExceptionQps() {
|
||||
return exceptionQps;
|
||||
}
|
||||
|
||||
public void setExceptionQps(Long exceptionQps) {
|
||||
this.exceptionQps = exceptionQps;
|
||||
}
|
||||
|
||||
public Long getOneMinutePass() {
|
||||
return oneMinutePass;
|
||||
}
|
||||
|
||||
public void setOneMinutePass(Long oneMinutePass) {
|
||||
this.oneMinutePass = oneMinutePass;
|
||||
}
|
||||
|
||||
public Long getOneMinuteBlock() {
|
||||
return oneMinuteBlock;
|
||||
}
|
||||
|
||||
public void setOneMinuteBlock(Long oneMinuteBlock) {
|
||||
this.oneMinuteBlock = oneMinuteBlock;
|
||||
}
|
||||
|
||||
public Long getOneMinuteException() {
|
||||
return oneMinuteException;
|
||||
}
|
||||
|
||||
public void setOneMinuteException(Long oneMinuteException) {
|
||||
this.oneMinuteException = oneMinuteException;
|
||||
}
|
||||
|
||||
public Long getOneMinuteTotal() {
|
||||
return oneMinuteTotal;
|
||||
}
|
||||
|
||||
public void setOneMinuteTotal(Long oneMinuteTotal) {
|
||||
this.oneMinuteTotal = oneMinuteTotal;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
public List<ResourceTreeNode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(List<ResourceTreeNode> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.domain;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class Result<R> {
|
||||
|
||||
private boolean success;
|
||||
private int code;
|
||||
private String msg;
|
||||
private R data;
|
||||
|
||||
public static <R> Result<R> ofSuccess(R data) {
|
||||
return new Result<R>()
|
||||
.setSuccess(true)
|
||||
.setMsg("success")
|
||||
.setData(data);
|
||||
}
|
||||
|
||||
public static <R> Result<R> ofSuccessMsg(String msg) {
|
||||
return new Result<R>()
|
||||
.setSuccess(true)
|
||||
.setMsg(msg);
|
||||
}
|
||||
|
||||
public static <R> Result<R> ofFail(int code, String msg) {
|
||||
Result<R> result = new Result<>();
|
||||
result.setSuccess(false);
|
||||
result.setCode(code);
|
||||
result.setMsg(msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <R> Result<R> ofThrowable(int code, Throwable throwable) {
|
||||
Result<R> result = new Result<>();
|
||||
result.setSuccess(false);
|
||||
result.setCode(code);
|
||||
result.setMsg(throwable.getClass().getName() + ", " + throwable.getMessage());
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public Result<R> setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public Result<R> setCode(int code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public Result<R> setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
return this;
|
||||
}
|
||||
|
||||
public R getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Result<R> setData(R data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Result{" +
|
||||
"success=" + success +
|
||||
", code=" + code +
|
||||
", msg='" + msg + '\'' +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterAppAssignResultVO {
|
||||
|
||||
private Set<String> failedServerSet;
|
||||
private Set<String> failedClientSet;
|
||||
|
||||
private Integer totalCount;
|
||||
|
||||
public Set<String> getFailedServerSet() {
|
||||
return failedServerSet;
|
||||
}
|
||||
|
||||
public ClusterAppAssignResultVO setFailedServerSet(Set<String> failedServerSet) {
|
||||
this.failedServerSet = failedServerSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getFailedClientSet() {
|
||||
return failedClientSet;
|
||||
}
|
||||
|
||||
public ClusterAppAssignResultVO setFailedClientSet(Set<String> failedClientSet) {
|
||||
this.failedClientSet = failedClientSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public ClusterAppAssignResultVO setTotalCount(Integer totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterAppAssignResultVO{" +
|
||||
"failedServerSet=" + failedServerSet +
|
||||
", failedClientSet=" + failedClientSet +
|
||||
", totalCount=" + totalCount +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.request.ClusterAppAssignMap;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterAppFullAssignRequest {
|
||||
|
||||
private List<ClusterAppAssignMap> clusterMap;
|
||||
private Set<String> remainingList;
|
||||
|
||||
public List<ClusterAppAssignMap> getClusterMap() {
|
||||
return clusterMap;
|
||||
}
|
||||
|
||||
public ClusterAppFullAssignRequest setClusterMap(
|
||||
List<ClusterAppAssignMap> clusterMap) {
|
||||
this.clusterMap = clusterMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getRemainingList() {
|
||||
return remainingList;
|
||||
}
|
||||
|
||||
public ClusterAppFullAssignRequest setRemainingList(Set<String> remainingList) {
|
||||
this.remainingList = remainingList;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterAppFullAssignRequest{" +
|
||||
"clusterMap=" + clusterMap +
|
||||
", remainingList=" + remainingList +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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.domain.cluster;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.request.ClusterAppAssignMap;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterAppSingleServerAssignRequest {
|
||||
|
||||
private ClusterAppAssignMap clusterMap;
|
||||
private Set<String> remainingList;
|
||||
|
||||
public ClusterAppAssignMap getClusterMap() {
|
||||
return clusterMap;
|
||||
}
|
||||
|
||||
public ClusterAppSingleServerAssignRequest setClusterMap(ClusterAppAssignMap clusterMap) {
|
||||
this.clusterMap = clusterMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getRemainingList() {
|
||||
return remainingList;
|
||||
}
|
||||
|
||||
public ClusterAppSingleServerAssignRequest setRemainingList(Set<String> remainingList) {
|
||||
this.remainingList = remainingList;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterAppSingleServerAssignRequest{" +
|
||||
"clusterMap=" + clusterMap +
|
||||
", remainingList=" + remainingList +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterClientInfoVO {
|
||||
|
||||
private String serverHost;
|
||||
private Integer serverPort;
|
||||
|
||||
private Integer clientState;
|
||||
|
||||
private Integer requestTimeout;
|
||||
|
||||
public String getServerHost() {
|
||||
return serverHost;
|
||||
}
|
||||
|
||||
public ClusterClientInfoVO setServerHost(String serverHost) {
|
||||
this.serverHost = serverHost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public ClusterClientInfoVO setServerPort(Integer serverPort) {
|
||||
this.serverPort = serverPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getClientState() {
|
||||
return clientState;
|
||||
}
|
||||
|
||||
public ClusterClientInfoVO setClientState(Integer clientState) {
|
||||
this.clientState = clientState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getRequestTimeout() {
|
||||
return requestTimeout;
|
||||
}
|
||||
|
||||
public ClusterClientInfoVO setRequestTimeout(Integer requestTimeout) {
|
||||
this.requestTimeout = requestTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterClientInfoVO{" +
|
||||
"serverHost='" + serverHost + '\'' +
|
||||
", serverPort=" + serverPort +
|
||||
", clientState=" + clientState +
|
||||
", requestTimeout=" + requestTimeout +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterGroupEntity {
|
||||
|
||||
private String machineId;
|
||||
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Set<String> clientSet = new HashSet<>();
|
||||
|
||||
private Boolean belongToApp;
|
||||
|
||||
public String getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setMachineId(String machineId) {
|
||||
this.machineId = machineId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getClientSet() {
|
||||
return clientSet;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setClientSet(Set<String> clientSet) {
|
||||
this.clientSet = clientSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getBelongToApp() {
|
||||
return belongToApp;
|
||||
}
|
||||
|
||||
public ClusterGroupEntity setBelongToApp(Boolean belongToApp) {
|
||||
this.belongToApp = belongToApp;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterGroupEntity{" +
|
||||
"machineId='" + machineId + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", clientSet=" + clientSet +
|
||||
", belongToApp=" + belongToApp +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterStateSingleVO {
|
||||
|
||||
private String address;
|
||||
private Integer mode;
|
||||
private String target;
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public ClusterStateSingleVO setAddress(String address) {
|
||||
this.address = address;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public ClusterStateSingleVO setMode(Integer mode) {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public ClusterStateSingleVO setTarget(String target) {
|
||||
this.target = target;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterStateSingleVO{" +
|
||||
"address='" + address + '\'' +
|
||||
", mode=" + mode +
|
||||
", target='" + target + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ConnectionDescriptorVO {
|
||||
|
||||
private String address;
|
||||
private String host;
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public ConnectionDescriptorVO setAddress(String address) {
|
||||
this.address = address;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public ConnectionDescriptorVO setHost(String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectionDescriptorVO{" +
|
||||
"address='" + address + '\'' +
|
||||
", host='" + host + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.domain.cluster;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ConnectionGroupVO {
|
||||
|
||||
private String namespace;
|
||||
private List<ConnectionDescriptorVO> connectionSet;
|
||||
private Integer connectedCount;
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public ConnectionGroupVO setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ConnectionDescriptorVO> getConnectionSet() {
|
||||
return connectionSet;
|
||||
}
|
||||
|
||||
public ConnectionGroupVO setConnectionSet(
|
||||
List<ConnectionDescriptorVO> connectionSet) {
|
||||
this.connectionSet = connectionSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getConnectedCount() {
|
||||
return connectedCount;
|
||||
}
|
||||
|
||||
public ConnectionGroupVO setConnectedCount(Integer connectedCount) {
|
||||
this.connectedCount = connectedCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectionGroupVO{" +
|
||||
"namespace='" + namespace + '\'' +
|
||||
", connectionSet=" + connectionSet +
|
||||
", connectedCount=" + connectedCount +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.domain.cluster.config;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterClientConfig {
|
||||
|
||||
private String serverHost;
|
||||
private Integer serverPort;
|
||||
|
||||
private Integer requestTimeout;
|
||||
private Integer connectTimeout;
|
||||
|
||||
public String getServerHost() {
|
||||
return serverHost;
|
||||
}
|
||||
|
||||
public ClusterClientConfig setServerHost(String serverHost) {
|
||||
this.serverHost = serverHost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public ClusterClientConfig setServerPort(Integer serverPort) {
|
||||
this.serverPort = serverPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getRequestTimeout() {
|
||||
return requestTimeout;
|
||||
}
|
||||
|
||||
public ClusterClientConfig setRequestTimeout(Integer requestTimeout) {
|
||||
this.requestTimeout = requestTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public ClusterClientConfig setConnectTimeout(Integer connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterClientConfig{" +
|
||||
"serverHost='" + serverHost + '\'' +
|
||||
", serverPort=" + serverPort +
|
||||
", requestTimeout=" + requestTimeout +
|
||||
", connectTimeout=" + connectTimeout +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.domain.cluster.config;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ServerFlowConfig {
|
||||
|
||||
public static final double DEFAULT_EXCEED_COUNT = 1.0d;
|
||||
public static final double DEFAULT_MAX_OCCUPY_RATIO = 1.0d;
|
||||
|
||||
public static final int DEFAULT_INTERVAL_MS = 1000;
|
||||
public static final int DEFAULT_SAMPLE_COUNT= 10;
|
||||
public static final double DEFAULT_MAX_ALLOWED_QPS= 30000;
|
||||
|
||||
private final String namespace;
|
||||
|
||||
private Double exceedCount = DEFAULT_EXCEED_COUNT;
|
||||
private Double maxOccupyRatio = DEFAULT_MAX_OCCUPY_RATIO;
|
||||
private Integer intervalMs = DEFAULT_INTERVAL_MS;
|
||||
private Integer sampleCount = DEFAULT_SAMPLE_COUNT;
|
||||
|
||||
private Double maxAllowedQps = DEFAULT_MAX_ALLOWED_QPS;
|
||||
|
||||
public ServerFlowConfig() {
|
||||
this("default");
|
||||
}
|
||||
|
||||
public ServerFlowConfig(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public Double getExceedCount() {
|
||||
return exceedCount;
|
||||
}
|
||||
|
||||
public ServerFlowConfig setExceedCount(Double exceedCount) {
|
||||
this.exceedCount = exceedCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Double getMaxOccupyRatio() {
|
||||
return maxOccupyRatio;
|
||||
}
|
||||
|
||||
public ServerFlowConfig setMaxOccupyRatio(Double maxOccupyRatio) {
|
||||
this.maxOccupyRatio = maxOccupyRatio;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getIntervalMs() {
|
||||
return intervalMs;
|
||||
}
|
||||
|
||||
public ServerFlowConfig setIntervalMs(Integer intervalMs) {
|
||||
this.intervalMs = intervalMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getSampleCount() {
|
||||
return sampleCount;
|
||||
}
|
||||
|
||||
public ServerFlowConfig setSampleCount(Integer sampleCount) {
|
||||
this.sampleCount = sampleCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Double getMaxAllowedQps() {
|
||||
return maxAllowedQps;
|
||||
}
|
||||
|
||||
public ServerFlowConfig setMaxAllowedQps(Double maxAllowedQps) {
|
||||
this.maxAllowedQps = maxAllowedQps;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerFlowConfig{" +
|
||||
"namespace='" + namespace + '\'' +
|
||||
", exceedCount=" + exceedCount +
|
||||
", maxOccupyRatio=" + maxOccupyRatio +
|
||||
", intervalMs=" + intervalMs +
|
||||
", sampleCount=" + sampleCount +
|
||||
", maxAllowedQps=" + maxAllowedQps +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.domain.cluster.config;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ServerTransportConfig {
|
||||
|
||||
public static final int DEFAULT_PORT = 18730;
|
||||
public static final int DEFAULT_IDLE_SECONDS = 600;
|
||||
|
||||
private Integer port;
|
||||
private Integer idleSeconds;
|
||||
|
||||
public ServerTransportConfig() {
|
||||
this(DEFAULT_PORT, DEFAULT_IDLE_SECONDS);
|
||||
}
|
||||
|
||||
public ServerTransportConfig(Integer port, Integer idleSeconds) {
|
||||
this.port = port;
|
||||
this.idleSeconds = idleSeconds;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ServerTransportConfig setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getIdleSeconds() {
|
||||
return idleSeconds;
|
||||
}
|
||||
|
||||
public ServerTransportConfig setIdleSeconds(Integer idleSeconds) {
|
||||
this.idleSeconds = idleSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerTransportConfig{" +
|
||||
"port=" + port +
|
||||
", idleSeconds=" + idleSeconds +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.domain.cluster.request;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterAppAssignMap {
|
||||
|
||||
private String machineId;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Boolean belongToApp;
|
||||
|
||||
private Set<String> clientSet;
|
||||
|
||||
private Set<String> namespaceSet;
|
||||
private Double maxAllowedQps;
|
||||
|
||||
public String getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setMachineId(String machineId) {
|
||||
this.machineId = machineId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getClientSet() {
|
||||
return clientSet;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setClientSet(Set<String> clientSet) {
|
||||
this.clientSet = clientSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getNamespaceSet() {
|
||||
return namespaceSet;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setNamespaceSet(Set<String> namespaceSet) {
|
||||
this.namespaceSet = namespaceSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getBelongToApp() {
|
||||
return belongToApp;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setBelongToApp(Boolean belongToApp) {
|
||||
this.belongToApp = belongToApp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Double getMaxAllowedQps() {
|
||||
return maxAllowedQps;
|
||||
}
|
||||
|
||||
public ClusterAppAssignMap setMaxAllowedQps(Double maxAllowedQps) {
|
||||
this.maxAllowedQps = maxAllowedQps;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterAppAssignMap{" +
|
||||
"machineId='" + machineId + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", belongToApp=" + belongToApp +
|
||||
", clientSet=" + clientSet +
|
||||
", namespaceSet=" + namespaceSet +
|
||||
", maxAllowedQps=" + maxAllowedQps +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.domain.cluster.request;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ClusterClientConfig;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterClientModifyRequest implements ClusterModifyRequest {
|
||||
|
||||
private String app;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Integer mode;
|
||||
private ClusterClientConfig clientConfig;
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public ClusterClientModifyRequest setApp(String app) {
|
||||
this.app = app;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public ClusterClientModifyRequest setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ClusterClientModifyRequest setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public ClusterClientModifyRequest setMode(Integer mode) {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterClientConfig getClientConfig() {
|
||||
return clientConfig;
|
||||
}
|
||||
|
||||
public ClusterClientModifyRequest setClientConfig(
|
||||
ClusterClientConfig clientConfig) {
|
||||
this.clientConfig = clientConfig;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.domain.cluster.request;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public interface ClusterModifyRequest {
|
||||
|
||||
String getApp();
|
||||
|
||||
String getIp();
|
||||
|
||||
Integer getPort();
|
||||
|
||||
Integer getMode();
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.domain.cluster.request;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerFlowConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerTransportConfig;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterServerModifyRequest implements ClusterModifyRequest {
|
||||
|
||||
private String app;
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Integer mode;
|
||||
private ServerFlowConfig flowConfig;
|
||||
private ServerTransportConfig transportConfig;
|
||||
private Set<String> namespaceSet;
|
||||
|
||||
@Override
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setApp(String app) {
|
||||
this.app = app;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setMode(Integer mode) {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerFlowConfig getFlowConfig() {
|
||||
return flowConfig;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setFlowConfig(
|
||||
ServerFlowConfig flowConfig) {
|
||||
this.flowConfig = flowConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerTransportConfig getTransportConfig() {
|
||||
return transportConfig;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setTransportConfig(
|
||||
ServerTransportConfig transportConfig) {
|
||||
this.transportConfig = transportConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getNamespaceSet() {
|
||||
return namespaceSet;
|
||||
}
|
||||
|
||||
public ClusterServerModifyRequest setNamespaceSet(Set<String> namespaceSet) {
|
||||
this.namespaceSet = namespaceSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterServerModifyRequest{" +
|
||||
"app='" + app + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port=" + port +
|
||||
", mode=" + mode +
|
||||
", flowConfig=" + flowConfig +
|
||||
", transportConfig=" + transportConfig +
|
||||
", namespaceSet=" + namespaceSet +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class AppClusterClientStateWrapVO {
|
||||
|
||||
/**
|
||||
* {ip}@{transport_command_port}.
|
||||
*/
|
||||
private String id;
|
||||
|
||||
private Integer commandPort;
|
||||
private String ip;
|
||||
|
||||
private ClusterClientStateVO state;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public AppClusterClientStateWrapVO setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public AppClusterClientStateWrapVO setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterClientStateVO getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public AppClusterClientStateWrapVO setState(ClusterClientStateVO state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getCommandPort() {
|
||||
return commandPort;
|
||||
}
|
||||
|
||||
public AppClusterClientStateWrapVO setCommandPort(Integer commandPort) {
|
||||
this.commandPort = commandPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AppClusterClientStateWrapVO{" +
|
||||
"id='" + id + '\'' +
|
||||
", commandPort=" + commandPort +
|
||||
", ip='" + ip + '\'' +
|
||||
", state=" + state +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class AppClusterServerStateWrapVO {
|
||||
|
||||
/**
|
||||
* {ip}@{transport_command_port}.
|
||||
*/
|
||||
private String id;
|
||||
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
private Integer connectedCount;
|
||||
|
||||
private Boolean belongToApp;
|
||||
|
||||
private ClusterServerStateVO state;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public AppClusterServerStateWrapVO setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public AppClusterServerStateWrapVO setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public AppClusterServerStateWrapVO setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getBelongToApp() {
|
||||
return belongToApp;
|
||||
}
|
||||
|
||||
public AppClusterServerStateWrapVO setBelongToApp(Boolean belongToApp) {
|
||||
this.belongToApp = belongToApp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getConnectedCount() {
|
||||
return connectedCount;
|
||||
}
|
||||
|
||||
public AppClusterServerStateWrapVO setConnectedCount(Integer connectedCount) {
|
||||
this.connectedCount = connectedCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public AppClusterServerStateWrapVO setState(ClusterServerStateVO state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AppClusterServerStateWrapVO{" +
|
||||
"id='" + id + '\'' +
|
||||
", ip='" + ip + '\'' +
|
||||
", port='" + port + '\'' +
|
||||
", belongToApp=" + belongToApp +
|
||||
", state=" + state +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ClusterClientInfoVO;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterClientStateVO {
|
||||
|
||||
/**
|
||||
* Cluster token client state.
|
||||
*/
|
||||
private ClusterClientInfoVO clientConfig;
|
||||
|
||||
public ClusterClientInfoVO getClientConfig() {
|
||||
return clientConfig;
|
||||
}
|
||||
|
||||
public ClusterClientStateVO setClientConfig(ClusterClientInfoVO clientConfig) {
|
||||
this.clientConfig = clientConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterClientStateVO{" +
|
||||
"clientConfig=" + clientConfig +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterRequestLimitVO {
|
||||
|
||||
private String namespace;
|
||||
private Double currentQps;
|
||||
private Double maxAllowedQps;
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public ClusterRequestLimitVO setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Double getCurrentQps() {
|
||||
return currentQps;
|
||||
}
|
||||
|
||||
public ClusterRequestLimitVO setCurrentQps(Double currentQps) {
|
||||
this.currentQps = currentQps;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Double getMaxAllowedQps() {
|
||||
return maxAllowedQps;
|
||||
}
|
||||
|
||||
public ClusterRequestLimitVO setMaxAllowedQps(Double maxAllowedQps) {
|
||||
this.maxAllowedQps = maxAllowedQps;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterRequestLimitVO{" +
|
||||
"namespace='" + namespace + '\'' +
|
||||
", currentQps=" + currentQps +
|
||||
", maxAllowedQps=" + maxAllowedQps +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.ConnectionGroupVO;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerFlowConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.cluster.config.ServerTransportConfig;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterServerStateVO {
|
||||
|
||||
private String appName;
|
||||
|
||||
private ServerTransportConfig transport;
|
||||
private ServerFlowConfig flow;
|
||||
private Set<String> namespaceSet;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private List<ConnectionGroupVO> connection;
|
||||
private List<ClusterRequestLimitVO> requestLimitData;
|
||||
|
||||
private Boolean embedded;
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerTransportConfig getTransport() {
|
||||
return transport;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setTransport(ServerTransportConfig transport) {
|
||||
this.transport = transport;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerFlowConfig getFlow() {
|
||||
return flow;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setFlow(ServerFlowConfig flow) {
|
||||
this.flow = flow;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getNamespaceSet() {
|
||||
return namespaceSet;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setNamespaceSet(Set<String> namespaceSet) {
|
||||
this.namespaceSet = namespaceSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ConnectionGroupVO> getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setConnection(List<ConnectionGroupVO> connection) {
|
||||
this.connection = connection;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ClusterRequestLimitVO> getRequestLimitData() {
|
||||
return requestLimitData;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setRequestLimitData(List<ClusterRequestLimitVO> requestLimitData) {
|
||||
this.requestLimitData = requestLimitData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getEmbedded() {
|
||||
return embedded;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO setEmbedded(Boolean embedded) {
|
||||
this.embedded = embedded;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterServerStateVO{" +
|
||||
"appName='" + appName + '\'' +
|
||||
", transport=" + transport +
|
||||
", flow=" + flow +
|
||||
", namespaceSet=" + namespaceSet +
|
||||
", port=" + port +
|
||||
", connection=" + connection +
|
||||
", requestLimitData=" + requestLimitData +
|
||||
", embedded=" + embedded +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterStateSimpleEntity {
|
||||
|
||||
private Integer mode;
|
||||
private Long lastModified;
|
||||
private Boolean clientAvailable;
|
||||
private Boolean serverAvailable;
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public ClusterStateSimpleEntity setMode(Integer mode) {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public ClusterStateSimpleEntity setLastModified(Long lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getClientAvailable() {
|
||||
return clientAvailable;
|
||||
}
|
||||
|
||||
public ClusterStateSimpleEntity setClientAvailable(Boolean clientAvailable) {
|
||||
this.clientAvailable = clientAvailable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean getServerAvailable() {
|
||||
return serverAvailable;
|
||||
}
|
||||
|
||||
public ClusterStateSimpleEntity setServerAvailable(Boolean serverAvailable) {
|
||||
this.serverAvailable = serverAvailable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterStateSimpleEntity{" +
|
||||
"mode=" + mode +
|
||||
", lastModified=" + lastModified +
|
||||
", clientAvailable=" + clientAvailable +
|
||||
", serverAvailable=" + serverAvailable +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.1
|
||||
*/
|
||||
public class ClusterUniversalStatePairVO {
|
||||
|
||||
private String ip;
|
||||
private Integer commandPort;
|
||||
|
||||
private ClusterUniversalStateVO state;
|
||||
|
||||
public ClusterUniversalStatePairVO() {}
|
||||
|
||||
public ClusterUniversalStatePairVO(String ip, Integer commandPort, ClusterUniversalStateVO state) {
|
||||
this.ip = ip;
|
||||
this.commandPort = commandPort;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public ClusterUniversalStatePairVO setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getCommandPort() {
|
||||
return commandPort;
|
||||
}
|
||||
|
||||
public ClusterUniversalStatePairVO setCommandPort(Integer commandPort) {
|
||||
this.commandPort = commandPort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterUniversalStateVO getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public ClusterUniversalStatePairVO setState(ClusterUniversalStateVO state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterUniversalStatePairVO{" +
|
||||
"ip='" + ip + '\'' +
|
||||
", commandPort=" + commandPort +
|
||||
", state=" + state +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.domain.cluster.state;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ClusterUniversalStateVO {
|
||||
|
||||
private ClusterStateSimpleEntity stateInfo;
|
||||
private ClusterClientStateVO client;
|
||||
private ClusterServerStateVO server;
|
||||
|
||||
public ClusterClientStateVO getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public ClusterUniversalStateVO setClient(ClusterClientStateVO client) {
|
||||
this.client = client;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterServerStateVO getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public ClusterUniversalStateVO setServer(ClusterServerStateVO server) {
|
||||
this.server = server;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClusterStateSimpleEntity getStateInfo() {
|
||||
return stateInfo;
|
||||
}
|
||||
|
||||
public ClusterUniversalStateVO setStateInfo(
|
||||
ClusterStateSimpleEntity stateInfo) {
|
||||
this.stateInfo = stateInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterUniversalStateVO{" +
|
||||
"stateInfo=" + stateInfo +
|
||||
", client=" + client +
|
||||
", server=" + server +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.domain.vo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class MachineInfoVo {
|
||||
|
||||
private String app;
|
||||
private String hostname;
|
||||
private String ip;
|
||||
private int port;
|
||||
private long heartbeatVersion;
|
||||
private long lastHeartbeat;
|
||||
private boolean healthy;
|
||||
|
||||
private String version;
|
||||
|
||||
public static List<MachineInfoVo> fromMachineInfoList(List<MachineInfo> machines) {
|
||||
List<MachineInfoVo> list = new ArrayList<>();
|
||||
for (MachineInfo machine : machines) {
|
||||
list.add(fromMachineInfo(machine));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static MachineInfoVo fromMachineInfo(MachineInfo machine) {
|
||||
MachineInfoVo vo = new MachineInfoVo();
|
||||
vo.setApp(machine.getApp());
|
||||
vo.setHostname(machine.getHostname());
|
||||
vo.setIp(machine.getIp());
|
||||
vo.setPort(machine.getPort());
|
||||
vo.setLastHeartbeat(machine.getLastHeartbeat());
|
||||
vo.setHeartbeatVersion(machine.getHeartbeatVersion());
|
||||
vo.setVersion(machine.getVersion());
|
||||
vo.setHealthy(machine.isHealthy());
|
||||
return vo;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public long getLastHeartbeat() {
|
||||
return lastHeartbeat;
|
||||
}
|
||||
|
||||
public void setLastHeartbeat(long lastHeartbeat) {
|
||||
this.lastHeartbeat = lastHeartbeat;
|
||||
}
|
||||
|
||||
public void setHeartbeatVersion(long heartbeatVersion) {
|
||||
this.heartbeatVersion = heartbeatVersion;
|
||||
}
|
||||
|
||||
public long getHeartbeatVersion() {
|
||||
return heartbeatVersion;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public MachineInfoVo setVersion(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isHealthy() {
|
||||
return healthy;
|
||||
}
|
||||
|
||||
public void setHealthy(boolean healthy) {
|
||||
this.healthy = healthy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.domain.vo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class MetricVo implements Comparable<MetricVo> {
|
||||
private Long id;
|
||||
private String app;
|
||||
private Long timestamp;
|
||||
private Long gmtCreate = System.currentTimeMillis();
|
||||
private String resource;
|
||||
private Long passQps;
|
||||
private Long blockQps;
|
||||
private Long successQps;
|
||||
private Long exceptionQps;
|
||||
/**
|
||||
* average rt
|
||||
*/
|
||||
private Double rt;
|
||||
private Integer count;
|
||||
|
||||
public MetricVo() {
|
||||
}
|
||||
|
||||
public static List<MetricVo> fromMetricEntities(Collection<MetricEntity> entities) {
|
||||
List<MetricVo> list = new ArrayList<>();
|
||||
if (entities != null) {
|
||||
for (MetricEntity entity : entities) {
|
||||
list.add(fromMetricEntity(entity));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留资源名为identity的结果。
|
||||
*
|
||||
* @param entities 通过hashCode查找到的MetricEntities
|
||||
* @param identity 真正需要查找的资源名
|
||||
* @return
|
||||
*/
|
||||
public static List<MetricVo> fromMetricEntities(Collection<MetricEntity> entities, String identity) {
|
||||
List<MetricVo> list = new ArrayList<>();
|
||||
if (entities != null) {
|
||||
for (MetricEntity entity : entities) {
|
||||
if (entity.getResource().equals(identity)) {
|
||||
list.add(fromMetricEntity(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static MetricVo fromMetricEntity(MetricEntity entity) {
|
||||
MetricVo vo = new MetricVo();
|
||||
vo.id = entity.getId();
|
||||
vo.app = entity.getApp();
|
||||
vo.timestamp = entity.getTimestamp().getTime();
|
||||
vo.gmtCreate = entity.getGmtCreate().getTime();
|
||||
vo.resource = entity.getResource();
|
||||
vo.passQps = entity.getPassQps();
|
||||
vo.blockQps = entity.getBlockQps();
|
||||
vo.successQps = entity.getSuccessQps();
|
||||
vo.exceptionQps = entity.getExceptionQps();
|
||||
if (entity.getSuccessQps() != 0) {
|
||||
vo.rt = entity.getRt() / entity.getSuccessQps();
|
||||
} else {
|
||||
vo.rt = 0D;
|
||||
}
|
||||
vo.count = entity.getCount();
|
||||
return vo;
|
||||
}
|
||||
|
||||
public static MetricVo parse(String line) {
|
||||
String[] strs = line.split("\\|");
|
||||
long timestamp = Long.parseLong(strs[0]);
|
||||
String identity = strs[1];
|
||||
long passQps = Long.parseLong(strs[2]);
|
||||
long blockQps = Long.parseLong(strs[3]);
|
||||
long exception = Long.parseLong(strs[4]);
|
||||
double rt = Double.parseDouble(strs[5]);
|
||||
long successQps = Long.parseLong(strs[6]);
|
||||
MetricVo vo = new MetricVo();
|
||||
vo.timestamp = timestamp;
|
||||
vo.resource = identity;
|
||||
vo.passQps = passQps;
|
||||
vo.blockQps = blockQps;
|
||||
vo.successQps = successQps;
|
||||
vo.exceptionQps = exception;
|
||||
vo.rt = rt;
|
||||
vo.count = 1;
|
||||
return vo;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Long getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Long gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Long getPassQps() {
|
||||
return passQps;
|
||||
}
|
||||
|
||||
public void setPassQps(Long passQps) {
|
||||
this.passQps = passQps;
|
||||
}
|
||||
|
||||
public Long getBlockQps() {
|
||||
return blockQps;
|
||||
}
|
||||
|
||||
public void setBlockQps(Long blockQps) {
|
||||
this.blockQps = blockQps;
|
||||
}
|
||||
|
||||
public Long getSuccessQps() {
|
||||
return successQps;
|
||||
}
|
||||
|
||||
public void setSuccessQps(Long successQps) {
|
||||
this.successQps = successQps;
|
||||
}
|
||||
|
||||
public Long getExceptionQps() {
|
||||
return exceptionQps;
|
||||
}
|
||||
|
||||
public void setExceptionQps(Long exceptionQps) {
|
||||
this.exceptionQps = exceptionQps;
|
||||
}
|
||||
|
||||
public Double getRt() {
|
||||
return rt;
|
||||
}
|
||||
|
||||
public void setRt(Double rt) {
|
||||
this.rt = rt;
|
||||
}
|
||||
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MetricVo o) {
|
||||
return Long.compare(this.timestamp, o.timestamp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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.domain.vo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.command.vo.NodeVo;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.domain.ResourceTreeNode;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
public class ResourceVo {
|
||||
private String parentTtId;
|
||||
private String ttId;
|
||||
private String resource;
|
||||
|
||||
private Integer threadNum;
|
||||
private Long passQps;
|
||||
private Long blockQps;
|
||||
private Long totalQps;
|
||||
private Long averageRt;
|
||||
private Long passRequestQps;
|
||||
private Long exceptionQps;
|
||||
private Long oneMinutePass;
|
||||
private Long oneMinuteBlock;
|
||||
private Long oneMinuteException;
|
||||
private Long oneMinuteTotal;
|
||||
|
||||
private boolean visible = true;
|
||||
|
||||
public ResourceVo() {
|
||||
}
|
||||
|
||||
public static List<ResourceVo> fromNodeVoList(List<NodeVo> nodeVos) {
|
||||
if (nodeVos == null) {
|
||||
return null;
|
||||
}
|
||||
List<ResourceVo> list = new ArrayList<>();
|
||||
for (NodeVo nodeVo : nodeVos) {
|
||||
ResourceVo vo = new ResourceVo();
|
||||
vo.parentTtId = nodeVo.getParentId();
|
||||
vo.ttId = nodeVo.getId();
|
||||
vo.resource = nodeVo.getResource();
|
||||
vo.threadNum = nodeVo.getThreadNum();
|
||||
vo.passQps = nodeVo.getPassQps();
|
||||
vo.blockQps = nodeVo.getBlockQps();
|
||||
vo.totalQps = nodeVo.getTotalQps();
|
||||
vo.averageRt = nodeVo.getAverageRt();
|
||||
vo.exceptionQps = nodeVo.getExceptionQps();
|
||||
vo.oneMinutePass = nodeVo.getOneMinutePass();
|
||||
vo.oneMinuteBlock = nodeVo.getOneMinuteBlock();
|
||||
vo.oneMinuteException = nodeVo.getOneMinuteException();
|
||||
vo.oneMinuteTotal = nodeVo.getOneMinuteTotal();
|
||||
list.add(vo);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<ResourceVo> fromResourceTreeNode(ResourceTreeNode root) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
List<ResourceVo> list = new ArrayList<>();
|
||||
visit(root, list, false, true);
|
||||
//if(!list.isEmpty()){
|
||||
// list.remove(0);
|
||||
//}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* This node is visible when this.visible==true or one of this's parents is visible,
|
||||
* root node is always invisible.
|
||||
*/
|
||||
private static void visit(ResourceTreeNode node, List<ResourceVo> list, boolean parentVisible, boolean isRoot) {
|
||||
boolean visible = !isRoot && (node.isVisible() || parentVisible);
|
||||
//boolean visible = node.isVisible();
|
||||
if (visible) {
|
||||
ResourceVo vo = new ResourceVo();
|
||||
vo.parentTtId = node.getParentId();
|
||||
vo.ttId = node.getId();
|
||||
vo.resource = node.getResource();
|
||||
vo.threadNum = node.getThreadNum();
|
||||
vo.passQps = node.getPassQps();
|
||||
vo.blockQps = node.getBlockQps();
|
||||
vo.totalQps = node.getTotalQps();
|
||||
vo.averageRt = node.getAverageRt();
|
||||
vo.exceptionQps = node.getExceptionQps();
|
||||
vo.oneMinutePass = node.getOneMinutePass();
|
||||
vo.oneMinuteBlock = node.getOneMinuteBlock();
|
||||
vo.oneMinuteException = node.getOneMinuteException();
|
||||
vo.oneMinuteTotal = node.getOneMinuteTotal();
|
||||
vo.visible = node.isVisible();
|
||||
list.add(vo);
|
||||
}
|
||||
for (ResourceTreeNode c : node.getChildren()) {
|
||||
visit(c, list, visible, false);
|
||||
}
|
||||
}
|
||||
|
||||
public String getParentTtId() {
|
||||
return parentTtId;
|
||||
}
|
||||
|
||||
public void setParentTtId(String parentTtId) {
|
||||
this.parentTtId = parentTtId;
|
||||
}
|
||||
|
||||
public String getTtId() {
|
||||
return ttId;
|
||||
}
|
||||
|
||||
public void setTtId(String ttId) {
|
||||
this.ttId = ttId;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Integer getThreadNum() {
|
||||
return threadNum;
|
||||
}
|
||||
|
||||
public void setThreadNum(Integer threadNum) {
|
||||
this.threadNum = threadNum;
|
||||
}
|
||||
|
||||
public Long getPassQps() {
|
||||
return passQps;
|
||||
}
|
||||
|
||||
public void setPassQps(Long passQps) {
|
||||
this.passQps = passQps;
|
||||
}
|
||||
|
||||
public Long getBlockQps() {
|
||||
return blockQps;
|
||||
}
|
||||
|
||||
public void setBlockQps(Long blockQps) {
|
||||
this.blockQps = blockQps;
|
||||
}
|
||||
|
||||
public Long getTotalQps() {
|
||||
return totalQps;
|
||||
}
|
||||
|
||||
public void setTotalQps(Long totalQps) {
|
||||
this.totalQps = totalQps;
|
||||
}
|
||||
|
||||
public Long getAverageRt() {
|
||||
return averageRt;
|
||||
}
|
||||
|
||||
public void setAverageRt(Long averageRt) {
|
||||
this.averageRt = averageRt;
|
||||
}
|
||||
|
||||
public Long getPassRequestQps() {
|
||||
return passRequestQps;
|
||||
}
|
||||
|
||||
public void setPassRequestQps(Long passRequestQps) {
|
||||
this.passRequestQps = passRequestQps;
|
||||
}
|
||||
|
||||
public Long getExceptionQps() {
|
||||
return exceptionQps;
|
||||
}
|
||||
|
||||
public void setExceptionQps(Long exceptionQps) {
|
||||
this.exceptionQps = exceptionQps;
|
||||
}
|
||||
|
||||
public Long getOneMinuteException() {
|
||||
return oneMinuteException;
|
||||
}
|
||||
|
||||
public void setOneMinuteException(Long oneMinuteException) {
|
||||
this.oneMinuteException = oneMinuteException;
|
||||
}
|
||||
|
||||
public Long getOneMinutePass() {
|
||||
return oneMinutePass;
|
||||
}
|
||||
|
||||
public void setOneMinutePass(Long oneMinutePass) {
|
||||
this.oneMinutePass = oneMinutePass;
|
||||
}
|
||||
|
||||
public Long getOneMinuteBlock() {
|
||||
return oneMinuteBlock;
|
||||
}
|
||||
|
||||
public void setOneMinuteBlock(Long oneMinuteBlock) {
|
||||
this.oneMinuteBlock = oneMinuteBlock;
|
||||
}
|
||||
|
||||
public Long getOneMinuteTotal() {
|
||||
return oneMinuteTotal;
|
||||
}
|
||||
|
||||
public void setOneMinuteTotal(Long oneMinuteTotal) {
|
||||
this.oneMinuteTotal = oneMinuteTotal;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.domain.vo.gateway.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Value Object for add gateway api.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class AddApiReqVo {
|
||||
|
||||
private String app;
|
||||
|
||||
private String ip;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private String apiName;
|
||||
|
||||
private List<ApiPredicateItemVo> predicateItems;
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getApiName() {
|
||||
return apiName;
|
||||
}
|
||||
|
||||
public void setApiName(String apiName) {
|
||||
this.apiName = apiName;
|
||||
}
|
||||
|
||||
public List<ApiPredicateItemVo> getPredicateItems() {
|
||||
return predicateItems;
|
||||
}
|
||||
|
||||
public void setPredicateItems(List<ApiPredicateItemVo> predicateItems) {
|
||||
this.predicateItems = predicateItems;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.domain.vo.gateway.api;
|
||||
|
||||
/**
|
||||
* Value Object for add or update gateway api.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class ApiPredicateItemVo {
|
||||
|
||||
/**
|
||||
* The pattern for matching url.
|
||||
*/
|
||||
private String pattern;
|
||||
|
||||
/**
|
||||
* The matching Strategy in url. Constants are defined in class SentinelGatewayConstants.\
|
||||
*
|
||||
* <ul>
|
||||
* <li>0(URL_MATCH_STRATEGY_EXACT): exact match mode</li>
|
||||
* <li>1(URL_MATCH_STRATEGY_PREFIX): prefix match mode</li>
|
||||
* <li>2(URL_MATCH_STRATEGY_REGEX): regex match mode</li>
|
||||
* </ul>
|
||||
*/
|
||||
private Integer matchStrategy;
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public Integer getMatchStrategy() {
|
||||
return matchStrategy;
|
||||
}
|
||||
|
||||
public void setMatchStrategy(Integer matchStrategy) {
|
||||
this.matchStrategy = matchStrategy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.domain.vo.gateway.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Value Object for update gateway api.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class UpdateApiReqVo {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String app;
|
||||
|
||||
private List<ApiPredicateItemVo> predicateItems;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public List<ApiPredicateItemVo> getPredicateItems() {
|
||||
return predicateItems;
|
||||
}
|
||||
|
||||
public void setPredicateItems(List<ApiPredicateItemVo> predicateItems) {
|
||||
this.predicateItems = predicateItems;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.domain.vo.gateway.rule;
|
||||
|
||||
/**
|
||||
* Value Object for add gateway flow rule.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class AddFlowRuleReqVo {
|
||||
|
||||
private String app;
|
||||
|
||||
private String ip;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private String resource;
|
||||
|
||||
private Integer resourceMode;
|
||||
|
||||
private Integer grade;
|
||||
|
||||
private Double count;
|
||||
|
||||
private Long interval;
|
||||
|
||||
private Integer intervalUnit;
|
||||
|
||||
private Integer controlBehavior;
|
||||
|
||||
private Integer burst;
|
||||
|
||||
private Integer maxQueueingTimeoutMs;
|
||||
|
||||
private GatewayParamFlowItemVo paramItem;
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public Integer getResourceMode() {
|
||||
return resourceMode;
|
||||
}
|
||||
|
||||
public void setResourceMode(Integer resourceMode) {
|
||||
this.resourceMode = resourceMode;
|
||||
}
|
||||
|
||||
public Integer getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void setGrade(Integer grade) {
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
public Double getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Double count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Long getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public void setInterval(Long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public Integer getIntervalUnit() {
|
||||
return intervalUnit;
|
||||
}
|
||||
|
||||
public void setIntervalUnit(Integer intervalUnit) {
|
||||
this.intervalUnit = intervalUnit;
|
||||
}
|
||||
|
||||
public Integer getControlBehavior() {
|
||||
return controlBehavior;
|
||||
}
|
||||
|
||||
public void setControlBehavior(Integer controlBehavior) {
|
||||
this.controlBehavior = controlBehavior;
|
||||
}
|
||||
|
||||
public Integer getBurst() {
|
||||
return burst;
|
||||
}
|
||||
|
||||
public void setBurst(Integer burst) {
|
||||
this.burst = burst;
|
||||
}
|
||||
|
||||
public Integer getMaxQueueingTimeoutMs() {
|
||||
return maxQueueingTimeoutMs;
|
||||
}
|
||||
|
||||
public void setMaxQueueingTimeoutMs(Integer maxQueueingTimeoutMs) {
|
||||
this.maxQueueingTimeoutMs = maxQueueingTimeoutMs;
|
||||
}
|
||||
|
||||
public GatewayParamFlowItemVo getParamItem() {
|
||||
return paramItem;
|
||||
}
|
||||
|
||||
public void setParamItem(GatewayParamFlowItemVo paramItem) {
|
||||
this.paramItem = paramItem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.domain.vo.gateway.rule;
|
||||
|
||||
/**
|
||||
* Value Object for add or update gateway flow rule.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class GatewayParamFlowItemVo {
|
||||
|
||||
private Integer parseStrategy;
|
||||
|
||||
private String fieldName;
|
||||
|
||||
private String pattern;
|
||||
|
||||
private Integer matchStrategy;
|
||||
|
||||
public Integer getParseStrategy() {
|
||||
return parseStrategy;
|
||||
}
|
||||
|
||||
public void setParseStrategy(Integer parseStrategy) {
|
||||
this.parseStrategy = parseStrategy;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
public void setFieldName(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void setPattern(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public Integer getMatchStrategy() {
|
||||
return matchStrategy;
|
||||
}
|
||||
|
||||
public void setMatchStrategy(Integer matchStrategy) {
|
||||
this.matchStrategy = matchStrategy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.domain.vo.gateway.rule;
|
||||
|
||||
/**
|
||||
* Value Object for update gateway flow rule.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public class UpdateFlowRuleReqVo {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String app;
|
||||
|
||||
private Integer grade;
|
||||
|
||||
private Double count;
|
||||
|
||||
private Long interval;
|
||||
|
||||
private Integer intervalUnit;
|
||||
|
||||
private Integer controlBehavior;
|
||||
|
||||
private Integer burst;
|
||||
|
||||
private Integer maxQueueingTimeoutMs;
|
||||
|
||||
private GatewayParamFlowItemVo paramItem;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public Integer getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void setGrade(Integer grade) {
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
public Double getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Double count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public Long getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public void setInterval(Long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public Integer getIntervalUnit() {
|
||||
return intervalUnit;
|
||||
}
|
||||
|
||||
public void setIntervalUnit(Integer intervalUnit) {
|
||||
this.intervalUnit = intervalUnit;
|
||||
}
|
||||
|
||||
public Integer getControlBehavior() {
|
||||
return controlBehavior;
|
||||
}
|
||||
|
||||
public void setControlBehavior(Integer controlBehavior) {
|
||||
this.controlBehavior = controlBehavior;
|
||||
}
|
||||
|
||||
public Integer getBurst() {
|
||||
return burst;
|
||||
}
|
||||
|
||||
public void setBurst(Integer burst) {
|
||||
this.burst = burst;
|
||||
}
|
||||
|
||||
public Integer getMaxQueueingTimeoutMs() {
|
||||
return maxQueueingTimeoutMs;
|
||||
}
|
||||
|
||||
public void setMaxQueueingTimeoutMs(Integer maxQueueingTimeoutMs) {
|
||||
this.maxQueueingTimeoutMs = maxQueueingTimeoutMs;
|
||||
}
|
||||
|
||||
public GatewayParamFlowItemVo getParamItem() {
|
||||
return paramItem;
|
||||
}
|
||||
|
||||
public void setParamItem(GatewayParamFlowItemVo paramItem) {
|
||||
this.paramItem = paramItem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* 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.metric;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.csp.sentinel.Constants;
|
||||
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
|
||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppInfo;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
|
||||
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.alibaba.csp.sentinel.node.metric.MetricNode;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.metric.MetricsRepository;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.concurrent.FutureCallback;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.impl.client.DefaultRedirectStrategy;
|
||||
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClients;
|
||||
import org.apache.http.impl.nio.reactor.IOReactorConfig;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Fetch metric of machines.
|
||||
*
|
||||
* @author leyou
|
||||
*/
|
||||
@Component
|
||||
public class MetricFetcher {
|
||||
|
||||
public static final String NO_METRICS = "No metrics";
|
||||
private static final int HTTP_OK = 200;
|
||||
private static final long MAX_LAST_FETCH_INTERVAL_MS = 1000 * 15;
|
||||
private static final long FETCH_INTERVAL_SECOND = 6;
|
||||
private static final Charset DEFAULT_CHARSET = Charset.forName(SentinelConfig.charset());
|
||||
private final static String METRIC_URL_PATH = "metric";
|
||||
private static Logger logger = LoggerFactory.getLogger(MetricFetcher.class);
|
||||
private final long intervalSecond = 1;
|
||||
|
||||
private Map<String, AtomicLong> appLastFetchTime = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private MetricsRepository<MetricEntity> metricStore;
|
||||
@Autowired
|
||||
private AppManagement appManagement;
|
||||
|
||||
private CloseableHttpAsyncClient httpclient;
|
||||
|
||||
@SuppressWarnings("PMD.ThreadPoolCreationRule")
|
||||
private ScheduledExecutorService fetchScheduleService = Executors.newScheduledThreadPool(1,
|
||||
new NamedThreadFactory("sentinel-dashboard-metrics-fetch-task", true));
|
||||
private ExecutorService fetchService;
|
||||
private ExecutorService fetchWorker;
|
||||
|
||||
public MetricFetcher() {
|
||||
int cores = Runtime.getRuntime().availableProcessors() * 2;
|
||||
long keepAliveTime = 0;
|
||||
int queueSize = 2048;
|
||||
RejectedExecutionHandler handler = new DiscardPolicy();
|
||||
fetchService = new ThreadPoolExecutor(cores, cores,
|
||||
keepAliveTime, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(queueSize),
|
||||
new NamedThreadFactory("sentinel-dashboard-metrics-fetchService", true), handler);
|
||||
fetchWorker = new ThreadPoolExecutor(cores, cores,
|
||||
keepAliveTime, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(queueSize),
|
||||
new NamedThreadFactory("sentinel-dashboard-metrics-fetchWorker",true), handler);
|
||||
IOReactorConfig ioConfig = IOReactorConfig.custom()
|
||||
.setConnectTimeout(3000)
|
||||
.setSoTimeout(3000)
|
||||
.setIoThreadCount(Runtime.getRuntime().availableProcessors() * 2)
|
||||
.build();
|
||||
|
||||
httpclient = HttpAsyncClients.custom()
|
||||
.setRedirectStrategy(new DefaultRedirectStrategy() {
|
||||
@Override
|
||||
protected boolean isRedirectable(final String method) {
|
||||
return false;
|
||||
}
|
||||
}).setMaxConnTotal(4000)
|
||||
.setMaxConnPerRoute(1000)
|
||||
.setDefaultIOReactorConfig(ioConfig)
|
||||
.build();
|
||||
httpclient.start();
|
||||
start();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
fetchScheduleService.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
fetchAllApp();
|
||||
} catch (Exception e) {
|
||||
logger.info("fetchAllApp error:", e);
|
||||
}
|
||||
}, 10, intervalSecond, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void writeMetric(Map<String, MetricEntity> map) {
|
||||
if (map.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Date date = new Date();
|
||||
for (MetricEntity entity : map.values()) {
|
||||
entity.setGmtCreate(date);
|
||||
entity.setGmtModified(date);
|
||||
}
|
||||
metricStore.saveAll(map.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse each APP, and then pull the metric of all machines for that APP.
|
||||
*/
|
||||
private void fetchAllApp() {
|
||||
List<String> apps = appManagement.getAppNames();
|
||||
if (apps == null) {
|
||||
return;
|
||||
}
|
||||
for (final String app : apps) {
|
||||
fetchService.submit(() -> {
|
||||
try {
|
||||
doFetchAppMetric(app);
|
||||
} catch (Exception e) {
|
||||
logger.error("fetchAppMetric error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch metric between [startTime, endTime], both side inclusive
|
||||
*/
|
||||
private void fetchOnce(String app, long startTime, long endTime, int maxWaitSeconds) {
|
||||
if (maxWaitSeconds <= 0) {
|
||||
throw new IllegalArgumentException("maxWaitSeconds must > 0, but " + maxWaitSeconds);
|
||||
}
|
||||
AppInfo appInfo = appManagement.getDetailApp(app);
|
||||
// auto remove for app
|
||||
if (appInfo.isDead()) {
|
||||
logger.info("Dead app removed: {}", app);
|
||||
appManagement.removeApp(app);
|
||||
return;
|
||||
}
|
||||
Set<MachineInfo> machines = appInfo.getMachines();
|
||||
logger.debug("enter fetchOnce(" + app + "), machines.size()=" + machines.size()
|
||||
+ ", time intervalMs [" + startTime + ", " + endTime + "]");
|
||||
if (machines.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final String msg = "fetch";
|
||||
AtomicLong unhealthy = new AtomicLong();
|
||||
final AtomicLong success = new AtomicLong();
|
||||
final AtomicLong fail = new AtomicLong();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
/** app_resource_timeSecond -> metric */
|
||||
final Map<String, MetricEntity> metricMap = new ConcurrentHashMap<>(16);
|
||||
final CountDownLatch latch = new CountDownLatch(machines.size());
|
||||
for (final MachineInfo machine : machines) {
|
||||
// auto remove
|
||||
if (machine.isDead()) {
|
||||
latch.countDown();
|
||||
appManagement.getDetailApp(app).removeMachine(machine.getIp(), machine.getPort());
|
||||
logger.info("Dead machine removed: {}:{} of {}", machine.getIp(), machine.getPort(), app);
|
||||
continue;
|
||||
}
|
||||
if (!machine.isHealthy()) {
|
||||
latch.countDown();
|
||||
unhealthy.incrementAndGet();
|
||||
continue;
|
||||
}
|
||||
final String url = "http://" + machine.getIp() + ":" + machine.getPort() + "/" + METRIC_URL_PATH
|
||||
+ "?startTime=" + startTime + "&endTime=" + endTime + "&refetch=" + false;
|
||||
final HttpGet httpGet = new HttpGet(url);
|
||||
httpGet.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
|
||||
httpclient.execute(httpGet, new FutureCallback<HttpResponse>() {
|
||||
@Override
|
||||
public void completed(final HttpResponse response) {
|
||||
try {
|
||||
handleResponse(response, machine, metricMap);
|
||||
success.incrementAndGet();
|
||||
} catch (Exception e) {
|
||||
logger.error(msg + " metric " + url + " error:", e);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(final Exception ex) {
|
||||
latch.countDown();
|
||||
fail.incrementAndGet();
|
||||
httpGet.abort();
|
||||
if (ex instanceof SocketTimeoutException) {
|
||||
logger.error("Failed to fetch metric from <{}>: socket timeout", url);
|
||||
} else if (ex instanceof ConnectException) {
|
||||
logger.error("Failed to fetch metric from <{}> (ConnectionException: {})", url, ex.getMessage());
|
||||
} else {
|
||||
logger.error(msg + " metric " + url + " error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelled() {
|
||||
latch.countDown();
|
||||
fail.incrementAndGet();
|
||||
httpGet.abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
try {
|
||||
latch.await(maxWaitSeconds, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
logger.info(msg + " metric, wait http client error:", e);
|
||||
}
|
||||
//long cost = System.currentTimeMillis() - start;
|
||||
//logger.info("finished " + msg + " metric for " + app + ", time intervalMs [" + startTime + ", " + endTime
|
||||
// + "], total machines=" + machines.size() + ", dead=" + dead + ", fetch success="
|
||||
// + success + ", fetch fail=" + fail + ", time cost=" + cost + " ms");
|
||||
writeMetric(metricMap);
|
||||
}
|
||||
|
||||
private void doFetchAppMetric(final String app) {
|
||||
long now = System.currentTimeMillis();
|
||||
long lastFetchMs = now - MAX_LAST_FETCH_INTERVAL_MS;
|
||||
if (appLastFetchTime.containsKey(app)) {
|
||||
lastFetchMs = Math.max(lastFetchMs, appLastFetchTime.get(app).get() + 1000);
|
||||
}
|
||||
// trim milliseconds
|
||||
lastFetchMs = lastFetchMs / 1000 * 1000;
|
||||
long endTime = lastFetchMs + FETCH_INTERVAL_SECOND * 1000;
|
||||
if (endTime > now - 1000 * 2) {
|
||||
// too near
|
||||
return;
|
||||
}
|
||||
// update last_fetch in advance.
|
||||
appLastFetchTime.computeIfAbsent(app, a -> new AtomicLong()).set(endTime);
|
||||
final long finalLastFetchMs = lastFetchMs;
|
||||
final long finalEndTime = endTime;
|
||||
try {
|
||||
// do real fetch async
|
||||
fetchWorker.submit(() -> {
|
||||
try {
|
||||
fetchOnce(app, finalLastFetchMs, finalEndTime, 5);
|
||||
} catch (Exception e) {
|
||||
logger.info("fetchOnce(" + app + ") error", e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.info("submit fetchOnce(" + app + ") fail, intervalMs [" + lastFetchMs + ", " + endTime + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleResponse(final HttpResponse response, MachineInfo machine,
|
||||
Map<String, MetricEntity> metricMap) throws Exception {
|
||||
int code = response.getStatusLine().getStatusCode();
|
||||
if (code != HTTP_OK) {
|
||||
return;
|
||||
}
|
||||
Charset charset = null;
|
||||
try {
|
||||
String contentTypeStr = response.getFirstHeader("Content-type").getValue();
|
||||
if (StringUtil.isNotEmpty(contentTypeStr)) {
|
||||
ContentType contentType = ContentType.parse(contentTypeStr);
|
||||
charset = contentType.getCharset();
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
String body = EntityUtils.toString(response.getEntity(), charset != null ? charset : DEFAULT_CHARSET);
|
||||
if (StringUtil.isEmpty(body) || body.startsWith(NO_METRICS)) {
|
||||
//logger.info(machine.getApp() + ":" + machine.getIp() + ":" + machine.getPort() + ", bodyStr is empty");
|
||||
return;
|
||||
}
|
||||
String[] lines = body.split("\n");
|
||||
//logger.info(machine.getApp() + ":" + machine.getIp() + ":" + machine.getPort() +
|
||||
// ", bodyStr.length()=" + body.length() + ", lines=" + lines.length);
|
||||
handleBody(lines, machine, metricMap);
|
||||
}
|
||||
|
||||
private void handleBody(String[] lines, MachineInfo machine, Map<String, MetricEntity> map) {
|
||||
//logger.info("handleBody() lines=" + lines.length + ", machine=" + machine);
|
||||
if (lines.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String line : lines) {
|
||||
try {
|
||||
MetricNode node = MetricNode.fromThinString(line);
|
||||
if (shouldFilterOut(node.getResource())) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* aggregation metrics by app_resource_timeSecond, ignore ip and port.
|
||||
*/
|
||||
String key = buildMetricKey(machine.getApp(), node.getResource(), node.getTimestamp());
|
||||
|
||||
MetricEntity metricEntity = map.computeIfAbsent(key, s -> {
|
||||
MetricEntity initMetricEntity = new MetricEntity();
|
||||
initMetricEntity.setApp(machine.getApp());
|
||||
initMetricEntity.setTimestamp(new Date(node.getTimestamp()));
|
||||
initMetricEntity.setPassQps(0L);
|
||||
initMetricEntity.setBlockQps(0L);
|
||||
initMetricEntity.setRtAndSuccessQps(0, 0L);
|
||||
initMetricEntity.setExceptionQps(0L);
|
||||
initMetricEntity.setCount(0);
|
||||
initMetricEntity.setResource(node.getResource());
|
||||
return initMetricEntity;
|
||||
});
|
||||
metricEntity.addPassQps(node.getPassQps());
|
||||
metricEntity.addBlockQps(node.getBlockQps());
|
||||
metricEntity.addRtAndSuccessQps(node.getRt(), node.getSuccessQps());
|
||||
metricEntity.addExceptionQps(node.getExceptionQps());
|
||||
metricEntity.addCount(1);
|
||||
} catch (Exception e) {
|
||||
logger.warn("handleBody line exception, machine: {}, line: {}", machine.toLogString(), line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String buildMetricKey(String app, String resource, long timestamp) {
|
||||
return app + "__" + resource + "__" + (timestamp / 1000);
|
||||
}
|
||||
|
||||
private boolean shouldFilterOut(String resource) {
|
||||
return RES_EXCLUSION_SET.contains(resource);
|
||||
}
|
||||
|
||||
private static final Set<String> RES_EXCLUSION_SET = new HashSet<String>() {{
|
||||
add(Constants.TOTAL_IN_RESOURCE_NAME);
|
||||
add(Constants.SYSTEM_LOAD_RESOURCE_NAME);
|
||||
add(Constants.CPU_USAGE_RESOURCE_NAME);
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.repository.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Store {@link ApiDefinitionEntity} in memory.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@Component
|
||||
public class InMemApiDefinitionStore extends InMemoryRuleRepositoryAdapter<ApiDefinitionEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
}
|
||||
@@ -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.repository.gateway;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Store {@link GatewayFlowRuleEntity} in memory.
|
||||
*
|
||||
* @author cdfive
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@Component
|
||||
public class InMemGatewayFlowRuleStore extends InMemoryRuleRepositoryAdapter<GatewayFlowRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.repository.metric;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Caches metrics data in a period of time in memory.
|
||||
*
|
||||
* @author Carpenter Lee
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
@Component
|
||||
public class InMemoryMetricsRepository implements MetricsRepository<MetricEntity> {
|
||||
|
||||
private static final long MAX_METRIC_LIVE_TIME_MS = 1000 * 60 * 5;
|
||||
|
||||
/**
|
||||
* {@code app -> resource -> timestamp -> metric}
|
||||
*/
|
||||
private Map<String, Map<String, LinkedHashMap<Long, MetricEntity>>> allMetrics = new ConcurrentHashMap<>();
|
||||
|
||||
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
|
||||
|
||||
|
||||
@Override
|
||||
public void save(MetricEntity entity) {
|
||||
if (entity == null || StringUtil.isBlank(entity.getApp())) {
|
||||
return;
|
||||
}
|
||||
readWriteLock.writeLock().lock();
|
||||
try {
|
||||
allMetrics.computeIfAbsent(entity.getApp(), e -> new HashMap<>(16))
|
||||
.computeIfAbsent(entity.getResource(), e -> new LinkedHashMap<Long, MetricEntity>() {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Entry<Long, MetricEntity> eldest) {
|
||||
// Metric older than {@link #MAX_METRIC_LIVE_TIME_MS} will be removed.
|
||||
return eldest.getKey() < TimeUtil.currentTimeMillis() - MAX_METRIC_LIVE_TIME_MS;
|
||||
}
|
||||
}).put(entity.getTimestamp().getTime(), entity);
|
||||
} finally {
|
||||
readWriteLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll(Iterable<MetricEntity> metrics) {
|
||||
if (metrics == null) {
|
||||
return;
|
||||
}
|
||||
readWriteLock.writeLock().lock();
|
||||
try {
|
||||
metrics.forEach(this::save);
|
||||
} finally {
|
||||
readWriteLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricEntity> queryByAppAndResourceBetween(String app, String resource,
|
||||
long startTime, long endTime) {
|
||||
List<MetricEntity> results = new ArrayList<>();
|
||||
if (StringUtil.isBlank(app)) {
|
||||
return results;
|
||||
}
|
||||
Map<String, LinkedHashMap<Long, MetricEntity>> resourceMap = allMetrics.get(app);
|
||||
if (resourceMap == null) {
|
||||
return results;
|
||||
}
|
||||
LinkedHashMap<Long, MetricEntity> metricsMap = resourceMap.get(resource);
|
||||
if (metricsMap == null) {
|
||||
return results;
|
||||
}
|
||||
readWriteLock.readLock().lock();
|
||||
try {
|
||||
for (Entry<Long, MetricEntity> entry : metricsMap.entrySet()) {
|
||||
if (entry.getKey() >= startTime && entry.getKey() <= endTime) {
|
||||
results.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
return results;
|
||||
} finally {
|
||||
readWriteLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listResourcesOfApp(String app) {
|
||||
List<String> results = new ArrayList<>();
|
||||
if (StringUtil.isBlank(app)) {
|
||||
return results;
|
||||
}
|
||||
// resource -> timestamp -> metric
|
||||
Map<String, LinkedHashMap<Long, MetricEntity>> resourceMap = allMetrics.get(app);
|
||||
if (resourceMap == null) {
|
||||
return results;
|
||||
}
|
||||
final long minTimeMs = System.currentTimeMillis() - 1000 * 60;
|
||||
Map<String, MetricEntity> resourceCount = new ConcurrentHashMap<>(32);
|
||||
|
||||
readWriteLock.readLock().lock();
|
||||
try {
|
||||
for (Entry<String, LinkedHashMap<Long, MetricEntity>> resourceMetrics : resourceMap.entrySet()) {
|
||||
for (Entry<Long, MetricEntity> metrics : resourceMetrics.getValue().entrySet()) {
|
||||
if (metrics.getKey() < minTimeMs) {
|
||||
continue;
|
||||
}
|
||||
MetricEntity newEntity = metrics.getValue();
|
||||
if (resourceCount.containsKey(resourceMetrics.getKey())) {
|
||||
MetricEntity oldEntity = resourceCount.get(resourceMetrics.getKey());
|
||||
oldEntity.addPassQps(newEntity.getPassQps());
|
||||
oldEntity.addRtAndSuccessQps(newEntity.getRt(), newEntity.getSuccessQps());
|
||||
oldEntity.addBlockQps(newEntity.getBlockQps());
|
||||
oldEntity.addExceptionQps(newEntity.getExceptionQps());
|
||||
oldEntity.addCount(1);
|
||||
} else {
|
||||
resourceCount.put(resourceMetrics.getKey(), MetricEntity.copyOf(newEntity));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Order by last minute b_qps DESC.
|
||||
return resourceCount.entrySet()
|
||||
.stream()
|
||||
.sorted((o1, o2) -> {
|
||||
MetricEntity e1 = o1.getValue();
|
||||
MetricEntity e2 = o2.getValue();
|
||||
int t = e2.getBlockQps().compareTo(e1.getBlockQps());
|
||||
if (t != 0) {
|
||||
return t;
|
||||
}
|
||||
return e2.getPassQps().compareTo(e1.getPassQps());
|
||||
})
|
||||
.map(Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
} finally {
|
||||
readWriteLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.repository.metric;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository interface for aggregated metrics data.
|
||||
*
|
||||
* @param <T> type of metrics
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public interface MetricsRepository<T> {
|
||||
|
||||
/**
|
||||
* Save the metric to the storage repository.
|
||||
*
|
||||
* @param metric metric data to save
|
||||
*/
|
||||
void save(T metric);
|
||||
|
||||
/**
|
||||
* Save all metrics to the storage repository.
|
||||
*
|
||||
* @param metrics metrics to save
|
||||
*/
|
||||
void saveAll(Iterable<T> metrics);
|
||||
|
||||
/**
|
||||
* Get all metrics by {@code appName} and {@code resourceName} between a period of time.
|
||||
*
|
||||
* @param app application name for Sentinel
|
||||
* @param resource resource name
|
||||
* @param startTime start timestamp
|
||||
* @param endTime end timestamp
|
||||
* @return all metrics in query conditions
|
||||
*/
|
||||
List<T> queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime);
|
||||
|
||||
/**
|
||||
* List resource name of provided application name.
|
||||
*
|
||||
* @param app application name
|
||||
* @return list of resources
|
||||
*/
|
||||
List<String> listResourcesOfApp(String app);
|
||||
}
|
||||
@@ -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.repository.rule;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* In-memory storage for authority rules.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
@Component
|
||||
public class InMemAuthorityRuleStore extends InMemoryRuleRepositoryAdapter<AuthorityRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.repository.rule;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
@Component
|
||||
public class InMemDegradeRuleStore extends InMemoryRuleRepositoryAdapter<DegradeRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.repository.rule;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.ClusterFlowConfig;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Store {@link FlowRuleEntity} in memory.
|
||||
*
|
||||
* @author leyou
|
||||
*/
|
||||
@Component
|
||||
public class InMemFlowRuleStore extends InMemoryRuleRepositoryAdapter<FlowRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FlowRuleEntity preProcess(FlowRuleEntity entity) {
|
||||
if (entity != null && entity.isClusterMode()) {
|
||||
ClusterFlowConfig config = entity.getClusterConfig();
|
||||
if (config == null) {
|
||||
config = new ClusterFlowConfig();
|
||||
entity.setClusterConfig(config);
|
||||
}
|
||||
// Set cluster rule id.
|
||||
config.setFlowId(entity.getId());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -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.repository.rule;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowClusterConfig;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
@Component
|
||||
public class InMemParamFlowRuleStore extends InMemoryRuleRepositoryAdapter<ParamFlowRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParamFlowRuleEntity preProcess(ParamFlowRuleEntity entity) {
|
||||
if (entity != null && entity.isClusterMode()) {
|
||||
ParamFlowClusterConfig config = entity.getClusterConfig();
|
||||
if (config == null) {
|
||||
config = new ParamFlowClusterConfig();
|
||||
}
|
||||
// Set cluster rule id.
|
||||
config.setFlowId(entity.getId());
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.repository.rule;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author leyou
|
||||
*/
|
||||
@Component
|
||||
public class InMemSystemRuleStore extends InMemoryRuleRepositoryAdapter<SystemRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user