From ebaee5b62b6db12f61f3fc8ee50752b929037681 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Tue, 26 Jul 2022 15:16:08 +0800 Subject: [PATCH] GR0 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 10 + .../ext/FizzServerHttpRequestDecorator.java | 8 +- fizz-common/src/test/java/we/OgnlTests.java | 47 ++ .../main/java/we/filter/AggregateFilter.java | 1 + .../java/we/plugin/FizzPluginFilterChain.java | 4 + .../main/java/we/plugin/auth/ApiConfig.java | 2 + fizz-core/src/main/java/we/proxy/Route.java | 22 + .../RegistryCenterService.java | 11 +- fizz-core/src/main/java/we/util/WebUtils.java | 6 + .../plugin/grayrelease/GrayReleasePlugin.java | 516 +++++++++++++++--- .../grayrelease/GrayReleasePluginTests.java | 60 ++ .../src/test/resources/log4j2-test.xml | 18 + pom.xml | 14 +- 14 files changed, 629 insertions(+), 92 deletions(-) create mode 100644 fizz-common/src/test/java/we/OgnlTests.java create mode 100644 fizz-plugin/src/test/java/we/plugin/grayrelease/GrayReleasePluginTests.java create mode 100644 fizz-plugin/src/test/resources/log4j2-test.xml diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 1df3a90..df91010 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -32,7 +32,7 @@ 1.15 2.11.1 2.8.9 - 2.0.53.Final + 2.0.54.Final 2.2.9.RELEASE 1.30 Moore-SR13--> diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index b0a7f37..f2ef7f9 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -17,6 +17,16 @@ + + com.github.seancfoley + ipaddress + + + + ognl + ognl + + org.openjdk.jol jol-core diff --git a/fizz-common/src/main/java/we/spring/http/server/reactive/ext/FizzServerHttpRequestDecorator.java b/fizz-common/src/main/java/we/spring/http/server/reactive/ext/FizzServerHttpRequestDecorator.java index a38b5d4..083fb13 100644 --- a/fizz-common/src/main/java/we/spring/http/server/reactive/ext/FizzServerHttpRequestDecorator.java +++ b/fizz-common/src/main/java/we/spring/http/server/reactive/ext/FizzServerHttpRequestDecorator.java @@ -68,7 +68,10 @@ public class FizzServerHttpRequestDecorator extends ServerHttpRequestDecorator { public FizzServerHttpRequestDecorator(ServerHttpRequest delegate) { super(delegate); this.delegate = (AbstractServerHttpRequest) delegate; - nativeRequest = this.delegate.getNativeRequest(); + try { + nativeRequest = this.delegate.getNativeRequest(); + } catch (IllegalStateException e) { + } } @Override @@ -120,6 +123,9 @@ public class FizzServerHttpRequestDecorator extends ServerHttpRequestDecorator { } private MultiValueMap initCookies() { + if (nativeRequest == null) { + return null; + } MultiValueMap cookies = new LinkedMultiValueMap<>(); for (CharSequence name : nativeRequest.cookies().keySet()) { for (Cookie cookie : nativeRequest.cookies().get(name)) { diff --git a/fizz-common/src/test/java/we/OgnlTests.java b/fizz-common/src/test/java/we/OgnlTests.java new file mode 100644 index 0000000..c371400 --- /dev/null +++ b/fizz-common/src/test/java/we/OgnlTests.java @@ -0,0 +1,47 @@ +package we; + +import ognl.Ognl; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class OgnlTests { + + @Test + void testGet() throws Exception { + + Root root = new Root(); + + Map query = new HashMap<>(); + query.put("version", "v2"); + query.put("userId", 1234563); + query.put("age", 25); + + root.put("query", query); + + Map client = new HashMap<>(); + client.put("ip", "10.2.3.4"); + client.put("ip2", "10.2.3.88"); + root.put("client", client); + + Boolean result = (Boolean) Ognl.getValue("checkIp(client.ip2) && (query.version == 'v2' || query.age < 20) and query.age in (22,25,30) && client.ip=='10.2.3.4'", root); + + System.out.println(result); + assertEquals(true, result); + } +} + +class Root extends HashMap { + + public Root() { + } + + public boolean checkIp(String ip) { + System.out.println(ip); + return ip.equals("10.2.3.88"); + } + +} \ No newline at end of file diff --git a/fizz-core/src/main/java/we/filter/AggregateFilter.java b/fizz-core/src/main/java/we/filter/AggregateFilter.java index a87536f..804ce5a 100644 --- a/fizz-core/src/main/java/we/filter/AggregateFilter.java +++ b/fizz-core/src/main/java/we/filter/AggregateFilter.java @@ -83,6 +83,7 @@ public class AggregateFilter implements WebFilter { String serviceId = WebUtils.getBackendService(exchange); if (serviceId == null) { return chain.filter(exchange); + } else if (WebUtils.ignorePlugin(exchange) && WebUtils.getRoute(exchange).type == ApiConfig.Type.SERVICE_AGGREGATE) { } else { byte act = WebUtils.getApiConfigType(exchange); if (act == ApiConfig.Type.UNDEFINED) { diff --git a/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java b/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java index 6700a4b..07289f3 100644 --- a/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java +++ b/fizz-core/src/main/java/we/plugin/FizzPluginFilterChain.java @@ -44,6 +44,10 @@ public final class FizzPluginFilterChain { } public static Mono next(ServerWebExchange exchange) { + if (WebUtils.ignorePlugin(exchange)) { + WebFilterChain chain = exchange.getAttribute(WEB_FILTER_CHAIN); + return chain.filter(exchange); + } Iterator it = exchange.getAttribute(pluginConfigsIt); Route route = WebUtils.getRoute(exchange); if (it == null || route.pluginConfigsChange) { diff --git a/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java b/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java index b12fd84..9cebb86 100644 --- a/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java +++ b/fizz-core/src/main/java/we/plugin/auth/ApiConfig.java @@ -47,6 +47,7 @@ public class ApiConfig { static final byte REVERSE_PROXY = 3; static final byte CALLBACK = 4; static final byte DUBBO = 5; + static final byte DIRECT_RESPONSE = 6; } public static final String ALL_METHOD = "AM"; @@ -226,6 +227,7 @@ public class ApiConfig { Route r = new Route().dedicatedLine( this.dedicatedLine) .type( this.type) .method( request.getMethod()) + .path( this.path) .registryCenter( this.registryCenter) .backendService( this.backendService) .backendPath( this.backendPath) diff --git a/fizz-core/src/main/java/we/proxy/Route.java b/fizz-core/src/main/java/we/proxy/Route.java index 269e339..52773b5 100644 --- a/fizz-core/src/main/java/we/proxy/Route.java +++ b/fizz-core/src/main/java/we/proxy/Route.java @@ -18,6 +18,7 @@ package we.proxy; import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; import we.plugin.PluginConfig; import we.util.Consts; import we.util.JacksonUtils; @@ -36,6 +37,8 @@ public class Route { public HttpMethod method; + public String path; + public String registryCenter; public String backendService; @@ -68,6 +71,10 @@ public class Route { public long retryInterval = 0; + public MediaType contentType; + + public String body; + public Route dedicatedLine(boolean b) { dedicatedLine = b; return this; @@ -83,6 +90,11 @@ public class Route { return this; } + public Route path(String p) { + path = p; + return this; + } + public Route registryCenter(String rc) { registryCenter = rc; return this; @@ -150,6 +162,16 @@ public class Route { return this; } + public Route contentType(MediaType type) { + contentType = type; + return this; + } + + public Route body(String b) { + body = b; + return this; + } + @Deprecated public String getBackendPathQuery() { if (query != null) { diff --git a/fizz-core/src/main/java/we/service_registry/RegistryCenterService.java b/fizz-core/src/main/java/we/service_registry/RegistryCenterService.java index 670eb3a..f6c7555 100644 --- a/fizz-core/src/main/java/we/service_registry/RegistryCenterService.java +++ b/fizz-core/src/main/java/we/service_registry/RegistryCenterService.java @@ -28,10 +28,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import we.config.AggregateRedisConfig; import we.config.SystemConfig; -import we.util.Consts; -import we.util.JacksonUtils; -import we.util.Result; -import we.util.ThreadContext; +import we.util.*; import javax.annotation.Resource; import java.util.Collections; @@ -182,7 +179,11 @@ public class RegistryCenterService implements ApplicationListener { + + public double random() { + return Math.random(); + } + + public boolean exist(String key) { + String[] keys = StringUtils.split(key, Consts.S.COMMA); + Map m = this; + int keyLen = keys.length; + for (int i = 0; i < keyLen; i++) { + String k = keys[i]; + if (m.containsKey(k)) { + Object obj = m.get(k); + if (obj instanceof Map) { + m = (Map) obj; + } else if (i + 1 != keyLen) { + return false; + } + } else { + return false; + } + } + return true; + } + + public boolean matches(String key, String regex) throws OgnlException { + String value = (String) Ognl.getValue(key, this); + if (value == null) { + return false; + } + return value.matches(regex); + } + + public String jwtClaim(String name) { + Map headerMap = (Map) get(GrayReleasePlugin.header); + if (headerMap == null) { + return null; + } else { + String token = (String) headerMap.get(HttpHeaders.AUTHORIZATION.toLowerCase()); + if (StringUtils.isBlank(token)) { + return null; + } else if (token.length() > 7 && token.substring(0, 7).equalsIgnoreCase("Bearer ")) { + token = token.substring(7); + } + DecodedJWT jwt = JWT.decode(token); + Claim claim = jwt.getClaim(name); + if (claim == null) { + return null; + } + return claim.asString(); + } + } + + public boolean clientIpInRange(String range) throws AddressStringException { + Map cli = (Map) get(client); + if (cli == null) { + return false; + } else { + String pi = (String) cli.get(ip); + if (pi == null) { + return false; + } else { + return ipInRange(pi, range); + } + } + } + + public boolean ipInRange(String ip, String range) throws AddressStringException { + IPAddress ipAddress = new IPAddressString(ip).toAddress(); + IPAddress rangeAddress = new IPAddressString(range).getAddress(); + return rangeAddress.contains(ipAddress); + } + + public boolean ipInRange(String ip, String rangeStartIp, String rangeEndIp) throws AddressStringException { + IPAddress startIPAddress = new IPAddressString(rangeStartIp).getAddress(); + IPAddress endIPAddress = new IPAddressString(rangeEndIp).getAddress(); + IPAddressSeqRange ipRange = startIPAddress.spanWithRange(endIPAddress); + IPAddress ipAddress = new IPAddressString(ip).toAddress(); + return ipRange.contains(ipAddress); + } + + public String toString() { + return JacksonUtils.writeValueAsString(this); + } + } @Override public Mono doFilter(ServerWebExchange exchange, Map config) { String traceId = WebUtils.getTraceId(exchange); ThreadContext.put(Consts.TRACE_ID, traceId); + String tc = (String) config.get(triggerCondition); + Object ognlRoot = request2ognlContext(exchange); + Boolean conditionMatch = false; try { - // LogService.setBizId(traceId); - String dedicatedLineId = WebUtils.getDedicatedLineId(exchange); - String cryptoKey = dedicatedLineService.getRequestCryptoKey(dedicatedLineId); + conditionMatch = (Boolean) Ognl.getValue(tc, ognlRoot); + } catch (OgnlException e) { + LOGGER.error("calc condition expression {} with context {}", tc, ognlRoot, e); + throw new RuntimeException(e); + } + if (conditionMatch) { + Route route = WebUtils.getRoute(exchange); + changeRoute(exchange, route, config); + if (route.type == ApiConfig.Type.DIRECT_RESPONSE) { + HttpHeaders hdrs = new HttpHeaders(); + hdrs.setContentType(route.contentType); + return WebUtils.response(exchange, HttpStatus.OK, hdrs, route.body); + } else { + exchange.getAttributes().put(WebUtils.IGNORE_PLUGIN, Consts.S.EMPTY); + } + } + return FizzPluginFilterChain.next(exchange); + } - FizzServerHttpRequestDecorator request = (FizzServerHttpRequestDecorator) exchange.getRequest(); - return request.getBody().defaultIfEmpty(NettyDataBufferUtils.EMPTY_DATA_BUFFER).single().flatMap(body -> { - if (body != NettyDataBufferUtils.EMPTY_DATA_BUFFER && systemConfig.fizzDedicatedLineClientRequestCrypto()) { - byte[] bodyBytes = request.getBodyBytes(); - request.setBody(decrypt(bodyBytes, cryptoKey)); - request.getHeaders().remove(HttpHeaders.CONTENT_LENGTH); - } + private Object request2ognlContext(ServerWebExchange exchange) { + OgnlRoot ognlRoot = new OgnlRoot(); + ServerHttpRequest request = exchange.getRequest(); - ServerHttpResponse original = exchange.getResponse(); - FizzServerHttpResponseDecorator fizzServerHttpResponseDecorator = new FizzServerHttpResponseDecorator(original) { - @Override - public Publisher writeWith(DataBuffer remoteResponseBody) { - if (remoteResponseBody == null || remoteResponseBody == NettyDataBufferUtils.EMPTY_DATA_BUFFER) { - return Mono.empty(); - } else { - if (StringUtils.isNotBlank(cryptoKey)) { - getDelegate().getHeaders().remove(HttpHeaders.CONTENT_LENGTH); - byte[] bytes = remoteResponseBody.asByteBuffer().array(); - NettyDataBuffer from = NettyDataBufferUtils.from(encrypt(bytes, cryptoKey)); - return Mono.just(from); - } else { - return Mono.just(remoteResponseBody); + ognlRoot.put(method, request.getMethodValue().toLowerCase()); + ognlRoot.put(path, WebUtils.getClientReqPath(exchange)); + + MultiValueMap queryParams = request.getQueryParams(); + if (!queryParams.isEmpty()) { + Map queryMap = new HashMap<>(); + queryParams.forEach( + (name, values) -> { + if (CollectionUtils.isEmpty(values)) { + queryMap.put(name, null); + } else if (values.size() > 1) { + queryMap.put(name, values); + } else { + queryMap.put(name, values.get(0)); + } + } + ); + ognlRoot.put(query, queryMap); + } + + HttpHeaders headers = request.getHeaders(); + if (!headers.isEmpty()) { + Map headerMap = new HashMap<>(); + headers.forEach( + (nm, values) -> { + String name = nm.toLowerCase(); + if (CollectionUtils.isEmpty(values)) { + headerMap.put(name, null); + } else if (values.size() > 1) { + headerMap.put(name, values); + } else { + headerMap.put(name, values.get(0)); + } + } + ); + ognlRoot.put(header, headerMap); + } + + MultiValueMap cookies = request.getCookies(); + if (!CollectionUtils.isEmpty(cookies)) { + Map cookieMap = new HashMap<>(); + cookies.forEach( + (name, values) -> { + if (CollectionUtils.isEmpty(values)) { + cookieMap.put(name, null); + } else if (values.size() > 1) { + List lst = new ArrayList<>(values.size()); + for (HttpCookie value : values) { + lst.add(value.getValue()); + } + cookieMap.put(name, lst); + } else { + cookieMap.put(name, values.get(0).getValue()); + } + } + ); + ognlRoot.put(cookie, cookieMap); + } + + MediaType reqContentType = request.getHeaders().getContentType(); + if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(reqContentType)) { + exchange.getFormData() + .map( + formData -> { + if (formData == FizzServerWebExchangeDecorator.EMPTY_FORM_DATA) { + return null; + } else { + Map formMap = new HashMap<>(); + formData.forEach( + (name, values) -> { + if (CollectionUtils.isEmpty(values)) { + formMap.put(name, null); + } else if (values.size() > 1) { + formMap.put(name, values); + } else { + formMap.put(name, values.get(0)); + } + } + ); + ognlRoot.put(form, formMap); + return formMap; + } } - } - } - }; - ServerWebExchange build = exchange.mutate().response(fizzServerHttpResponseDecorator).build(); - return FizzPluginFilterChain.next(build); - }); + ) + .subscribe(); + } else if (MediaType.APPLICATION_JSON.isCompatibleWith(reqContentType)) { + request.getBody() + .single() + .map( + bodyDataBuffer -> { + if (bodyDataBuffer == NettyDataBufferUtils.EMPTY_DATA_BUFFER) { + return null; + } else { + String json = bodyDataBuffer.toString(StandardCharsets.UTF_8).trim(); + if (json.charAt(0) == Consts.S.LEFT_SQUARE_BRACKET) { + List bodyMap = JacksonUtils.readValue(json, new TypeReference>(){}); + ognlRoot.put(body, bodyMap); + } else { + Map bodyMap = JacksonUtils.readValue(json, new TypeReference>(){}); + ognlRoot.put(body, bodyMap); + } + return null; + } + } + ) + .subscribe(); + } - } catch (Exception e) { - // log.error("{} {} Exception", traceId, DEDICATED_LINE_CODEC_PLUGIN_FILTER, LogService.BIZ_ID, traceId, e); - log.error("{} {} Exception", traceId, GRAY_RELEASE_PLUGIN, e); - String respJson = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(), - HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), traceId); - return WebUtils.response(exchange, HttpStatus.INTERNAL_SERVER_ERROR, null, respJson); + String originIp = WebUtils.getOriginIp(exchange); + if (originIp != null) { + Map clientMap = new HashMap<>(); + clientMap.put(ip, originIp); + ognlRoot.put(client, clientMap); + } + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("request {} ognl root: {}", request.getId(), ognlRoot); + } + + return ognlRoot; + } + + private void changeRoute(ServerWebExchange exchange, Route route, Map pluginConfig) { + byte rt = ((Integer) pluginConfig.get(routeType)).byteValue(); + route.type = rt; + Map newRouteConfig = (Map) pluginConfig.get(routeConfigMap); + if (newRouteConfig == null) { + newRouteConfig = routeConfig2map((String) pluginConfig.get(routeConfig)); + pluginConfig.put(routeConfigMap, newRouteConfig); + pluginConfig.remove(routeConfig); + } + if (rt == ApiConfig.Type.SERVICE_DISCOVERY) { + changeServiceDiscoveryRoute(exchange, route, newRouteConfig); + } else if (rt == ApiConfig.Type.REVERSE_PROXY) { + changeReverseProxyRoute(exchange, pluginConfig, route, newRouteConfig); + } else if (rt == ApiConfig.Type.SERVICE_AGGREGATE) { + changeAggregateRoute(exchange, route, newRouteConfig); + } else { + String ct = (String) pluginConfig.get(contentType); + String b = (String) pluginConfig.get(body); + route.contentType(MediaType.valueOf(ct)) + .body(b); + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("route is changed: {}", route); } } - /*public String encrypt(String data, String secretKey) { - if (StringUtils.isBlank(data)) { - return data; + private void changeServiceDiscoveryRoute(ServerWebExchange exchange, Route route, Map newRouteConfig) { + String type = newRouteConfig.get("type"); + String service = newRouteConfig.get("serviceName"); + if (StringUtils.isNotBlank(service)) { + route.backendService = service; + } + String timeout = newRouteConfig.get("timeout"); + if (StringUtils.isNotBlank(timeout)) { + route.timeout(Long.parseLong(timeout)); + } + if (type.equals("http")) { + String registry = newRouteConfig.get("registry"); + if (StringUtils.isNotBlank(registry)) { + route.registryCenter = registry; + } + String method = newRouteConfig.get("methodName"); + if (StringUtils.isNotBlank(method)) { + route.method(HttpMethod.resolve(method)); + } + String path = newRouteConfig.get("path"); + if (StringUtils.isNotBlank(path)) { + route.backendPath = UrlTransformUtils.transform(route.path, path, WebUtils.getClientReqPath(exchange)); + } + String qry = newRouteConfig.get("query"); + if (StringUtils.isNotBlank(qry)) { + route.query = qry; + } + String retryCount = newRouteConfig.get("retryCount"); + if (StringUtils.isNotBlank(retryCount)) { + route.retryCount(Integer.parseInt(retryCount)); + } + String retryInterval = newRouteConfig.get("retryInterval"); + if (StringUtils.isNotBlank(retryInterval)) { + route.retryInterval(Long.parseLong(retryInterval)); + } + } else { + route.type = ApiConfig.Type.DUBBO; + String method = newRouteConfig.get("methodName"); + if (StringUtils.isNotBlank(method)) { + route.rpcMethod(method); + } + String version = newRouteConfig.get("version"); + if (StringUtils.isNotBlank(version)) { + route.rpcVersion(version); + } + String group = newRouteConfig.get("group"); + if (StringUtils.isNotBlank(group)) { + route.rpcGroup(group); + } + String paramTypes = newRouteConfig.get("paramTypes"); + if (StringUtils.isNotBlank(paramTypes)) { + route.rpcParamTypes(paramTypes); + } } - byte[] key = SecureUtil.decode(secretKey); - SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); - return symmetric.encryptBase64(data); - }*/ - - public byte[] encrypt(byte[] data, String secretKey) { - byte[] key = SecureUtil.decode(secretKey); - SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); - return symmetric.encrypt(data); } - /*public String decrypt(String data, String secretKey) { - if (StringUtils.isBlank(data)) { - return data; + private void changeReverseProxyRoute(ServerWebExchange exchange, Map pluginConfig, Route route, Map newRouteConfig) { + List httpHostPorts = (List) pluginConfig.get("httpHostPorts"); + if (httpHostPorts == null) { + String httpHostPortStr = newRouteConfig.get("serviceName"); + if (StringUtils.isBlank(httpHostPortStr)) { + httpHostPorts = WebUtils.getApiConfig(exchange).httpHostPorts; + } else { + httpHostPorts = Arrays.asList(StringUtils.split(httpHostPortStr, Consts.S.COMMA)); + } + pluginConfig.put("httpHostPorts", httpHostPorts); + newRouteConfig.remove("serviceName"); } - byte[] key = SecureUtil.decode(secretKey); - SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); - return symmetric.decryptStr(data); - }*/ + int counter = (int) pluginConfig.getOrDefault("counter", 0); + counter++; + if (counter < 0) { + counter = Math.abs(counter); + } + String hostPort = httpHostPorts.get( + counter % httpHostPorts.size() + ); + route.nextHttpHostPort(hostPort); + pluginConfig.put("counter", counter); - public byte[] decrypt(byte[] data, String secretKey) { - byte[] key = SecureUtil.decode(secretKey); - SymmetricCrypto symmetric = new SymmetricCrypto(SymmetricAlgorithm.AES, key); - return symmetric.decrypt(data); + String method = newRouteConfig.get("methodName"); + if (StringUtils.isNotBlank(method)) { + route.method(HttpMethod.resolve(method)); + } + + String path = newRouteConfig.get("path"); + if (StringUtils.isNotBlank(path)) { + route.backendPath = UrlTransformUtils.transform(route.path, path, WebUtils.getClientReqPath(exchange)); + } + + String qry = newRouteConfig.get("query"); + if (StringUtils.isNotBlank(qry)) { + route.query = qry; + } + + String timeout = newRouteConfig.get("timeout"); + if (StringUtils.isNotBlank(timeout)) { + route.timeout(Long.parseLong(timeout)); + } + + String retryCount = newRouteConfig.get("retryCount"); + if (StringUtils.isNotBlank(retryCount)) { + route.retryCount(Integer.parseInt(retryCount)); + } + + String retryInterval = newRouteConfig.get("retryInterval"); + if (StringUtils.isNotBlank(retryInterval)) { + route.retryInterval(Long.parseLong(retryInterval)); + } + } + + private void changeAggregateRoute(ServerWebExchange exchange, Route route, Map newRouteConfig) { + String service = newRouteConfig.get("serviceName"); + if (StringUtils.isNotBlank(service)) { + route.backendService = service; + WebUtils.setBackendService(exchange, route.backendService); + } + String path = newRouteConfig.get("path"); + if (StringUtils.isNotBlank(path)) { + route.backendPath = UrlTransformUtils.transform(route.path, path, WebUtils.getClientReqPath(exchange)); + WebUtils.setBackendPath(exchange, route.backendPath); + } + } + + private Map routeConfig2map(String config) { + Map result = new HashMap<>(); + String[] lines = StringUtils.split(config, Consts.S.LF); + for (String line : lines) { + /*int colonIdx = line.indexOf(Consts.S.COLON); + int start = 0, end = 0; + for (int i = 0; i < line.length(); i++) { + if (line.charAt(i) != Consts.S.SPACE) { + start = i; + break; + } + } + for (int i = line.length() - 1; i > -1; i--) { + if (line.charAt(i) != Consts.S.SPACE) { + end = i; + break; + } + } + String name = line.substring(start, colonIdx); + String value = line.substring(colonIdx + 1, end + 1); + result.put(name, value);*/ + String[] nameValue = StringUtils.split(line, Consts.S.COLON); + result.put(nameValue[0].trim(), nameValue[1].trim()); + } + return result; } } diff --git a/fizz-plugin/src/test/java/we/plugin/grayrelease/GrayReleasePluginTests.java b/fizz-plugin/src/test/java/we/plugin/grayrelease/GrayReleasePluginTests.java new file mode 100644 index 0000000..4b75979 --- /dev/null +++ b/fizz-plugin/src/test/java/we/plugin/grayrelease/GrayReleasePluginTests.java @@ -0,0 +1,60 @@ +package we.plugin.grayrelease; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Mono; +import we.plugin.FizzPluginFilterChain; +import we.proxy.Route; +import we.util.Consts; +import we.util.WebUtils; + +import java.util.HashMap; +import java.util.Map; + +public class GrayReleasePluginTests { + + @Test + public void simpleTest() { + WebTestClient client = WebTestClient.bindToWebHandler( + exchange -> { + ServerHttpResponse r = exchange.getResponse(); + r.setStatusCode(HttpStatus.OK); + r.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE); + return r.writeWith(Mono.just(r.bufferFactory().wrap("this is web handler response".getBytes()))); + } + ) + .webFilter( + (exchange, chain) -> { + GrayReleasePlugin grayReleasePlugin = new GrayReleasePlugin(); + Map config = new HashMap<>(); + config.put("triggerCondition", "method == 'get'"); + config.put("routeType", 2); + config.put("routeConfig", "type: http \n serviceName: bservice"); + + // exchange.getAttributes().put("pcsit@", Collections.emptyIterator()); + exchange.getAttributes().put(WebUtils.ROUTE, new Route()); + exchange.getAttributes().put(WebUtils.IGNORE_PLUGIN, Consts.S.EMPTY); + exchange.getAttributes().put(FizzPluginFilterChain.WEB_FILTER_CHAIN, chain); + exchange.getAttributes().put("oi@", "11.238.145.181"); + + return grayReleasePlugin.filter(exchange, config); + } + ) + .build(); + + client.get() + .uri("/proxy/aservice/apath") + //.header("h1", "v1") + .exchange() + .expectBody(String.class).value( + v -> { + System.err.println("body:\n" + v); + } + ) + ; + } +} diff --git a/fizz-plugin/src/test/resources/log4j2-test.xml b/fizz-plugin/src/test/resources/log4j2-test.xml new file mode 100644 index 0000000..b59feb3 --- /dev/null +++ b/fizz-plugin/src/test/resources/log4j2-test.xml @@ -0,0 +1,18 @@ + + + + + fizz-plugin + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index a000ab0..9395ee8 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 0.8.2 0.9.11 2.11.1 - 2.0.53.Final + 2.0.54.Final 2.2.9.RELEASE 1.30 Moore-SR13 @@ -70,6 +70,18 @@ + + com.github.seancfoley + ipaddress + 5.3.4 + + + + ognl + ognl + 3.3.3 + + org.openjdk.jol jol-core